1 /* Command interpreter routine for virtual terminal [aka TeletYpe]
2 Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
4 This file is part of GNU Zebra.
6 GNU Zebra is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published
8 by the Free Software Foundation; either version 2, or (at your
9 option) any later version.
11 GNU Zebra is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Zebra; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
26 #include <lib/version.h>
32 /* Command vector which includes some level of command lists. Normally
33 each daemon maintains each own cmdvec. */
36 /* Host information structure. */
39 /* Default motd string. */
42 Hello, this is " QUAGGA_PROGNAME
" (version " QUAGGA_VERSION
").\r\n\
43 Copyright 1996-2004 Kunihiro Ishiguro, et al.\r\n\
46 /* Standard command node structures. */
47 struct cmd_node auth_node
=
53 struct cmd_node view_node
=
59 struct cmd_node auth_enable_node
=
65 struct cmd_node enable_node
=
71 struct cmd_node config_node
=
78 /* Utility function to concatenate argv argument into a single string
79 with inserting ' ' character between each argument. */
81 argv_concat (char **argv
, int argc
, int shift
)
91 for (i
= shift
; i
< argc
; i
++)
93 len
= strlen (argv
[i
]);
97 str
= XSTRDUP (MTYPE_TMP
, argv
[i
]);
102 str
= XREALLOC (MTYPE_TMP
, str
, (index
+ len
+ 2));
104 memcpy (str
+ index
, argv
[i
], len
);
112 /* Install top node of command vector. */
114 install_node (struct cmd_node
*node
,
115 int (*func
) (struct vty
*))
117 vector_set_index (cmdvec
, node
->node
, node
);
119 node
->cmd_vector
= vector_init (VECTOR_MIN_SIZE
);
122 /* Compare two command's string. Used in sort_node (). */
124 cmp_node (const void *p
, const void *q
)
126 struct cmd_element
*a
= *(struct cmd_element
**)p
;
127 struct cmd_element
*b
= *(struct cmd_element
**)q
;
129 return strcmp (a
->string
, b
->string
);
133 cmp_desc (const void *p
, const void *q
)
135 struct desc
*a
= *(struct desc
**)p
;
136 struct desc
*b
= *(struct desc
**)q
;
138 return strcmp (a
->cmd
, b
->cmd
);
141 /* Sort each node's command element according to command string. */
146 struct cmd_node
*cnode
;
148 struct cmd_element
*cmd_element
;
150 for (i
= 0; i
< vector_max (cmdvec
); i
++)
151 if ((cnode
= vector_slot (cmdvec
, i
)) != NULL
)
153 vector cmd_vector
= cnode
->cmd_vector
;
154 qsort (cmd_vector
->index
, cmd_vector
->max
, sizeof (void *), cmp_node
);
156 for (j
= 0; j
< vector_max (cmd_vector
); j
++)
157 if ((cmd_element
= vector_slot (cmd_vector
, j
)) != NULL
)
159 descvec
= vector_slot (cmd_element
->strvec
,
160 vector_max (cmd_element
->strvec
) - 1);
161 qsort (descvec
->index
, descvec
->max
, sizeof (void *), cmp_desc
);
166 /* Breaking up string into each command piece. I assume given
167 character is separated by a space character. Return value is a
168 vector which includes char ** data element. */
170 cmd_make_strvec (char *string
)
172 char *cp
, *start
, *token
;
181 /* Skip white spaces. */
182 while (isspace ((int) *cp
) && *cp
!= '\0')
185 /* Return if there is only white spaces */
189 if (*cp
== '!' || *cp
== '#')
192 /* Prepare return vector. */
193 strvec
= vector_init (VECTOR_MIN_SIZE
);
195 /* Copy each command piece and set into vector. */
199 while (!(isspace ((int) *cp
) || *cp
== '\r' || *cp
== '\n') &&
203 token
= XMALLOC (MTYPE_STRVEC
, strlen
+ 1);
204 memcpy (token
, start
, strlen
);
205 *(token
+ strlen
) = '\0';
206 vector_set (strvec
, token
);
208 while ((isspace ((int) *cp
) || *cp
== '\n' || *cp
== '\r') &&
217 /* Free allocated string vector. */
219 cmd_free_strvec (vector v
)
227 for (i
= 0; i
< vector_max (v
); i
++)
228 if ((cp
= vector_slot (v
, i
)) != NULL
)
229 XFREE (MTYPE_STRVEC
, cp
);
234 /* Fetch next description. Used in cmd_make_descvec(). */
236 cmd_desc_str (char **string
)
238 char *cp
, *start
, *token
;
246 /* Skip white spaces. */
247 while (isspace ((int) *cp
) && *cp
!= '\0')
250 /* Return if there is only white spaces */
256 while (!(*cp
== '\r' || *cp
== '\n') && *cp
!= '\0')
260 token
= XMALLOC (MTYPE_STRVEC
, strlen
+ 1);
261 memcpy (token
, start
, strlen
);
262 *(token
+ strlen
) = '\0';
269 /* New string vector. */
271 cmd_make_descvec (char *string
, char *descstr
)
280 vector strvec
= NULL
;
289 allvec
= vector_init (VECTOR_MIN_SIZE
);
293 while (isspace ((int) *cp
) && *cp
!= '\0')
310 fprintf (stderr
, "Command parse error!: %s\n", string
);
316 while (isspace ((int) *cp
) && *cp
!= '\0')
330 while (! (isspace ((int) *cp
) || *cp
== '\r' || *cp
== '\n' || *cp
== ')' || *cp
== '|') && *cp
!= '\0')
335 token
= XMALLOC (MTYPE_STRVEC
, len
+ 1);
336 memcpy (token
, sp
, len
);
337 *(token
+ len
) = '\0';
339 desc
= XCALLOC (MTYPE_DESC
, sizeof (struct desc
));
341 desc
->str
= cmd_desc_str (&dp
);
347 strvec
= vector_init (VECTOR_MIN_SIZE
);
348 vector_set (allvec
, strvec
);
354 strvec
= vector_init (VECTOR_MIN_SIZE
);
355 vector_set (allvec
, strvec
);
357 vector_set (strvec
, desc
);
361 /* Count mandantory string vector size. This is to determine inputed
362 command has enough command length. */
364 cmd_cmdsize (vector strvec
)
371 for (i
= 0; i
< vector_max (strvec
); i
++)
373 descvec
= vector_slot (strvec
, i
);
375 if (vector_max (descvec
) == 1)
377 struct desc
*desc
= vector_slot (descvec
, 0);
381 if (str
== NULL
|| CMD_OPTION (str
))
392 /* Return prompt character of specified node. */
394 cmd_prompt (enum node_type node
)
396 struct cmd_node
*cnode
;
398 cnode
= vector_slot (cmdvec
, node
);
399 return cnode
->prompt
;
402 /* Install a command into a node. */
404 install_element (enum node_type ntype
, struct cmd_element
*cmd
)
406 struct cmd_node
*cnode
;
408 cnode
= vector_slot (cmdvec
, ntype
);
412 fprintf (stderr
, "Command node %d doesn't exist, please check it\n",
417 vector_set (cnode
->cmd_vector
, cmd
);
419 cmd
->strvec
= cmd_make_descvec (cmd
->string
, cmd
->doc
);
420 cmd
->cmdsize
= cmd_cmdsize (cmd
->strvec
);
423 static unsigned char itoa64
[] =
424 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
427 to64(char *s
, long v
, int n
)
431 *s
++ = itoa64
[v
&0x3f];
436 char *zencrypt (char *passwd
)
440 char *crypt (const char *, const char *);
444 to64(&salt
[0], random(), 3);
445 to64(&salt
[3], tv
.tv_usec
, 3);
448 return crypt (passwd
, salt
);
452 syslog_facility_print (int facility
)
516 /* This function write configuration of this host. */
518 config_write_host (struct vty
*vty
)
521 vty_out (vty
, "hostname %s%s", host
.name
, VTY_NEWLINE
);
525 if (host
.password_encrypt
)
526 vty_out (vty
, "password 8 %s%s", host
.password_encrypt
, VTY_NEWLINE
);
527 if (host
.enable_encrypt
)
528 vty_out (vty
, "enable password 8 %s%s", host
.enable_encrypt
, VTY_NEWLINE
);
533 vty_out (vty
, "password %s%s", host
.password
, VTY_NEWLINE
);
535 vty_out (vty
, "enable password %s%s", host
.enable
, VTY_NEWLINE
);
539 vty_out (vty
, "log file %s%s", host
.logfile
, VTY_NEWLINE
);
542 vty_out (vty
, "log stdout%s", VTY_NEWLINE
);
546 vty_out (vty
, "log syslog");
547 if (zlog_default
->facility
!= LOG_DAEMON
)
548 vty_out (vty
, " facility %s", syslog_facility_print (zlog_default
->facility
));
549 vty_out (vty
, "%s", VTY_NEWLINE
);
551 if (zlog_default
->maskpri
!= LOG_DEBUG
)
552 vty_out (vty
, "log trap %s%s", zlog_priority
[zlog_default
->maskpri
], VTY_NEWLINE
);
554 if (zlog_default
->record_priority
== 1)
555 vty_out (vty
, "log record-priority%s", VTY_NEWLINE
);
558 vty_out (vty
, "service advanced-vty%s", VTY_NEWLINE
);
561 vty_out (vty
, "service password-encryption%s", VTY_NEWLINE
);
564 vty_out (vty
, "service terminal-length %d%s", host
.lines
,
568 vty_out (vty
, "no banner motd%s", VTY_NEWLINE
);
573 /* Utility function for getting command vector. */
575 cmd_node_vector (vector v
, enum node_type ntype
)
577 struct cmd_node
*cnode
= vector_slot (v
, ntype
);
578 return cnode
->cmd_vector
;
581 /* Filter command vector by symbol */
583 cmd_filter_by_symbol (char *command
, char *symbol
)
587 if (strcmp (symbol
, "IPV4_ADDRESS") == 0)
590 lim
= strlen (command
);
593 if (! (isdigit ((int) command
[i
]) || command
[i
] == '.' || command
[i
] == '/'))
599 if (strcmp (symbol
, "STRING") == 0)
602 lim
= strlen (command
);
605 if (! (isalpha ((int) command
[i
]) || command
[i
] == '_' || command
[i
] == '-'))
611 if (strcmp (symbol
, "IFNAME") == 0)
614 lim
= strlen (command
);
617 if (! isalnum ((int) command
[i
]))
626 /* Completion match types. */
642 cmd_ipv4_match (char *str
)
645 int dots
= 0, nums
= 0;
653 memset (buf
, 0, sizeof (buf
));
662 if (*(str
+ 1) == '.')
665 if (*(str
+ 1) == '\0')
671 if (!isdigit ((int) *str
))
680 strncpy (buf
, sp
, str
- sp
);
681 if (atoi (buf
) > 255)
699 cmd_ipv4_prefix_match (char *str
)
710 memset (buf
, 0, sizeof (buf
));
712 while (*str
!= '\0' && *str
!= '/')
719 if (*(str
+ 1) == '.' || *(str
+ 1) == '/')
722 if (*(str
+ 1) == '\0')
729 if (!isdigit ((int) *str
))
738 strncpy (buf
, sp
, str
- sp
);
739 if (atoi (buf
) > 255)
746 if (*(str
+ 1) == '\0')
752 else if (*str
== '\0')
765 if (!isdigit ((int) *str
))
777 #define IPV6_ADDR_STR "0123456789abcdefABCDEF:.%"
778 #define IPV6_PREFIX_STR "0123456789abcdefABCDEF:.%/"
779 #define STATE_START 1
780 #define STATE_COLON 2
781 #define STATE_DOUBLE 3
784 #define STATE_SLASH 6
790 cmd_ipv6_match (char *str
)
792 int state
= STATE_START
;
793 int colons
= 0, nums
= 0, double_colon
= 0;
795 struct sockaddr_in6 sin6_dummy
;
801 if (strspn (str
, IPV6_ADDR_STR
) != strlen (str
))
804 /* use inet_pton that has a better support,
805 * for example inet_pton can support the automatic addresses:
808 ret
= inet_pton(AF_INET6
, str
, &sin6_dummy
.sin6_addr
);
820 if (*(str
+ 1) != ':' && *(str
+ 1) != '\0')
834 if (*(str
+ 1) == ':')
835 state
= STATE_DOUBLE
;
846 if (*(str
+ 1) == ':')
850 if (*(str
+ 1) != '\0')
860 if (*(str
+ 1) == ':' || *(str
+ 1) == '\0')
868 if (*(str
+ 1) == '.')
896 cmd_ipv6_prefix_match (char *str
)
898 int state
= STATE_START
;
899 int colons
= 0, nums
= 0, double_colon
= 0;
907 if (strspn (str
, IPV6_PREFIX_STR
) != strlen (str
))
910 while (*str
!= '\0' && state
!= STATE_MASK
)
917 if (*(str
+ 1) != ':' && *(str
+ 1) != '\0')
931 if (*(str
+ 1) == '/')
933 else if (*(str
+ 1) == ':')
934 state
= STATE_DOUBLE
;
945 if (*(str
+ 1) == ':')
949 if (*(str
+ 1) != '\0' && *(str
+ 1) != '/')
953 if (*(str
+ 1) == '/')
963 if (*(str
+ 1) == ':' || *(str
+ 1) == '.'
964 || *(str
+ 1) == '\0' || *(str
+ 1) == '/')
969 for (; sp
<= str
; sp
++)
975 if (*(str
+ 1) == ':')
977 else if (*(str
+ 1) == '.')
979 else if (*(str
+ 1) == '/')
987 if (*(str
+ 1) == '\0')
1005 if (state
< STATE_MASK
)
1006 return partly_match
;
1008 mask
= strtol (str
, &endptr
, 10);
1009 if (*endptr
!= '\0')
1012 if (mask
< 0 || mask
> 128)
1015 /* I don't know why mask < 13 makes command match partly.
1016 Forgive me to make this comments. I Want to set static default route
1017 because of lack of function to originate default in ospf6d; sorry
1020 return partly_match;
1026 #endif /* HAVE_IPV6 */
1028 #define DECIMAL_STRLEN_MAX 10
1031 cmd_range_match (char *range
, char *str
)
1034 char buf
[DECIMAL_STRLEN_MAX
+ 1];
1035 char *endptr
= NULL
;
1036 unsigned long min
, max
, val
;
1041 val
= strtoul (str
, &endptr
, 10);
1042 if (*endptr
!= '\0')
1046 p
= strchr (range
, '-');
1049 if (p
- range
> DECIMAL_STRLEN_MAX
)
1051 strncpy (buf
, range
, p
- range
);
1052 buf
[p
- range
] = '\0';
1053 min
= strtoul (buf
, &endptr
, 10);
1054 if (*endptr
!= '\0')
1058 p
= strchr (range
, '>');
1061 if (p
- range
> DECIMAL_STRLEN_MAX
)
1063 strncpy (buf
, range
, p
- range
);
1064 buf
[p
- range
] = '\0';
1065 max
= strtoul (buf
, &endptr
, 10);
1066 if (*endptr
!= '\0')
1069 if (val
< min
|| val
> max
)
1075 /* Make completion match and return match type flag. */
1077 cmd_filter_by_completion (char *command
, vector v
, int index
)
1081 struct cmd_element
*cmd_element
;
1082 enum match_type match_type
;
1086 match_type
= no_match
;
1088 /* If command and cmd_element string does not match set NULL to vector */
1089 for (i
= 0; i
< vector_max (v
); i
++)
1090 if ((cmd_element
= vector_slot (v
, i
)) != NULL
)
1092 if (index
>= vector_max (cmd_element
->strvec
))
1093 vector_slot (v
, i
) = NULL
;
1099 descvec
= vector_slot (cmd_element
->strvec
, index
);
1101 for (j
= 0; j
< vector_max (descvec
); j
++)
1103 desc
= vector_slot (descvec
, j
);
1106 if (CMD_VARARG (str
))
1108 if (match_type
< vararg_match
)
1109 match_type
= vararg_match
;
1112 else if (CMD_RANGE (str
))
1114 if (cmd_range_match (str
, command
))
1116 if (match_type
< range_match
)
1117 match_type
= range_match
;
1123 else if (CMD_IPV6 (str
))
1125 if (cmd_ipv6_match (command
))
1127 if (match_type
< ipv6_match
)
1128 match_type
= ipv6_match
;
1133 else if (CMD_IPV6_PREFIX (str
))
1135 if (cmd_ipv6_prefix_match (command
))
1137 if (match_type
< ipv6_prefix_match
)
1138 match_type
= ipv6_prefix_match
;
1143 #endif /* HAVE_IPV6 */
1144 else if (CMD_IPV4 (str
))
1146 if (cmd_ipv4_match (command
))
1148 if (match_type
< ipv4_match
)
1149 match_type
= ipv4_match
;
1154 else if (CMD_IPV4_PREFIX (str
))
1156 if (cmd_ipv4_prefix_match (command
))
1158 if (match_type
< ipv4_prefix_match
)
1159 match_type
= ipv4_prefix_match
;
1164 /* Check is this point's argument optional ? */
1165 if (CMD_OPTION (str
) || CMD_VARIABLE (str
))
1167 if (match_type
< extend_match
)
1168 match_type
= extend_match
;
1171 else if (strncmp (command
, str
, strlen (command
)) == 0)
1173 if (strcmp (command
, str
) == 0)
1174 match_type
= exact_match
;
1177 if (match_type
< partly_match
)
1178 match_type
= partly_match
;
1184 vector_slot (v
, i
) = NULL
;
1190 /* Filter vector by command character with index. */
1192 cmd_filter_by_string (char *command
, vector v
, int index
)
1196 struct cmd_element
*cmd_element
;
1197 enum match_type match_type
;
1201 match_type
= no_match
;
1203 /* If command and cmd_element string does not match set NULL to vector */
1204 for (i
= 0; i
< vector_max (v
); i
++)
1205 if ((cmd_element
= vector_slot (v
, i
)) != NULL
)
1207 /* If given index is bigger than max string vector of command,
1209 if (index
>= vector_max (cmd_element
->strvec
))
1210 vector_slot (v
, i
) = NULL
;
1216 descvec
= vector_slot (cmd_element
->strvec
, index
);
1218 for (j
= 0; j
< vector_max (descvec
); j
++)
1220 desc
= vector_slot (descvec
, j
);
1223 if (CMD_VARARG (str
))
1225 if (match_type
< vararg_match
)
1226 match_type
= vararg_match
;
1229 else if (CMD_RANGE (str
))
1231 if (cmd_range_match (str
, command
))
1233 if (match_type
< range_match
)
1234 match_type
= range_match
;
1239 else if (CMD_IPV6 (str
))
1241 if (cmd_ipv6_match (command
) == exact_match
)
1243 if (match_type
< ipv6_match
)
1244 match_type
= ipv6_match
;
1248 else if (CMD_IPV6_PREFIX (str
))
1250 if (cmd_ipv6_prefix_match (command
) == exact_match
)
1252 if (match_type
< ipv6_prefix_match
)
1253 match_type
= ipv6_prefix_match
;
1257 #endif /* HAVE_IPV6 */
1258 else if (CMD_IPV4 (str
))
1260 if (cmd_ipv4_match (command
) == exact_match
)
1262 if (match_type
< ipv4_match
)
1263 match_type
= ipv4_match
;
1267 else if (CMD_IPV4_PREFIX (str
))
1269 if (cmd_ipv4_prefix_match (command
) == exact_match
)
1271 if (match_type
< ipv4_prefix_match
)
1272 match_type
= ipv4_prefix_match
;
1276 else if (CMD_OPTION (str
) || CMD_VARIABLE (str
))
1278 if (match_type
< extend_match
)
1279 match_type
= extend_match
;
1284 if (strcmp (command
, str
) == 0)
1286 match_type
= exact_match
;
1292 vector_slot (v
, i
) = NULL
;
1298 /* Check ambiguous match */
1300 is_cmd_ambiguous (char *command
, vector v
, int index
, enum match_type type
)
1305 struct cmd_element
*cmd_element
;
1306 char *matched
= NULL
;
1310 for (i
= 0; i
< vector_max (v
); i
++)
1311 if ((cmd_element
= vector_slot (v
, i
)) != NULL
)
1315 descvec
= vector_slot (cmd_element
->strvec
, index
);
1317 for (j
= 0; j
< vector_max (descvec
); j
++)
1319 enum match_type ret
;
1321 desc
= vector_slot (descvec
, j
);
1327 if (! (CMD_OPTION (str
) || CMD_VARIABLE (str
))
1328 && strcmp (command
, str
) == 0)
1332 if (! (CMD_OPTION (str
) || CMD_VARIABLE (str
))
1333 && strncmp (command
, str
, strlen (command
)) == 0)
1335 if (matched
&& strcmp (matched
, str
) != 0)
1336 return 1; /* There is ambiguous match. */
1343 if (cmd_range_match (str
, command
))
1345 if (matched
&& strcmp (matched
, str
) != 0)
1357 case ipv6_prefix_match
:
1358 if ((ret
= cmd_ipv6_prefix_match (command
)) != no_match
)
1360 if (ret
== partly_match
)
1361 return 2; /* There is incomplete match. */
1366 #endif /* HAVE_IPV6 */
1371 case ipv4_prefix_match
:
1372 if ((ret
= cmd_ipv4_prefix_match (command
)) != no_match
)
1374 if (ret
== partly_match
)
1375 return 2; /* There is incomplete match. */
1381 if (CMD_OPTION (str
) || CMD_VARIABLE (str
))
1390 vector_slot (v
, i
) = NULL
;
1395 /* If src matches dst return dst string, otherwise return NULL */
1397 cmd_entry_function (char *src
, char *dst
)
1399 /* Skip variable arguments. */
1400 if (CMD_OPTION (dst
) || CMD_VARIABLE (dst
) || CMD_VARARG (dst
) ||
1401 CMD_IPV4 (dst
) || CMD_IPV4_PREFIX (dst
) || CMD_RANGE (dst
))
1404 /* In case of 'command \t', given src is NULL string. */
1408 /* Matched with input string. */
1409 if (strncmp (src
, dst
, strlen (src
)) == 0)
1415 /* If src matches dst return dst string, otherwise return NULL */
1416 /* This version will return the dst string always if it is
1417 CMD_VARIABLE for '?' key processing */
1419 cmd_entry_function_desc (char *src
, char *dst
)
1421 if (CMD_VARARG (dst
))
1424 if (CMD_RANGE (dst
))
1426 if (cmd_range_match (dst
, src
))
1435 if (cmd_ipv6_match (src
))
1441 if (CMD_IPV6_PREFIX (dst
))
1443 if (cmd_ipv6_prefix_match (src
))
1448 #endif /* HAVE_IPV6 */
1452 if (cmd_ipv4_match (src
))
1458 if (CMD_IPV4_PREFIX (dst
))
1460 if (cmd_ipv4_prefix_match (src
))
1466 /* Optional or variable commands always match on '?' */
1467 if (CMD_OPTION (dst
) || CMD_VARIABLE (dst
))
1470 /* In case of 'command \t', given src is NULL string. */
1474 if (strncmp (src
, dst
, strlen (src
)) == 0)
1480 /* Check same string element existence. If it isn't there return
1483 cmd_unique_string (vector v
, char *str
)
1488 for (i
= 0; i
< vector_max (v
); i
++)
1489 if ((match
= vector_slot (v
, i
)) != NULL
)
1490 if (strcmp (match
, str
) == 0)
1495 /* Compare string to description vector. If there is same string
1496 return 1 else return 0. */
1498 desc_unique_string (vector v
, char *str
)
1503 for (i
= 0; i
< vector_max (v
); i
++)
1504 if ((desc
= vector_slot (v
, i
)) != NULL
)
1505 if (strcmp (desc
->cmd
, str
) == 0)
1511 cmd_try_do_shortcut (enum node_type node
, char* first_word
) {
1512 if ( first_word
!= NULL
&&
1513 node
!= AUTH_NODE
&&
1514 node
!= VIEW_NODE
&&
1515 node
!= AUTH_ENABLE_NODE
&&
1516 node
!= ENABLE_NODE
&&
1517 0 == strcmp( "do", first_word
) )
1522 /* '?' describe command support. */
1524 cmd_describe_command_real (vector vline
, struct vty
*vty
, int *status
)
1528 #define INIT_MATCHVEC_SIZE 10
1530 struct cmd_element
*cmd_element
;
1533 enum match_type match
;
1535 static struct desc desc_cr
= { "<cr>", "" };
1538 index
= vector_max (vline
) - 1;
1540 /* Make copy vector of current node's command vector. */
1541 cmd_vector
= vector_copy (cmd_node_vector (cmdvec
, vty
->node
));
1543 /* Prepare match vector */
1544 matchvec
= vector_init (INIT_MATCHVEC_SIZE
);
1546 /* Filter commands. */
1547 /* Only words precedes current word will be checked in this loop. */
1548 for (i
= 0; i
< index
; i
++)
1550 command
= vector_slot (vline
, i
);
1551 match
= cmd_filter_by_completion (command
, cmd_vector
, i
);
1553 if (match
== vararg_match
)
1555 struct cmd_element
*cmd_element
;
1559 for (j
= 0; j
< vector_max (cmd_vector
); j
++)
1560 if ((cmd_element
= vector_slot (cmd_vector
, j
)) != NULL
)
1562 descvec
= vector_slot (cmd_element
->strvec
,
1563 vector_max (cmd_element
->strvec
) - 1);
1564 for (k
= 0; k
< vector_max (descvec
); k
++)
1566 struct desc
*desc
= vector_slot (descvec
, k
);
1567 vector_set (matchvec
, desc
);
1571 vector_set (matchvec
, &desc_cr
);
1572 vector_free (cmd_vector
);
1577 if ((ret
= is_cmd_ambiguous (command
, cmd_vector
, i
, match
)) == 1)
1579 vector_free (cmd_vector
);
1580 *status
= CMD_ERR_AMBIGUOUS
;
1585 vector_free (cmd_vector
);
1586 *status
= CMD_ERR_NO_MATCH
;
1591 /* Prepare match vector */
1592 /* matchvec = vector_init (INIT_MATCHVEC_SIZE); */
1594 /* Make sure that cmd_vector is filtered based on current word */
1595 command
= vector_slot (vline
, index
);
1597 match
= cmd_filter_by_completion (command
, cmd_vector
, index
);
1599 /* Make description vector. */
1600 for (i
= 0; i
< vector_max (cmd_vector
); i
++)
1601 if ((cmd_element
= vector_slot (cmd_vector
, i
)) != NULL
)
1603 char *string
= NULL
;
1604 vector strvec
= cmd_element
->strvec
;
1606 /* if command is NULL, index may be equal to vector_max */
1607 if (command
&& index
>= vector_max (strvec
))
1608 vector_slot (cmd_vector
, i
) = NULL
;
1611 /* Check if command is completed. */
1612 if (command
== NULL
&& index
== vector_max (strvec
))
1615 if (! desc_unique_string (matchvec
, string
))
1616 vector_set (matchvec
, &desc_cr
);
1621 vector descvec
= vector_slot (strvec
, index
);
1624 for (j
= 0; j
< vector_max (descvec
); j
++)
1626 desc
= vector_slot (descvec
, j
);
1627 string
= cmd_entry_function_desc (command
, desc
->cmd
);
1630 /* Uniqueness check */
1631 if (! desc_unique_string (matchvec
, string
))
1632 vector_set (matchvec
, desc
);
1638 vector_free (cmd_vector
);
1640 if (vector_slot (matchvec
, 0) == NULL
)
1642 vector_free (matchvec
);
1643 *status
= CMD_ERR_NO_MATCH
;
1646 *status
= CMD_SUCCESS
;
1652 cmd_describe_command (vector vline
, struct vty
*vty
, int *status
)
1656 if ( cmd_try_do_shortcut(vty
->node
, vector_slot(vline
, 0) ) )
1658 enum node_type onode
;
1659 vector shifted_vline
;
1663 vty
->node
= ENABLE_NODE
;
1664 /* We can try it on enable node, cos' the vty is authenticated */
1666 shifted_vline
= vector_init (vector_count(vline
));
1668 for (index
= 1; index
< vector_max (vline
); index
++)
1670 vector_set_index (shifted_vline
, index
-1, vector_lookup(vline
, index
));
1673 ret
= cmd_describe_command_real (shifted_vline
, vty
, status
);
1675 vector_free(shifted_vline
);
1681 return cmd_describe_command_real (vline
, vty
, status
);
1685 /* Check LCD of matched command. */
1687 cmd_lcd (char **matched
)
1695 if (matched
[0] == NULL
|| matched
[1] == NULL
)
1698 for (i
= 1; matched
[i
] != NULL
; i
++)
1700 s1
= matched
[i
- 1];
1703 for (j
= 0; (c1
= s1
[j
]) && (c2
= s2
[j
]); j
++)
1718 /* Command line completion support. */
1720 cmd_complete_command_real (vector vline
, struct vty
*vty
, int *status
)
1723 vector cmd_vector
= vector_copy (cmd_node_vector (cmdvec
, vty
->node
));
1724 #define INIT_MATCHVEC_SIZE 10
1726 struct cmd_element
*cmd_element
;
1727 int index
= vector_max (vline
) - 1;
1734 /* First, filter by preceeding command string */
1735 for (i
= 0; i
< index
; i
++)
1737 enum match_type match
;
1740 command
= vector_slot (vline
, i
);
1742 /* First try completion match, if there is exactly match return 1 */
1743 match
= cmd_filter_by_completion (command
, cmd_vector
, i
);
1745 /* If there is exact match then filter ambiguous match else check
1747 if ((ret
= is_cmd_ambiguous (command
, cmd_vector
, i
, match
)) == 1)
1749 vector_free (cmd_vector
);
1750 *status
= CMD_ERR_AMBIGUOUS
;
1756 vector_free (cmd_vector);
1757 *status = CMD_ERR_NO_MATCH;
1763 /* Prepare match vector. */
1764 matchvec
= vector_init (INIT_MATCHVEC_SIZE
);
1766 /* Now we got into completion */
1767 for (i
= 0; i
< vector_max (cmd_vector
); i
++)
1768 if ((cmd_element
= vector_slot (cmd_vector
, i
)) != NULL
)
1771 vector strvec
= cmd_element
->strvec
;
1773 /* Check field length */
1774 if (index
>= vector_max (strvec
))
1775 vector_slot (cmd_vector
, i
) = NULL
;
1780 descvec
= vector_slot (strvec
, index
);
1781 for (j
= 0; j
< vector_max (descvec
); j
++)
1783 desc
= vector_slot (descvec
, j
);
1785 if ((string
= cmd_entry_function (vector_slot (vline
, index
),
1787 if (cmd_unique_string (matchvec
, string
))
1788 vector_set (matchvec
, XSTRDUP (MTYPE_TMP
, string
));
1793 /* We don't need cmd_vector any more. */
1794 vector_free (cmd_vector
);
1796 /* No matched command */
1797 if (vector_slot (matchvec
, 0) == NULL
)
1799 vector_free (matchvec
);
1801 /* In case of 'command \t' pattern. Do you need '?' command at
1802 the end of the line. */
1803 if (vector_slot (vline
, index
) == '\0')
1804 *status
= CMD_ERR_NOTHING_TODO
;
1806 *status
= CMD_ERR_NO_MATCH
;
1810 /* Only one matched */
1811 if (vector_slot (matchvec
, 1) == NULL
)
1813 match_str
= (char **) matchvec
->index
;
1814 vector_only_wrapper_free (matchvec
);
1815 *status
= CMD_COMPLETE_FULL_MATCH
;
1818 /* Make it sure last element is NULL. */
1819 vector_set (matchvec
, NULL
);
1821 /* Check LCD of matched strings. */
1822 if (vector_slot (vline
, index
) != NULL
)
1824 lcd
= cmd_lcd ((char **) matchvec
->index
);
1828 int len
= strlen (vector_slot (vline
, index
));
1834 lcdstr
= XMALLOC (MTYPE_TMP
, lcd
+ 1);
1835 memcpy (lcdstr
, matchvec
->index
[0], lcd
);
1838 /* match_str = (char **) &lcdstr; */
1840 /* Free matchvec. */
1841 for (i
= 0; i
< vector_max (matchvec
); i
++)
1843 if (vector_slot (matchvec
, i
))
1844 XFREE (MTYPE_TMP
, vector_slot (matchvec
, i
));
1846 vector_free (matchvec
);
1848 /* Make new matchvec. */
1849 matchvec
= vector_init (INIT_MATCHVEC_SIZE
);
1850 vector_set (matchvec
, lcdstr
);
1851 match_str
= (char **) matchvec
->index
;
1852 vector_only_wrapper_free (matchvec
);
1854 *status
= CMD_COMPLETE_MATCH
;
1860 match_str
= (char **) matchvec
->index
;
1861 vector_only_wrapper_free (matchvec
);
1862 *status
= CMD_COMPLETE_LIST_MATCH
;
1867 cmd_complete_command (vector vline
, struct vty
*vty
, int *status
)
1871 if ( cmd_try_do_shortcut(vty
->node
, vector_slot(vline
, 0) ) )
1873 enum node_type onode
;
1874 vector shifted_vline
;
1878 vty
->node
= ENABLE_NODE
;
1879 /* We can try it on enable node, cos' the vty is authenticated */
1881 shifted_vline
= vector_init (vector_count(vline
));
1883 for (index
= 1; index
< vector_max (vline
); index
++)
1885 vector_set_index (shifted_vline
, index
-1, vector_lookup(vline
, index
));
1888 ret
= cmd_complete_command_real (shifted_vline
, vty
, status
);
1890 vector_free(shifted_vline
);
1896 return cmd_complete_command_real (vline
, vty
, status
);
1899 /* return parent node */
1900 /* MUST eventually converge on CONFIG_NODE */
1901 enum node_type
node_parent ( enum node_type node
)
1905 assert (node
> CONFIG_NODE
);
1909 case BGP_VPNV4_NODE
:
1911 case BGP_IPV4M_NODE
:
1915 case KEYCHAIN_KEY_NODE
:
1916 ret
= KEYCHAIN_NODE
;
1925 /* Execute command by argument vline vector. */
1927 cmd_execute_command_real (vector vline
, struct vty
*vty
, struct cmd_element
**cmd
)
1932 struct cmd_element
*cmd_element
;
1933 struct cmd_element
*matched_element
;
1934 unsigned int matched_count
, incomplete_count
;
1936 char *argv
[CMD_ARGC_MAX
];
1937 enum match_type match
= 0;
1941 /* Make copy of command elements. */
1942 cmd_vector
= vector_copy (cmd_node_vector (cmdvec
, vty
->node
));
1944 for (index
= 0; index
< vector_max (vline
); index
++)
1948 command
= vector_slot (vline
, index
);
1950 match
= cmd_filter_by_completion (command
, cmd_vector
, index
);
1952 if (match
== vararg_match
)
1955 ret
= is_cmd_ambiguous (command
, cmd_vector
, index
, match
);
1959 vector_free (cmd_vector
);
1960 return CMD_ERR_AMBIGUOUS
;
1964 vector_free (cmd_vector
);
1965 return CMD_ERR_NO_MATCH
;
1969 /* Check matched count. */
1970 matched_element
= NULL
;
1972 incomplete_count
= 0;
1974 for (i
= 0; i
< vector_max (cmd_vector
); i
++)
1975 if (vector_slot (cmd_vector
,i
) != NULL
)
1977 cmd_element
= vector_slot (cmd_vector
,i
);
1979 if (match
== vararg_match
|| index
>= cmd_element
->cmdsize
)
1981 matched_element
= cmd_element
;
1983 printf ("DEBUG: %s\n", cmd_element
->string
);
1993 /* Finish of using cmd_vector. */
1994 vector_free (cmd_vector
);
1996 /* To execute command, matched_count must be 1.*/
1997 if (matched_count
== 0)
1999 if (incomplete_count
)
2000 return CMD_ERR_INCOMPLETE
;
2002 return CMD_ERR_NO_MATCH
;
2005 if (matched_count
> 1)
2006 return CMD_ERR_AMBIGUOUS
;
2008 /* Argument treatment */
2012 for (i
= 0; i
< vector_max (vline
); i
++)
2015 argv
[argc
++] = vector_slot (vline
, i
);
2018 vector descvec
= vector_slot (matched_element
->strvec
, i
);
2020 if (vector_max (descvec
) == 1)
2022 struct desc
*desc
= vector_slot (descvec
, 0);
2023 char *str
= desc
->cmd
;
2025 if (CMD_VARARG (str
))
2028 if (varflag
|| CMD_VARIABLE (str
) || CMD_OPTION (str
))
2029 argv
[argc
++] = vector_slot (vline
, i
);
2032 argv
[argc
++] = vector_slot (vline
, i
);
2035 if (argc
>= CMD_ARGC_MAX
)
2036 return CMD_ERR_EXEED_ARGC_MAX
;
2039 /* For vtysh execution. */
2041 *cmd
= matched_element
;
2043 if (matched_element
->daemon
)
2044 return CMD_SUCCESS_DAEMON
;
2046 /* Execute matched command. */
2047 return (*matched_element
->func
) (matched_element
, vty
, argc
, argv
);
2052 cmd_execute_command (vector vline
, struct vty
*vty
, struct cmd_element
**cmd
) {
2053 int ret
, saved_ret
, tried
= 0;
2054 enum node_type onode
, try_node
;
2056 onode
= try_node
= vty
->node
;
2058 if ( cmd_try_do_shortcut(vty
->node
, vector_slot(vline
, 0) ) )
2060 vector shifted_vline
;
2063 vty
->node
= ENABLE_NODE
;
2064 /* We can try it on enable node, cos' the vty is authenticated */
2066 shifted_vline
= vector_init (vector_count(vline
));
2068 for (index
= 1; index
< vector_max (vline
); index
++)
2070 vector_set_index (shifted_vline
, index
-1, vector_lookup(vline
, index
));
2073 ret
= cmd_execute_command_real (shifted_vline
, vty
, cmd
);
2075 vector_free(shifted_vline
);
2081 saved_ret
= ret
= cmd_execute_command_real (vline
, vty
, cmd
);
2083 /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
2084 while ( ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
2085 && vty
->node
> CONFIG_NODE
)
2087 try_node
= node_parent(try_node
);
2088 vty
->node
= try_node
;
2089 ret
= cmd_execute_command_real (vline
, vty
, cmd
);
2091 if (ret
== CMD_SUCCESS
|| ret
== CMD_WARNING
)
2093 /* succesfull command, leave the node as is */
2097 /* no command succeeded, reset the vty to the original node and
2098 return the error for this node */
2104 /* Execute command by argument readline. */
2106 cmd_execute_command_strict (vector vline
, struct vty
*vty
,
2107 struct cmd_element
**cmd
)
2112 struct cmd_element
*cmd_element
;
2113 struct cmd_element
*matched_element
;
2114 unsigned int matched_count
, incomplete_count
;
2116 char *argv
[CMD_ARGC_MAX
];
2118 enum match_type match
= 0;
2121 /* Make copy of command element */
2122 cmd_vector
= vector_copy (cmd_node_vector (cmdvec
, vty
->node
));
2124 for (index
= 0; index
< vector_max (vline
); index
++)
2128 command
= vector_slot (vline
, index
);
2130 match
= cmd_filter_by_string (vector_slot (vline
, index
),
2133 /* If command meets '.VARARG' then finish matching. */
2134 if (match
== vararg_match
)
2137 ret
= is_cmd_ambiguous (command
, cmd_vector
, index
, match
);
2140 vector_free (cmd_vector
);
2141 return CMD_ERR_AMBIGUOUS
;
2145 vector_free (cmd_vector
);
2146 return CMD_ERR_NO_MATCH
;
2150 /* Check matched count. */
2151 matched_element
= NULL
;
2153 incomplete_count
= 0;
2154 for (i
= 0; i
< vector_max (cmd_vector
); i
++)
2155 if (vector_slot (cmd_vector
,i
) != NULL
)
2157 cmd_element
= vector_slot (cmd_vector
,i
);
2159 if (match
== vararg_match
|| index
>= cmd_element
->cmdsize
)
2161 matched_element
= cmd_element
;
2168 /* Finish of using cmd_vector. */
2169 vector_free (cmd_vector
);
2171 /* To execute command, matched_count must be 1.*/
2172 if (matched_count
== 0)
2174 if (incomplete_count
)
2175 return CMD_ERR_INCOMPLETE
;
2177 return CMD_ERR_NO_MATCH
;
2180 if (matched_count
> 1)
2181 return CMD_ERR_AMBIGUOUS
;
2183 /* Argument treatment */
2187 for (i
= 0; i
< vector_max (vline
); i
++)
2190 argv
[argc
++] = vector_slot (vline
, i
);
2193 vector descvec
= vector_slot (matched_element
->strvec
, i
);
2195 if (vector_max (descvec
) == 1)
2197 struct desc
*desc
= vector_slot (descvec
, 0);
2198 char *str
= desc
->cmd
;
2200 if (CMD_VARARG (str
))
2203 if (varflag
|| CMD_VARIABLE (str
) || CMD_OPTION (str
))
2204 argv
[argc
++] = vector_slot (vline
, i
);
2207 argv
[argc
++] = vector_slot (vline
, i
);
2210 if (argc
>= CMD_ARGC_MAX
)
2211 return CMD_ERR_EXEED_ARGC_MAX
;
2214 /* For vtysh execution. */
2216 *cmd
= matched_element
;
2218 if (matched_element
->daemon
)
2219 return CMD_SUCCESS_DAEMON
;
2221 /* Now execute matched command */
2222 return (*matched_element
->func
) (matched_element
, vty
, argc
, argv
);
2225 /* Configration make from file. */
2227 config_from_file (struct vty
*vty
, FILE *fp
)
2232 while (fgets (vty
->buf
, VTY_BUFSIZ
, fp
))
2234 vline
= cmd_make_strvec (vty
->buf
);
2236 /* In case of comment line */
2239 /* Execute configuration command : this is strict match */
2240 ret
= cmd_execute_command_strict (vline
, vty
, NULL
);
2242 /* Try again with setting node to CONFIG_NODE */
2243 while (ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
2244 && vty
->node
!= CONFIG_NODE
)
2246 vty
->node
= node_parent(vty
->node
);
2247 ret
= cmd_execute_command_strict (vline
, vty
, NULL
);
2250 cmd_free_strvec (vline
);
2252 if (ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
)
2258 /* Configration from terminal */
2259 DEFUN (config_terminal
,
2260 config_terminal_cmd
,
2261 "configure terminal",
2262 "Configuration from vty interface\n"
2263 "Configuration terminal\n")
2265 if (vty_config_lock (vty
))
2266 vty
->node
= CONFIG_NODE
;
2269 vty_out (vty
, "VTY configuration is locked by other VTY%s", VTY_NEWLINE
);
2275 /* Enable command */
2279 "Turn on privileged mode command\n")
2281 /* If enable password is NULL, change to ENABLE_NODE */
2282 if ((host
.enable
== NULL
&& host
.enable_encrypt
== NULL
) ||
2283 vty
->type
== VTY_SHELL_SERV
)
2284 vty
->node
= ENABLE_NODE
;
2286 vty
->node
= AUTH_ENABLE_NODE
;
2291 /* Disable command */
2295 "Turn off privileged mode command\n")
2297 if (vty
->node
== ENABLE_NODE
)
2298 vty
->node
= VIEW_NODE
;
2302 /* Down vty node level. */
2306 "Exit current mode and down to previous mode\n")
2312 if (vty_shell (vty
))
2315 vty
->status
= VTY_CLOSE
;
2318 vty
->node
= ENABLE_NODE
;
2319 vty_config_unlock (vty
);
2321 case INTERFACE_NODE
:
2333 vty
->node
= CONFIG_NODE
;
2335 case BGP_VPNV4_NODE
:
2337 case BGP_IPV4M_NODE
:
2339 vty
->node
= BGP_NODE
;
2341 case KEYCHAIN_KEY_NODE
:
2342 vty
->node
= KEYCHAIN_NODE
;
2350 /* quit is alias of exit. */
2354 "Exit current mode and down to previous mode\n")
2356 /* End of configuration. */
2360 "End current mode and change to enable mode.")
2366 /* Nothing to do. */
2369 case INTERFACE_NODE
:
2374 case BGP_VPNV4_NODE
:
2376 case BGP_IPV4M_NODE
:
2383 case KEYCHAIN_KEY_NODE
:
2386 vty_config_unlock (vty
);
2387 vty
->node
= ENABLE_NODE
;
2396 DEFUN (show_version
,
2400 "Displays zebra version\n")
2402 vty_out (vty
, "Quagga %s (%s).%s", QUAGGA_VERSION
,
2405 vty_out (vty
, "Copyright 1996-2002, Kunihiro Ishiguro.%s", VTY_NEWLINE
);
2410 /* Help display function for all node. */
2414 "Description of the interactive help system\n")
2417 "Zebra VTY provides advanced help feature. 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
,
2430 VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
);
2434 /* Help display function for all node. */
2438 "Print command list\n")
2441 struct cmd_node
*cnode
= vector_slot (cmdvec
, vty
->node
);
2442 struct cmd_element
*cmd
;
2444 for (i
= 0; i
< vector_max (cnode
->cmd_vector
); i
++)
2445 if ((cmd
= vector_slot (cnode
->cmd_vector
, i
)) != NULL
)
2446 vty_out (vty
, " %s%s", cmd
->string
,
2451 /* Write current configuration into file. */
2452 DEFUN (config_write_file
,
2453 config_write_file_cmd
,
2455 "Write running configuration to memory, network, or terminal\n"
2456 "Write to configuration file\n")
2460 struct cmd_node
*node
;
2462 char *config_file_tmp
= NULL
;
2463 char *config_file_sav
= NULL
;
2464 struct vty
*file_vty
;
2466 /* Check and see if we are operating under vtysh configuration */
2467 if (host
.config
== NULL
)
2469 vty_out (vty
, "Can't save to configuration file, using vtysh.%s",
2475 config_file
= host
.config
;
2477 config_file_sav
= malloc (strlen (config_file
) + strlen (CONF_BACKUP_EXT
) + 1);
2478 strcpy (config_file_sav
, config_file
);
2479 strcat (config_file_sav
, CONF_BACKUP_EXT
);
2482 config_file_tmp
= malloc (strlen (config_file
) + 8);
2483 sprintf (config_file_tmp
, "%s.XXXXXX", config_file
);
2485 /* Open file to configuration write. */
2486 fd
= mkstemp (config_file_tmp
);
2489 vty_out (vty
, "Can't open configuration file %s.%s", config_file_tmp
,
2491 free (config_file_tmp
);
2492 free (config_file_sav
);
2496 /* Make vty for configuration file. */
2497 file_vty
= vty_new ();
2499 file_vty
->type
= VTY_FILE
;
2501 /* Config file header print. */
2502 vty_out (file_vty
, "!\n! Zebra configuration saved from vty\n! ");
2503 vty_time_print (file_vty
, 1);
2504 vty_out (file_vty
, "!\n");
2506 for (i
= 0; i
< vector_max (cmdvec
); i
++)
2507 if ((node
= vector_slot (cmdvec
, i
)) && node
->func
)
2509 if ((*node
->func
) (file_vty
))
2510 vty_out (file_vty
, "!\n");
2512 vty_close (file_vty
);
2514 if (unlink (config_file_sav
) != 0)
2515 if (errno
!= ENOENT
)
2517 vty_out (vty
, "Can't unlink backup configuration file %s.%s", config_file_sav
,
2519 free (config_file_sav
);
2520 free (config_file_tmp
);
2521 unlink (config_file_tmp
);
2524 if (link (config_file
, config_file_sav
) != 0)
2526 vty_out (vty
, "Can't backup old configuration file %s.%s", config_file_sav
,
2528 free (config_file_sav
);
2529 free (config_file_tmp
);
2530 unlink (config_file_tmp
);
2534 if (unlink (config_file
) != 0)
2536 vty_out (vty
, "Can't unlink configuration file %s.%s", config_file
,
2538 free (config_file_sav
);
2539 free (config_file_tmp
);
2540 unlink (config_file_tmp
);
2543 if (link (config_file_tmp
, config_file
) != 0)
2545 vty_out (vty
, "Can't save configuration file %s.%s", config_file
,
2547 free (config_file_sav
);
2548 free (config_file_tmp
);
2549 unlink (config_file_tmp
);
2552 unlink (config_file_tmp
);
2555 free (config_file_sav
);
2556 free (config_file_tmp
);
2558 if (chmod (config_file
, CONFIGFILE_MASK
) != 0)
2560 vty_out (vty
, "Can't chmod configuration file %s: %s (%d).%s",
2561 config_file
, strerror(errno
), errno
, VTY_NEWLINE
);
2565 vty_out (vty
, "Configuration saved to %s%s", config_file
,
2570 ALIAS (config_write_file
,
2573 "Write running configuration to memory, network, or terminal\n")
2575 ALIAS (config_write_file
,
2576 config_write_memory_cmd
,
2578 "Write running configuration to memory, network, or terminal\n"
2579 "Write configuration to the file (same as write file)\n")
2581 ALIAS (config_write_file
,
2582 copy_runningconfig_startupconfig_cmd
,
2583 "copy running-config startup-config",
2584 "Copy configuration\n"
2585 "Copy running config to... \n"
2586 "Copy running config to startup config (same as write file)\n")
2588 /* Write current configuration into the terminal. */
2589 DEFUN (config_write_terminal
,
2590 config_write_terminal_cmd
,
2592 "Write running configuration to memory, network, or terminal\n"
2593 "Write to terminal\n")
2596 struct cmd_node
*node
;
2598 if (vty
->type
== VTY_SHELL_SERV
)
2600 for (i
= 0; i
< vector_max (cmdvec
); i
++)
2601 if ((node
= vector_slot (cmdvec
, i
)) && node
->func
&& node
->vtysh
)
2603 if ((*node
->func
) (vty
))
2604 vty_out (vty
, "!%s", VTY_NEWLINE
);
2609 vty_out (vty
, "%sCurrent configuration:%s", VTY_NEWLINE
,
2611 vty_out (vty
, "!%s", VTY_NEWLINE
);
2613 for (i
= 0; i
< vector_max (cmdvec
); i
++)
2614 if ((node
= vector_slot (cmdvec
, i
)) && node
->func
)
2616 if ((*node
->func
) (vty
))
2617 vty_out (vty
, "!%s", VTY_NEWLINE
);
2619 vty_out (vty
, "end%s",VTY_NEWLINE
);
2624 /* Write current configuration into the terminal. */
2625 ALIAS (config_write_terminal
,
2626 show_running_config_cmd
,
2627 "show running-config",
2629 "running configuration\n")
2631 /* Write startup configuration into the terminal. */
2632 DEFUN (show_startup_config
,
2633 show_startup_config_cmd
,
2634 "show startup-config",
2636 "Contentes of startup configuration\n")
2641 confp
= fopen (host
.config
, "r");
2644 vty_out (vty
, "Can't open configuration file [%s]%s",
2645 host
.config
, VTY_NEWLINE
);
2649 while (fgets (buf
, BUFSIZ
, confp
))
2653 while (*cp
!= '\r' && *cp
!= '\n' && *cp
!= '\0')
2657 vty_out (vty
, "%s%s", buf
, VTY_NEWLINE
);
2665 /* Hostname configuration */
2666 DEFUN (config_hostname
,
2669 "Set system's network name\n"
2670 "This system's network name\n")
2672 if (!isalpha((int) *argv
[0]))
2674 vty_out (vty
, "Please specify string starting with alphabet%s", VTY_NEWLINE
);
2679 XFREE (0, host
.name
);
2681 host
.name
= strdup (argv
[0]);
2685 DEFUN (config_no_hostname
,
2687 "no hostname [HOSTNAME]",
2689 "Reset system's network name\n"
2690 "Host name of this router\n")
2693 XFREE (0, host
.name
);
2698 /* VTY interface password set. */
2699 DEFUN (config_password
, password_cmd
,
2700 "password (8|) WORD",
2701 "Assign the terminal connection password\n"
2702 "Specifies a HIDDEN password will follow\n"
2704 "The HIDDEN line password string\n")
2706 /* Argument check. */
2709 vty_out (vty
, "Please specify password.%s", VTY_NEWLINE
);
2715 if (*argv
[0] == '8')
2718 XFREE (0, host
.password
);
2719 host
.password
= NULL
;
2720 if (host
.password_encrypt
)
2721 XFREE (0, host
.password_encrypt
);
2722 host
.password_encrypt
= XSTRDUP (0, strdup (argv
[1]));
2727 vty_out (vty
, "Unknown encryption type.%s", VTY_NEWLINE
);
2732 if (!isalnum ((int) *argv
[0]))
2735 "Please specify string starting with alphanumeric%s", VTY_NEWLINE
);
2740 XFREE (0, host
.password
);
2741 host
.password
= NULL
;
2745 if (host
.password_encrypt
)
2746 XFREE (0, host
.password_encrypt
);
2747 host
.password_encrypt
= XSTRDUP (0, zencrypt (argv
[0]));
2750 host
.password
= XSTRDUP (0, argv
[0]);
2755 ALIAS (config_password
, password_text_cmd
,
2757 "Assign the terminal connection password\n"
2758 "The UNENCRYPTED (cleartext) line password\n")
2760 /* VTY enable password set. */
2761 DEFUN (config_enable_password
, enable_password_cmd
,
2762 "enable password (8|) WORD",
2763 "Modify enable password parameters\n"
2764 "Assign the privileged level password\n"
2765 "Specifies a HIDDEN password will follow\n"
2767 "The HIDDEN 'enable' password string\n")
2769 /* Argument check. */
2772 vty_out (vty
, "Please specify password.%s", VTY_NEWLINE
);
2776 /* Crypt type is specified. */
2779 if (*argv
[0] == '8')
2782 XFREE (0, host
.enable
);
2785 if (host
.enable_encrypt
)
2786 XFREE (0, host
.enable_encrypt
);
2787 host
.enable_encrypt
= XSTRDUP (0, argv
[1]);
2793 vty_out (vty
, "Unknown encryption type.%s", VTY_NEWLINE
);
2798 if (!isalnum ((int) *argv
[0]))
2801 "Please specify string starting with alphanumeric%s", VTY_NEWLINE
);
2806 XFREE (0, host
.enable
);
2809 /* Plain password input. */
2812 if (host
.enable_encrypt
)
2813 XFREE (0, host
.enable_encrypt
);
2814 host
.enable_encrypt
= XSTRDUP (0, zencrypt (argv
[0]));
2817 host
.enable
= XSTRDUP (0, argv
[0]);
2822 ALIAS (config_enable_password
,
2823 enable_password_text_cmd
,
2824 "enable password LINE",
2825 "Modify enable password parameters\n"
2826 "Assign the privileged level password\n"
2827 "The UNENCRYPTED (cleartext) 'enable' password\n")
2829 /* VTY enable password delete. */
2830 DEFUN (no_config_enable_password
, no_enable_password_cmd
,
2831 "no enable password",
2833 "Modify enable password parameters\n"
2834 "Assign the privileged level password\n")
2837 XFREE (0, host
.enable
);
2840 if (host
.enable_encrypt
)
2841 XFREE (0, host
.enable_encrypt
);
2842 host
.enable_encrypt
= NULL
;
2847 DEFUN (service_password_encrypt
,
2848 service_password_encrypt_cmd
,
2849 "service password-encryption",
2850 "Set up miscellaneous service\n"
2851 "Enable encrypted passwords\n")
2860 if (host
.password_encrypt
)
2861 XFREE (0, host
.password_encrypt
);
2862 host
.password_encrypt
= XSTRDUP (0, zencrypt (host
.password
));
2866 if (host
.enable_encrypt
)
2867 XFREE (0, host
.enable_encrypt
);
2868 host
.enable_encrypt
= XSTRDUP (0, zencrypt (host
.enable
));
2874 DEFUN (no_service_password_encrypt
,
2875 no_service_password_encrypt_cmd
,
2876 "no service password-encryption",
2878 "Set up miscellaneous service\n"
2879 "Enable encrypted passwords\n")
2886 if (host
.password_encrypt
)
2887 XFREE (0, host
.password_encrypt
);
2888 host
.password_encrypt
= NULL
;
2890 if (host
.enable_encrypt
)
2891 XFREE (0, host
.enable_encrypt
);
2892 host
.enable_encrypt
= NULL
;
2897 DEFUN (config_terminal_length
, config_terminal_length_cmd
,
2898 "terminal length <0-512>",
2899 "Set terminal line parameters\n"
2900 "Set number of lines on a screen\n"
2901 "Number of lines on screen (0 for no pausing)\n")
2904 char *endptr
= NULL
;
2906 lines
= strtol (argv
[0], &endptr
, 10);
2907 if (lines
< 0 || lines
> 512 || *endptr
!= '\0')
2909 vty_out (vty
, "length is malformed%s", VTY_NEWLINE
);
2917 DEFUN (config_terminal_no_length
, config_terminal_no_length_cmd
,
2918 "terminal no length",
2919 "Set terminal line parameters\n"
2921 "Set number of lines on a screen\n")
2927 DEFUN (service_terminal_length
, service_terminal_length_cmd
,
2928 "service terminal-length <0-512>",
2929 "Set up miscellaneous service\n"
2930 "System wide terminal length configuration\n"
2931 "Number of lines of VTY (0 means no line control)\n")
2934 char *endptr
= NULL
;
2936 lines
= strtol (argv
[0], &endptr
, 10);
2937 if (lines
< 0 || lines
> 512 || *endptr
!= '\0')
2939 vty_out (vty
, "length is malformed%s", VTY_NEWLINE
);
2947 DEFUN (no_service_terminal_length
, no_service_terminal_length_cmd
,
2948 "no service terminal-length [<0-512>]",
2950 "Set up miscellaneous service\n"
2951 "System wide terminal length configuration\n"
2952 "Number of lines of VTY (0 means no line control)\n")
2958 DEFUN (config_log_stdout
,
2959 config_log_stdout_cmd
,
2962 "Logging goes to stdout\n")
2964 zlog_set_flag (NULL
, ZLOG_STDOUT
);
2965 host
.log_stdout
= 1;
2969 DEFUN (no_config_log_stdout
,
2970 no_config_log_stdout_cmd
,
2974 "Cancel logging to stdout\n")
2976 zlog_reset_flag (NULL
, ZLOG_STDOUT
);
2977 host
.log_stdout
= 0;
2981 DEFUN (config_log_file
,
2982 config_log_file_cmd
,
2983 "log file FILENAME",
2986 "Logging filename\n")
2992 /* Path detection. */
2993 if (! IS_DIRECTORY_SEP (*argv
[0]))
2995 cwd
= getcwd (NULL
, MAXPATHLEN
);
2996 fullpath
= XMALLOC (MTYPE_TMP
,
2997 strlen (cwd
) + strlen (argv
[0]) + 2);
2998 sprintf (fullpath
, "%s/%s", cwd
, argv
[0]);
3003 ret
= zlog_set_file (NULL
, ZLOG_FILE
, fullpath
);
3007 vty_out (vty
, "can't open logfile %s\n", argv
[0]);
3012 XFREE (MTYPE_TMP
, host
.logfile
);
3014 host
.logfile
= strdup (argv
[0]);
3019 DEFUN (no_config_log_file
,
3020 no_config_log_file_cmd
,
3021 "no log file [FILENAME]",
3024 "Cancel logging to file\n"
3025 "Logging file name\n")
3027 zlog_reset_file (NULL
);
3030 XFREE (MTYPE_TMP
, host
.logfile
);
3032 host
.logfile
= NULL
;
3037 DEFUN (config_log_syslog
,
3038 config_log_syslog_cmd
,
3041 "Logging goes to syslog\n")
3043 zlog_set_flag (NULL
, ZLOG_SYSLOG
);
3044 host
.log_syslog
= 1;
3045 zlog_default
->facility
= LOG_DAEMON
;
3049 DEFUN (config_log_syslog_facility
,
3050 config_log_syslog_facility_cmd
,
3051 "log syslog facility (kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7)",
3053 "Logging goes to syslog\n"
3054 "Facility parameter for syslog messages\n"
3059 "Authorization system\n"
3061 "Line printer system\n"
3063 "Unix-to-Unix copy system\n"
3064 "Cron/at facility\n"
3074 int facility
= LOG_DAEMON
;
3076 zlog_set_flag (NULL
, ZLOG_SYSLOG
);
3077 host
.log_syslog
= 1;
3079 if (strncmp (argv
[0], "kern", 1) == 0)
3080 facility
= LOG_KERN
;
3081 else if (strncmp (argv
[0], "user", 2) == 0)
3082 facility
= LOG_USER
;
3083 else if (strncmp (argv
[0], "mail", 1) == 0)
3084 facility
= LOG_MAIL
;
3085 else if (strncmp (argv
[0], "daemon", 1) == 0)
3086 facility
= LOG_DAEMON
;
3087 else if (strncmp (argv
[0], "auth", 1) == 0)
3088 facility
= LOG_AUTH
;
3089 else if (strncmp (argv
[0], "syslog", 1) == 0)
3090 facility
= LOG_SYSLOG
;
3091 else if (strncmp (argv
[0], "lpr", 2) == 0)
3093 else if (strncmp (argv
[0], "news", 1) == 0)
3094 facility
= LOG_NEWS
;
3095 else if (strncmp (argv
[0], "uucp", 2) == 0)
3096 facility
= LOG_UUCP
;
3097 else if (strncmp (argv
[0], "cron", 1) == 0)
3098 facility
= LOG_CRON
;
3099 else if (strncmp (argv
[0], "local0", 6) == 0)
3100 facility
= LOG_LOCAL0
;
3101 else if (strncmp (argv
[0], "local1", 6) == 0)
3102 facility
= LOG_LOCAL1
;
3103 else if (strncmp (argv
[0], "local2", 6) == 0)
3104 facility
= LOG_LOCAL2
;
3105 else if (strncmp (argv
[0], "local3", 6) == 0)
3106 facility
= LOG_LOCAL3
;
3107 else if (strncmp (argv
[0], "local4", 6) == 0)
3108 facility
= LOG_LOCAL4
;
3109 else if (strncmp (argv
[0], "local5", 6) == 0)
3110 facility
= LOG_LOCAL5
;
3111 else if (strncmp (argv
[0], "local6", 6) == 0)
3112 facility
= LOG_LOCAL6
;
3113 else if (strncmp (argv
[0], "local7", 6) == 0)
3114 facility
= LOG_LOCAL7
;
3116 zlog_default
->facility
= facility
;
3121 DEFUN (no_config_log_syslog
,
3122 no_config_log_syslog_cmd
,
3126 "Cancel logging to syslog\n")
3128 zlog_reset_flag (NULL
, ZLOG_SYSLOG
);
3129 host
.log_syslog
= 0;
3130 zlog_default
->facility
= LOG_DAEMON
;
3134 ALIAS (no_config_log_syslog
,
3135 no_config_log_syslog_facility_cmd
,
3136 "no log syslog facility (kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7)",
3139 "Logging goes to syslog\n"
3140 "Facility parameter for syslog messages\n"
3145 "Authorization system\n"
3147 "Line printer system\n"
3149 "Unix-to-Unix copy system\n"
3150 "Cron/at facility\n"
3160 DEFUN (config_log_trap
,
3161 config_log_trap_cmd
,
3162 "log trap (emergencies|alerts|critical|errors|warnings|notifications|informational|debugging)",
3164 "Limit logging to specifed level\n")
3168 for ( new_level
= 0 ; zlog_priority
[new_level
] != NULL
; new_level
++ )
3170 if ( strcmp ( argv
[0], zlog_priority
[new_level
] ) == 0 )
3171 /* found new logging level */
3173 zlog_default
->maskpri
= new_level
;
3177 return CMD_ERR_NO_MATCH
;
3180 DEFUN (no_config_log_trap
,
3181 no_config_log_trap_cmd
,
3185 "Permit all logging information\n")
3187 zlog_default
->maskpri
= LOG_DEBUG
;
3191 DEFUN (config_log_record_priority
,
3192 config_log_record_priority_cmd
,
3193 "log record-priority",
3195 "Log the priority of the message within the message\n")
3197 zlog_default
->record_priority
= 1 ;
3201 DEFUN (no_config_log_record_priority
,
3202 no_config_log_record_priority_cmd
,
3203 "no log record-priority",
3206 "Do not log the priority of the message within the message\n")
3208 zlog_default
->record_priority
= 0 ;
3213 DEFUN (banner_motd_default
,
3214 banner_motd_default_cmd
,
3215 "banner motd default",
3216 "Set banner string\n"
3217 "Strings for motd\n"
3220 host
.motd
= default_motd
;
3224 DEFUN (no_banner_motd
,
3228 "Set banner string\n"
3229 "Strings for motd\n")
3235 /* Set config filename. Called from vty.c */
3237 host_config_set (char *filename
)
3239 host
.config
= strdup (filename
);
3243 install_default (enum node_type node
)
3245 install_element (node
, &config_exit_cmd
);
3246 install_element (node
, &config_quit_cmd
);
3247 install_element (node
, &config_end_cmd
);
3248 install_element (node
, &config_help_cmd
);
3249 install_element (node
, &config_list_cmd
);
3251 install_element (node
, &config_write_terminal_cmd
);
3252 install_element (node
, &config_write_file_cmd
);
3253 install_element (node
, &config_write_memory_cmd
);
3254 install_element (node
, &config_write_cmd
);
3255 install_element (node
, &show_running_config_cmd
);
3258 /* Initialize command interface. Install basic nodes and commands. */
3260 cmd_init (int terminal
)
3262 /* Allocate initial top vector of commands. */
3263 cmdvec
= vector_init (VECTOR_MIN_SIZE
);
3265 /* Default host value settings. */
3267 host
.password
= NULL
;
3269 host
.logfile
= NULL
;
3272 host
.motd
= default_motd
;
3274 /* Install top nodes. */
3275 install_node (&view_node
, NULL
);
3276 install_node (&enable_node
, NULL
);
3277 install_node (&auth_node
, NULL
);
3278 install_node (&auth_enable_node
, NULL
);
3279 install_node (&config_node
, config_write_host
);
3281 /* Each node's basic commands. */
3282 install_element (VIEW_NODE
, &show_version_cmd
);
3285 install_element (VIEW_NODE
, &config_list_cmd
);
3286 install_element (VIEW_NODE
, &config_exit_cmd
);
3287 install_element (VIEW_NODE
, &config_quit_cmd
);
3288 install_element (VIEW_NODE
, &config_help_cmd
);
3289 install_element (VIEW_NODE
, &config_enable_cmd
);
3290 install_element (VIEW_NODE
, &config_terminal_length_cmd
);
3291 install_element (VIEW_NODE
, &config_terminal_no_length_cmd
);
3296 install_default (ENABLE_NODE
);
3297 install_element (ENABLE_NODE
, &config_disable_cmd
);
3298 install_element (ENABLE_NODE
, &config_terminal_cmd
);
3299 install_element (ENABLE_NODE
, ©_runningconfig_startupconfig_cmd
);
3301 install_element (ENABLE_NODE
, &show_startup_config_cmd
);
3302 install_element (ENABLE_NODE
, &show_version_cmd
);
3306 install_element (ENABLE_NODE
, &config_terminal_length_cmd
);
3307 install_element (ENABLE_NODE
, &config_terminal_no_length_cmd
);
3309 install_default (CONFIG_NODE
);
3311 install_element (CONFIG_NODE
, &hostname_cmd
);
3312 install_element (CONFIG_NODE
, &no_hostname_cmd
);
3313 install_element (CONFIG_NODE
, &password_cmd
);
3314 install_element (CONFIG_NODE
, &password_text_cmd
);
3315 install_element (CONFIG_NODE
, &enable_password_cmd
);
3316 install_element (CONFIG_NODE
, &enable_password_text_cmd
);
3317 install_element (CONFIG_NODE
, &no_enable_password_cmd
);
3319 install_element (CONFIG_NODE
, &config_log_stdout_cmd
);
3320 install_element (CONFIG_NODE
, &no_config_log_stdout_cmd
);
3321 install_element (CONFIG_NODE
, &config_log_file_cmd
);
3322 install_element (CONFIG_NODE
, &no_config_log_file_cmd
);
3323 install_element (CONFIG_NODE
, &config_log_syslog_cmd
);
3324 install_element (CONFIG_NODE
, &config_log_syslog_facility_cmd
);
3325 install_element (CONFIG_NODE
, &no_config_log_syslog_cmd
);
3326 install_element (CONFIG_NODE
, &no_config_log_syslog_facility_cmd
);
3327 install_element (CONFIG_NODE
, &config_log_trap_cmd
);
3328 install_element (CONFIG_NODE
, &no_config_log_trap_cmd
);
3329 install_element (CONFIG_NODE
, &config_log_record_priority_cmd
);
3330 install_element (CONFIG_NODE
, &no_config_log_record_priority_cmd
);
3331 install_element (CONFIG_NODE
, &service_password_encrypt_cmd
);
3332 install_element (CONFIG_NODE
, &no_service_password_encrypt_cmd
);
3333 install_element (CONFIG_NODE
, &banner_motd_default_cmd
);
3334 install_element (CONFIG_NODE
, &no_banner_motd_cmd
);
3335 install_element (CONFIG_NODE
, &service_terminal_length_cmd
);
3336 install_element (CONFIG_NODE
, &no_service_terminal_length_cmd
);
3338 install_element(VIEW_NODE
, &show_thread_cpu_cmd
);
3339 install_element(ENABLE_NODE
, &show_thread_cpu_cmd
);