blob: 4f6d184da81fa3b1e33f648b85ac7494b5443551 [file] [log] [blame]
ajs274a4a42004-12-07 15:39:31 +00001/*
ajs274a4a42004-12-07 15:39:31 +00002 Command interpreter routine for virtual terminal [aka TeletYpe]
paul718e3742002-12-13 20:15:29 +00003 Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
4
5This file is part of GNU Zebra.
6
7GNU Zebra is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published
9by the Free Software Foundation; either version 2, or (at your
10option) any later version.
11
12GNU Zebra is distributed in the hope that it will be useful, but
13WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Zebra; see the file COPYING. If not, write to the
19Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20Boston, MA 02111-1307, USA. */
21
22#include <zebra.h>
23
paulb21b19c2003-06-15 01:28:29 +000024
paul718e3742002-12-13 20:15:29 +000025#include "memory.h"
26#include "log.h"
gdt5e4fa162004-03-16 14:38:36 +000027#include <lib/version.h>
paul9ab68122003-01-18 01:16:20 +000028#include "thread.h"
paulb21b19c2003-06-15 01:28:29 +000029#include "vector.h"
30#include "vty.h"
31#include "command.h"
paul354d1192005-04-25 16:26:42 +000032#include "workqueue.h"
paul718e3742002-12-13 20:15:29 +000033
34/* Command vector which includes some level of command lists. Normally
35 each daemon maintains each own cmdvec. */
pauleb820af2005-09-05 11:54:13 +000036vector cmdvec = NULL;
paul718e3742002-12-13 20:15:29 +000037
Chris Caputo228da422009-07-18 05:44:03 +000038struct desc desc_cr;
39char *command_cr = NULL;
40
paul718e3742002-12-13 20:15:29 +000041/* Host information structure. */
42struct host host;
43
paul718e3742002-12-13 20:15:29 +000044/* Standard command node structures. */
Stephen Hemminger7fc626d2008-12-01 11:10:34 -080045static struct cmd_node auth_node =
paul718e3742002-12-13 20:15:29 +000046{
47 AUTH_NODE,
48 "Password: ",
49};
50
Stephen Hemminger7fc626d2008-12-01 11:10:34 -080051static struct cmd_node view_node =
paul718e3742002-12-13 20:15:29 +000052{
53 VIEW_NODE,
54 "%s> ",
55};
56
Stephen Hemminger7fc626d2008-12-01 11:10:34 -080057static struct cmd_node restricted_node =
Paul Jakma62687ff2008-08-23 14:27:06 +010058{
59 RESTRICTED_NODE,
60 "%s$ ",
61};
62
Stephen Hemminger7fc626d2008-12-01 11:10:34 -080063static struct cmd_node auth_enable_node =
paul718e3742002-12-13 20:15:29 +000064{
65 AUTH_ENABLE_NODE,
66 "Password: ",
67};
68
Stephen Hemminger7fc626d2008-12-01 11:10:34 -080069static struct cmd_node enable_node =
paul718e3742002-12-13 20:15:29 +000070{
71 ENABLE_NODE,
72 "%s# ",
73};
74
Stephen Hemminger7fc626d2008-12-01 11:10:34 -080075static struct cmd_node config_node =
paul718e3742002-12-13 20:15:29 +000076{
77 CONFIG_NODE,
78 "%s(config)# ",
79 1
80};
hasso6590f2c2004-10-19 20:40:08 +000081
82/* Default motd string. */
Stephen Hemminger2d362d12009-12-21 12:54:58 +030083static const char *default_motd =
hasso6590f2c2004-10-19 20:40:08 +000084"\r\n\
85Hello, this is " QUAGGA_PROGNAME " (version " QUAGGA_VERSION ").\r\n\
86" QUAGGA_COPYRIGHT "\r\n\
87\r\n";
88
ajs274a4a42004-12-07 15:39:31 +000089
Stephen Hemminger2d362d12009-12-21 12:54:58 +030090static const struct facility_map {
ajs274a4a42004-12-07 15:39:31 +000091 int facility;
92 const char *name;
93 size_t match;
94} syslog_facilities[] =
95 {
96 { LOG_KERN, "kern", 1 },
97 { LOG_USER, "user", 2 },
98 { LOG_MAIL, "mail", 1 },
99 { LOG_DAEMON, "daemon", 1 },
100 { LOG_AUTH, "auth", 1 },
101 { LOG_SYSLOG, "syslog", 1 },
102 { LOG_LPR, "lpr", 2 },
103 { LOG_NEWS, "news", 1 },
104 { LOG_UUCP, "uucp", 2 },
105 { LOG_CRON, "cron", 1 },
106#ifdef LOG_FTP
107 { LOG_FTP, "ftp", 1 },
108#endif
109 { LOG_LOCAL0, "local0", 6 },
110 { LOG_LOCAL1, "local1", 6 },
111 { LOG_LOCAL2, "local2", 6 },
112 { LOG_LOCAL3, "local3", 6 },
113 { LOG_LOCAL4, "local4", 6 },
114 { LOG_LOCAL5, "local5", 6 },
115 { LOG_LOCAL6, "local6", 6 },
116 { LOG_LOCAL7, "local7", 6 },
117 { 0, NULL, 0 },
118 };
119
120static const char *
121facility_name(int facility)
122{
Stephen Hemminger2d362d12009-12-21 12:54:58 +0300123 const struct facility_map *fm;
ajs274a4a42004-12-07 15:39:31 +0000124
125 for (fm = syslog_facilities; fm->name; fm++)
126 if (fm->facility == facility)
127 return fm->name;
128 return "";
129}
130
131static int
132facility_match(const char *str)
133{
Stephen Hemminger2d362d12009-12-21 12:54:58 +0300134 const struct facility_map *fm;
ajs274a4a42004-12-07 15:39:31 +0000135
136 for (fm = syslog_facilities; fm->name; fm++)
137 if (!strncmp(str,fm->name,fm->match))
138 return fm->facility;
139 return -1;
140}
141
142static int
143level_match(const char *s)
144{
145 int level ;
146
147 for ( level = 0 ; zlog_priority [level] != NULL ; level ++ )
148 if (!strncmp (s, zlog_priority[level], 2))
149 return level;
150 return ZLOG_DISABLED;
151}
152
ajscb585b62005-01-14 17:09:38 +0000153/* This is called from main when a daemon is invoked with -v or --version. */
hasso6590f2c2004-10-19 20:40:08 +0000154void
155print_version (const char *progname)
156{
ajscb585b62005-01-14 17:09:38 +0000157 printf ("%s version %s\n", progname, QUAGGA_VERSION);
158 printf ("%s\n", QUAGGA_COPYRIGHT);
hasso6590f2c2004-10-19 20:40:08 +0000159}
160
paul718e3742002-12-13 20:15:29 +0000161
162/* Utility function to concatenate argv argument into a single string
163 with inserting ' ' character between each argument. */
164char *
paul42d49862004-10-13 05:22:18 +0000165argv_concat (const char **argv, int argc, int shift)
paul718e3742002-12-13 20:15:29 +0000166{
167 int i;
ajsf6834d42005-01-28 20:28:35 +0000168 size_t len;
paul718e3742002-12-13 20:15:29 +0000169 char *str;
ajsf6834d42005-01-28 20:28:35 +0000170 char *p;
paul718e3742002-12-13 20:15:29 +0000171
ajsf6834d42005-01-28 20:28:35 +0000172 len = 0;
173 for (i = shift; i < argc; i++)
174 len += strlen(argv[i])+1;
175 if (!len)
176 return NULL;
177 p = str = XMALLOC(MTYPE_TMP, len);
paul718e3742002-12-13 20:15:29 +0000178 for (i = shift; i < argc; i++)
179 {
ajsf6834d42005-01-28 20:28:35 +0000180 size_t arglen;
181 memcpy(p, argv[i], (arglen = strlen(argv[i])));
182 p += arglen;
183 *p++ = ' ';
paul718e3742002-12-13 20:15:29 +0000184 }
ajsf6834d42005-01-28 20:28:35 +0000185 *(p-1) = '\0';
paul718e3742002-12-13 20:15:29 +0000186 return str;
187}
188
189/* Install top node of command vector. */
190void
191install_node (struct cmd_node *node,
192 int (*func) (struct vty *))
193{
194 vector_set_index (cmdvec, node->node, node);
195 node->func = func;
196 node->cmd_vector = vector_init (VECTOR_MIN_SIZE);
197}
198
199/* Compare two command's string. Used in sort_node (). */
ajs274a4a42004-12-07 15:39:31 +0000200static int
paul718e3742002-12-13 20:15:29 +0000201cmp_node (const void *p, const void *q)
202{
Chris Caputo228da422009-07-18 05:44:03 +0000203 const struct cmd_element *a = *(struct cmd_element * const *)p;
204 const struct cmd_element *b = *(struct cmd_element * const *)q;
paul718e3742002-12-13 20:15:29 +0000205
206 return strcmp (a->string, b->string);
207}
208
ajs274a4a42004-12-07 15:39:31 +0000209static int
paul718e3742002-12-13 20:15:29 +0000210cmp_desc (const void *p, const void *q)
211{
Chris Caputo228da422009-07-18 05:44:03 +0000212 const struct desc *a = *(struct desc * const *)p;
213 const struct desc *b = *(struct desc * const *)q;
paul718e3742002-12-13 20:15:29 +0000214
215 return strcmp (a->cmd, b->cmd);
216}
217
218/* Sort each node's command element according to command string. */
219void
220sort_node ()
221{
hasso8c328f12004-10-05 21:01:23 +0000222 unsigned int i, j;
paul718e3742002-12-13 20:15:29 +0000223 struct cmd_node *cnode;
224 vector descvec;
225 struct cmd_element *cmd_element;
226
Chris Caputo228da422009-07-18 05:44:03 +0000227 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +0000228 if ((cnode = vector_slot (cmdvec, i)) != NULL)
229 {
230 vector cmd_vector = cnode->cmd_vector;
paul55468c82005-03-14 20:19:01 +0000231 qsort (cmd_vector->index, vector_active (cmd_vector),
paulb8961472005-03-14 17:35:52 +0000232 sizeof (void *), cmp_node);
paul718e3742002-12-13 20:15:29 +0000233
paul55468c82005-03-14 20:19:01 +0000234 for (j = 0; j < vector_active (cmd_vector); j++)
paulb8961472005-03-14 17:35:52 +0000235 if ((cmd_element = vector_slot (cmd_vector, j)) != NULL
paul55468c82005-03-14 20:19:01 +0000236 && vector_active (cmd_element->strvec))
paul718e3742002-12-13 20:15:29 +0000237 {
238 descvec = vector_slot (cmd_element->strvec,
paul55468c82005-03-14 20:19:01 +0000239 vector_active (cmd_element->strvec) - 1);
240 qsort (descvec->index, vector_active (descvec),
paulb8961472005-03-14 17:35:52 +0000241 sizeof (void *), cmp_desc);
paul718e3742002-12-13 20:15:29 +0000242 }
243 }
244}
245
246/* Breaking up string into each command piece. I assume given
247 character is separated by a space character. Return value is a
248 vector which includes char ** data element. */
249vector
hassoea8e9d92004-10-07 21:32:14 +0000250cmd_make_strvec (const char *string)
paul718e3742002-12-13 20:15:29 +0000251{
hassoea8e9d92004-10-07 21:32:14 +0000252 const char *cp, *start;
253 char *token;
paul718e3742002-12-13 20:15:29 +0000254 int strlen;
255 vector strvec;
256
257 if (string == NULL)
258 return NULL;
259
260 cp = string;
261
262 /* Skip white spaces. */
263 while (isspace ((int) *cp) && *cp != '\0')
264 cp++;
265
266 /* Return if there is only white spaces */
267 if (*cp == '\0')
268 return NULL;
269
270 if (*cp == '!' || *cp == '#')
271 return NULL;
272
273 /* Prepare return vector. */
274 strvec = vector_init (VECTOR_MIN_SIZE);
275
276 /* Copy each command piece and set into vector. */
277 while (1)
278 {
279 start = cp;
280 while (!(isspace ((int) *cp) || *cp == '\r' || *cp == '\n') &&
281 *cp != '\0')
282 cp++;
283 strlen = cp - start;
284 token = XMALLOC (MTYPE_STRVEC, strlen + 1);
285 memcpy (token, start, strlen);
286 *(token + strlen) = '\0';
287 vector_set (strvec, token);
288
289 while ((isspace ((int) *cp) || *cp == '\n' || *cp == '\r') &&
290 *cp != '\0')
291 cp++;
292
293 if (*cp == '\0')
294 return strvec;
295 }
296}
297
298/* Free allocated string vector. */
299void
300cmd_free_strvec (vector v)
301{
hasso8c328f12004-10-05 21:01:23 +0000302 unsigned int i;
paul718e3742002-12-13 20:15:29 +0000303 char *cp;
304
305 if (!v)
306 return;
307
paul55468c82005-03-14 20:19:01 +0000308 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +0000309 if ((cp = vector_slot (v, i)) != NULL)
310 XFREE (MTYPE_STRVEC, cp);
311
312 vector_free (v);
313}
314
315/* Fetch next description. Used in cmd_make_descvec(). */
ajs274a4a42004-12-07 15:39:31 +0000316static char *
hasso6ad96ea2004-10-07 19:33:46 +0000317cmd_desc_str (const char **string)
paul718e3742002-12-13 20:15:29 +0000318{
hasso6ad96ea2004-10-07 19:33:46 +0000319 const char *cp, *start;
320 char *token;
paul718e3742002-12-13 20:15:29 +0000321 int strlen;
322
323 cp = *string;
324
325 if (cp == NULL)
326 return NULL;
327
328 /* Skip white spaces. */
329 while (isspace ((int) *cp) && *cp != '\0')
330 cp++;
331
332 /* Return if there is only white spaces */
333 if (*cp == '\0')
334 return NULL;
335
336 start = cp;
337
338 while (!(*cp == '\r' || *cp == '\n') && *cp != '\0')
339 cp++;
340
341 strlen = cp - start;
342 token = XMALLOC (MTYPE_STRVEC, strlen + 1);
343 memcpy (token, start, strlen);
344 *(token + strlen) = '\0';
345
346 *string = cp;
347
348 return token;
349}
350
351/* New string vector. */
ajs274a4a42004-12-07 15:39:31 +0000352static vector
hasso8c328f12004-10-05 21:01:23 +0000353cmd_make_descvec (const char *string, const char *descstr)
paul718e3742002-12-13 20:15:29 +0000354{
355 int multiple = 0;
hasso8c328f12004-10-05 21:01:23 +0000356 const char *sp;
paul718e3742002-12-13 20:15:29 +0000357 char *token;
358 int len;
hasso8c328f12004-10-05 21:01:23 +0000359 const char *cp;
360 const char *dp;
paul718e3742002-12-13 20:15:29 +0000361 vector allvec;
362 vector strvec = NULL;
363 struct desc *desc;
364
365 cp = string;
366 dp = descstr;
367
368 if (cp == NULL)
369 return NULL;
370
371 allvec = vector_init (VECTOR_MIN_SIZE);
372
373 while (1)
374 {
375 while (isspace ((int) *cp) && *cp != '\0')
376 cp++;
377
378 if (*cp == '(')
379 {
380 multiple = 1;
381 cp++;
382 }
383 if (*cp == ')')
384 {
385 multiple = 0;
386 cp++;
387 }
388 if (*cp == '|')
389 {
390 if (! multiple)
391 {
392 fprintf (stderr, "Command parse error!: %s\n", string);
393 exit (1);
394 }
395 cp++;
396 }
397
398 while (isspace ((int) *cp) && *cp != '\0')
399 cp++;
400
401 if (*cp == '(')
402 {
403 multiple = 1;
404 cp++;
405 }
406
407 if (*cp == '\0')
408 return allvec;
409
410 sp = cp;
411
412 while (! (isspace ((int) *cp) || *cp == '\r' || *cp == '\n' || *cp == ')' || *cp == '|') && *cp != '\0')
413 cp++;
414
415 len = cp - sp;
416
417 token = XMALLOC (MTYPE_STRVEC, len + 1);
418 memcpy (token, sp, len);
419 *(token + len) = '\0';
420
421 desc = XCALLOC (MTYPE_DESC, sizeof (struct desc));
422 desc->cmd = token;
423 desc->str = cmd_desc_str (&dp);
424
425 if (multiple)
426 {
427 if (multiple == 1)
428 {
429 strvec = vector_init (VECTOR_MIN_SIZE);
430 vector_set (allvec, strvec);
431 }
432 multiple++;
433 }
434 else
435 {
436 strvec = vector_init (VECTOR_MIN_SIZE);
437 vector_set (allvec, strvec);
438 }
439 vector_set (strvec, desc);
440 }
441}
442
443/* Count mandantory string vector size. This is to determine inputed
444 command has enough command length. */
ajs274a4a42004-12-07 15:39:31 +0000445static int
paul718e3742002-12-13 20:15:29 +0000446cmd_cmdsize (vector strvec)
447{
hasso8c328f12004-10-05 21:01:23 +0000448 unsigned int i;
paul718e3742002-12-13 20:15:29 +0000449 int size = 0;
450 vector descvec;
paulb8961472005-03-14 17:35:52 +0000451 struct desc *desc;
paul718e3742002-12-13 20:15:29 +0000452
paul55468c82005-03-14 20:19:01 +0000453 for (i = 0; i < vector_active (strvec); i++)
paulb8961472005-03-14 17:35:52 +0000454 if ((descvec = vector_slot (strvec, i)) != NULL)
paul718e3742002-12-13 20:15:29 +0000455 {
paul55468c82005-03-14 20:19:01 +0000456 if ((vector_active (descvec)) == 1
paulb8961472005-03-14 17:35:52 +0000457 && (desc = vector_slot (descvec, 0)) != NULL)
paul718e3742002-12-13 20:15:29 +0000458 {
hasso8c328f12004-10-05 21:01:23 +0000459 if (desc->cmd == NULL || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +0000460 return size;
461 else
462 size++;
463 }
464 else
465 size++;
466 }
467 return size;
468}
469
470/* Return prompt character of specified node. */
hasso8c328f12004-10-05 21:01:23 +0000471const char *
paul718e3742002-12-13 20:15:29 +0000472cmd_prompt (enum node_type node)
473{
474 struct cmd_node *cnode;
475
476 cnode = vector_slot (cmdvec, node);
477 return cnode->prompt;
478}
479
480/* Install a command into a node. */
481void
482install_element (enum node_type ntype, struct cmd_element *cmd)
483{
484 struct cmd_node *cnode;
pauleb820af2005-09-05 11:54:13 +0000485
486 /* cmd_init hasn't been called */
487 if (!cmdvec)
488 return;
489
paul718e3742002-12-13 20:15:29 +0000490 cnode = vector_slot (cmdvec, ntype);
491
492 if (cnode == NULL)
493 {
494 fprintf (stderr, "Command node %d doesn't exist, please check it\n",
495 ntype);
496 exit (1);
497 }
498
499 vector_set (cnode->cmd_vector, cmd);
500
Chris Caputo228da422009-07-18 05:44:03 +0000501 if (cmd->strvec == NULL)
502 cmd->strvec = cmd_make_descvec (cmd->string, cmd->doc);
503
paul718e3742002-12-13 20:15:29 +0000504 cmd->cmdsize = cmd_cmdsize (cmd->strvec);
505}
506
Stephen Hemminger2d362d12009-12-21 12:54:58 +0300507static const unsigned char itoa64[] =
paul718e3742002-12-13 20:15:29 +0000508"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
509
ajs274a4a42004-12-07 15:39:31 +0000510static void
paul718e3742002-12-13 20:15:29 +0000511to64(char *s, long v, int n)
512{
513 while (--n >= 0)
514 {
515 *s++ = itoa64[v&0x3f];
516 v >>= 6;
517 }
518}
519
ajs274a4a42004-12-07 15:39:31 +0000520static char *
521zencrypt (const char *passwd)
paul718e3742002-12-13 20:15:29 +0000522{
523 char salt[6];
524 struct timeval tv;
525 char *crypt (const char *, const char *);
526
527 gettimeofday(&tv,0);
528
529 to64(&salt[0], random(), 3);
530 to64(&salt[3], tv.tv_usec, 3);
531 salt[5] = '\0';
532
533 return crypt (passwd, salt);
534}
535
536/* This function write configuration of this host. */
ajs274a4a42004-12-07 15:39:31 +0000537static int
paul718e3742002-12-13 20:15:29 +0000538config_write_host (struct vty *vty)
539{
540 if (host.name)
541 vty_out (vty, "hostname %s%s", host.name, VTY_NEWLINE);
542
543 if (host.encrypt)
544 {
545 if (host.password_encrypt)
546 vty_out (vty, "password 8 %s%s", host.password_encrypt, VTY_NEWLINE);
547 if (host.enable_encrypt)
548 vty_out (vty, "enable password 8 %s%s", host.enable_encrypt, VTY_NEWLINE);
549 }
550 else
551 {
552 if (host.password)
553 vty_out (vty, "password %s%s", host.password, VTY_NEWLINE);
554 if (host.enable)
555 vty_out (vty, "enable password %s%s", host.enable, VTY_NEWLINE);
556 }
557
ajs274a4a42004-12-07 15:39:31 +0000558 if (zlog_default->default_lvl != LOG_DEBUG)
ajs82146b82004-12-07 17:15:55 +0000559 {
560 vty_out (vty, "! N.B. The 'log trap' command is deprecated.%s",
561 VTY_NEWLINE);
562 vty_out (vty, "log trap %s%s",
563 zlog_priority[zlog_default->default_lvl], VTY_NEWLINE);
564 }
paul718e3742002-12-13 20:15:29 +0000565
ajs274a4a42004-12-07 15:39:31 +0000566 if (host.logfile && (zlog_default->maxlvl[ZLOG_DEST_FILE] != ZLOG_DISABLED))
paul12ab19f2003-07-26 06:14:55 +0000567 {
ajs274a4a42004-12-07 15:39:31 +0000568 vty_out (vty, "log file %s", host.logfile);
569 if (zlog_default->maxlvl[ZLOG_DEST_FILE] != zlog_default->default_lvl)
570 vty_out (vty, " %s",
571 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_FILE]]);
paul12ab19f2003-07-26 06:14:55 +0000572 vty_out (vty, "%s", VTY_NEWLINE);
573 }
ajs274a4a42004-12-07 15:39:31 +0000574
575 if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != ZLOG_DISABLED)
576 {
577 vty_out (vty, "log stdout");
578 if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != zlog_default->default_lvl)
579 vty_out (vty, " %s",
580 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_STDOUT]]);
581 vty_out (vty, "%s", VTY_NEWLINE);
582 }
583
584 if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
585 vty_out(vty,"no log monitor%s",VTY_NEWLINE);
586 else if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] != zlog_default->default_lvl)
587 vty_out(vty,"log monitor %s%s",
588 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_MONITOR]],VTY_NEWLINE);
589
590 if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED)
591 {
592 vty_out (vty, "log syslog");
593 if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != zlog_default->default_lvl)
594 vty_out (vty, " %s",
595 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_SYSLOG]]);
596 vty_out (vty, "%s", VTY_NEWLINE);
597 }
598
599 if (zlog_default->facility != LOG_DAEMON)
600 vty_out (vty, "log facility %s%s",
601 facility_name(zlog_default->facility), VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +0000602
603 if (zlog_default->record_priority == 1)
604 vty_out (vty, "log record-priority%s", VTY_NEWLINE);
605
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +0000606 if (zlog_default->timestamp_precision > 0)
607 vty_out (vty, "log timestamp precision %d%s",
608 zlog_default->timestamp_precision, VTY_NEWLINE);
609
paul718e3742002-12-13 20:15:29 +0000610 if (host.advanced)
611 vty_out (vty, "service advanced-vty%s", VTY_NEWLINE);
612
613 if (host.encrypt)
614 vty_out (vty, "service password-encryption%s", VTY_NEWLINE);
615
616 if (host.lines >= 0)
617 vty_out (vty, "service terminal-length %d%s", host.lines,
618 VTY_NEWLINE);
619
paul3b0c5d92005-03-08 10:43:43 +0000620 if (host.motdfile)
621 vty_out (vty, "banner motd file %s%s", host.motdfile, VTY_NEWLINE);
622 else if (! host.motd)
paul718e3742002-12-13 20:15:29 +0000623 vty_out (vty, "no banner motd%s", VTY_NEWLINE);
624
625 return 1;
626}
627
628/* Utility function for getting command vector. */
ajs274a4a42004-12-07 15:39:31 +0000629static vector
paul718e3742002-12-13 20:15:29 +0000630cmd_node_vector (vector v, enum node_type ntype)
631{
632 struct cmd_node *cnode = vector_slot (v, ntype);
633 return cnode->cmd_vector;
634}
635
ajs274a4a42004-12-07 15:39:31 +0000636#if 0
637/* Filter command vector by symbol. This function is not actually used;
638 * should it be deleted? */
639static int
paul718e3742002-12-13 20:15:29 +0000640cmd_filter_by_symbol (char *command, char *symbol)
641{
642 int i, lim;
643
644 if (strcmp (symbol, "IPV4_ADDRESS") == 0)
645 {
646 i = 0;
647 lim = strlen (command);
648 while (i < lim)
649 {
650 if (! (isdigit ((int) command[i]) || command[i] == '.' || command[i] == '/'))
651 return 1;
652 i++;
653 }
654 return 0;
655 }
656 if (strcmp (symbol, "STRING") == 0)
657 {
658 i = 0;
659 lim = strlen (command);
660 while (i < lim)
661 {
662 if (! (isalpha ((int) command[i]) || command[i] == '_' || command[i] == '-'))
663 return 1;
664 i++;
665 }
666 return 0;
667 }
668 if (strcmp (symbol, "IFNAME") == 0)
669 {
670 i = 0;
671 lim = strlen (command);
672 while (i < lim)
673 {
674 if (! isalnum ((int) command[i]))
675 return 1;
676 i++;
677 }
678 return 0;
679 }
680 return 0;
681}
ajs274a4a42004-12-07 15:39:31 +0000682#endif
paul718e3742002-12-13 20:15:29 +0000683
684/* Completion match types. */
685enum match_type
686{
687 no_match,
688 extend_match,
689 ipv4_prefix_match,
690 ipv4_match,
691 ipv6_prefix_match,
692 ipv6_match,
693 range_match,
694 vararg_match,
695 partly_match,
696 exact_match
697};
698
ajs274a4a42004-12-07 15:39:31 +0000699static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000700cmd_ipv4_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000701{
hasso8c328f12004-10-05 21:01:23 +0000702 const char *sp;
paul718e3742002-12-13 20:15:29 +0000703 int dots = 0, nums = 0;
704 char buf[4];
705
706 if (str == NULL)
707 return partly_match;
708
709 for (;;)
710 {
711 memset (buf, 0, sizeof (buf));
712 sp = str;
713 while (*str != '\0')
714 {
715 if (*str == '.')
716 {
717 if (dots >= 3)
718 return no_match;
719
720 if (*(str + 1) == '.')
721 return no_match;
722
723 if (*(str + 1) == '\0')
724 return partly_match;
725
726 dots++;
727 break;
728 }
729 if (!isdigit ((int) *str))
730 return no_match;
731
732 str++;
733 }
734
735 if (str - sp > 3)
736 return no_match;
737
738 strncpy (buf, sp, str - sp);
739 if (atoi (buf) > 255)
740 return no_match;
741
742 nums++;
743
744 if (*str == '\0')
745 break;
746
747 str++;
748 }
749
750 if (nums < 4)
751 return partly_match;
752
753 return exact_match;
754}
755
ajs274a4a42004-12-07 15:39:31 +0000756static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000757cmd_ipv4_prefix_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000758{
hasso8c328f12004-10-05 21:01:23 +0000759 const char *sp;
paul718e3742002-12-13 20:15:29 +0000760 int dots = 0;
761 char buf[4];
762
763 if (str == NULL)
764 return partly_match;
765
766 for (;;)
767 {
768 memset (buf, 0, sizeof (buf));
769 sp = str;
770 while (*str != '\0' && *str != '/')
771 {
772 if (*str == '.')
773 {
774 if (dots == 3)
775 return no_match;
776
777 if (*(str + 1) == '.' || *(str + 1) == '/')
778 return no_match;
779
780 if (*(str + 1) == '\0')
781 return partly_match;
782
783 dots++;
784 break;
785 }
786
787 if (!isdigit ((int) *str))
788 return no_match;
789
790 str++;
791 }
792
793 if (str - sp > 3)
794 return no_match;
795
796 strncpy (buf, sp, str - sp);
797 if (atoi (buf) > 255)
798 return no_match;
799
800 if (dots == 3)
801 {
802 if (*str == '/')
803 {
804 if (*(str + 1) == '\0')
805 return partly_match;
806
807 str++;
808 break;
809 }
810 else if (*str == '\0')
811 return partly_match;
812 }
813
814 if (*str == '\0')
815 return partly_match;
816
817 str++;
818 }
819
820 sp = str;
821 while (*str != '\0')
822 {
823 if (!isdigit ((int) *str))
824 return no_match;
825
826 str++;
827 }
828
829 if (atoi (sp) > 32)
830 return no_match;
831
832 return exact_match;
833}
834
835#define IPV6_ADDR_STR "0123456789abcdefABCDEF:.%"
836#define IPV6_PREFIX_STR "0123456789abcdefABCDEF:.%/"
837#define STATE_START 1
838#define STATE_COLON 2
839#define STATE_DOUBLE 3
840#define STATE_ADDR 4
841#define STATE_DOT 5
842#define STATE_SLASH 6
843#define STATE_MASK 7
844
paul22e0a9e2003-07-11 17:55:46 +0000845#ifdef HAVE_IPV6
846
ajs274a4a42004-12-07 15:39:31 +0000847static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000848cmd_ipv6_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000849{
850 int state = STATE_START;
851 int colons = 0, nums = 0, double_colon = 0;
hasso8c328f12004-10-05 21:01:23 +0000852 const char *sp = NULL;
hasso726f9b22003-05-25 21:04:54 +0000853 struct sockaddr_in6 sin6_dummy;
854 int ret;
paul718e3742002-12-13 20:15:29 +0000855
856 if (str == NULL)
857 return partly_match;
858
859 if (strspn (str, IPV6_ADDR_STR) != strlen (str))
860 return no_match;
861
hasso726f9b22003-05-25 21:04:54 +0000862 /* use inet_pton that has a better support,
863 * for example inet_pton can support the automatic addresses:
864 * ::1.2.3.4
865 */
866 ret = inet_pton(AF_INET6, str, &sin6_dummy.sin6_addr);
867
868 if (ret == 1)
869 return exact_match;
870
paul718e3742002-12-13 20:15:29 +0000871 while (*str != '\0')
872 {
873 switch (state)
874 {
875 case STATE_START:
876 if (*str == ':')
877 {
878 if (*(str + 1) != ':' && *(str + 1) != '\0')
879 return no_match;
880 colons--;
881 state = STATE_COLON;
882 }
883 else
884 {
885 sp = str;
886 state = STATE_ADDR;
887 }
888
889 continue;
890 case STATE_COLON:
891 colons++;
892 if (*(str + 1) == ':')
893 state = STATE_DOUBLE;
894 else
895 {
896 sp = str + 1;
897 state = STATE_ADDR;
898 }
899 break;
900 case STATE_DOUBLE:
901 if (double_colon)
902 return no_match;
903
904 if (*(str + 1) == ':')
905 return no_match;
906 else
907 {
908 if (*(str + 1) != '\0')
909 colons++;
910 sp = str + 1;
911 state = STATE_ADDR;
912 }
913
914 double_colon++;
915 nums++;
916 break;
917 case STATE_ADDR:
918 if (*(str + 1) == ':' || *(str + 1) == '\0')
919 {
920 if (str - sp > 3)
921 return no_match;
922
923 nums++;
924 state = STATE_COLON;
925 }
926 if (*(str + 1) == '.')
927 state = STATE_DOT;
928 break;
929 case STATE_DOT:
930 state = STATE_ADDR;
931 break;
932 default:
933 break;
934 }
935
936 if (nums > 8)
937 return no_match;
938
939 if (colons > 7)
940 return no_match;
941
942 str++;
943 }
944
945#if 0
946 if (nums < 11)
947 return partly_match;
948#endif /* 0 */
949
950 return exact_match;
951}
952
ajs274a4a42004-12-07 15:39:31 +0000953static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000954cmd_ipv6_prefix_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000955{
956 int state = STATE_START;
957 int colons = 0, nums = 0, double_colon = 0;
958 int mask;
hasso8c328f12004-10-05 21:01:23 +0000959 const char *sp = NULL;
paul718e3742002-12-13 20:15:29 +0000960 char *endptr = NULL;
961
962 if (str == NULL)
963 return partly_match;
964
965 if (strspn (str, IPV6_PREFIX_STR) != strlen (str))
966 return no_match;
967
968 while (*str != '\0' && state != STATE_MASK)
969 {
970 switch (state)
971 {
972 case STATE_START:
973 if (*str == ':')
974 {
975 if (*(str + 1) != ':' && *(str + 1) != '\0')
976 return no_match;
977 colons--;
978 state = STATE_COLON;
979 }
980 else
981 {
982 sp = str;
983 state = STATE_ADDR;
984 }
985
986 continue;
987 case STATE_COLON:
988 colons++;
989 if (*(str + 1) == '/')
990 return no_match;
991 else if (*(str + 1) == ':')
992 state = STATE_DOUBLE;
993 else
994 {
995 sp = str + 1;
996 state = STATE_ADDR;
997 }
998 break;
999 case STATE_DOUBLE:
1000 if (double_colon)
1001 return no_match;
1002
1003 if (*(str + 1) == ':')
1004 return no_match;
1005 else
1006 {
1007 if (*(str + 1) != '\0' && *(str + 1) != '/')
1008 colons++;
1009 sp = str + 1;
1010
1011 if (*(str + 1) == '/')
1012 state = STATE_SLASH;
1013 else
1014 state = STATE_ADDR;
1015 }
1016
1017 double_colon++;
1018 nums += 1;
1019 break;
1020 case STATE_ADDR:
1021 if (*(str + 1) == ':' || *(str + 1) == '.'
1022 || *(str + 1) == '\0' || *(str + 1) == '/')
1023 {
1024 if (str - sp > 3)
1025 return no_match;
1026
1027 for (; sp <= str; sp++)
1028 if (*sp == '/')
1029 return no_match;
1030
1031 nums++;
1032
1033 if (*(str + 1) == ':')
1034 state = STATE_COLON;
1035 else if (*(str + 1) == '.')
1036 state = STATE_DOT;
1037 else if (*(str + 1) == '/')
1038 state = STATE_SLASH;
1039 }
1040 break;
1041 case STATE_DOT:
1042 state = STATE_ADDR;
1043 break;
1044 case STATE_SLASH:
1045 if (*(str + 1) == '\0')
1046 return partly_match;
1047
1048 state = STATE_MASK;
1049 break;
1050 default:
1051 break;
1052 }
1053
1054 if (nums > 11)
1055 return no_match;
1056
1057 if (colons > 7)
1058 return no_match;
1059
1060 str++;
1061 }
1062
1063 if (state < STATE_MASK)
1064 return partly_match;
1065
1066 mask = strtol (str, &endptr, 10);
1067 if (*endptr != '\0')
1068 return no_match;
1069
1070 if (mask < 0 || mask > 128)
1071 return no_match;
1072
1073/* I don't know why mask < 13 makes command match partly.
1074 Forgive me to make this comments. I Want to set static default route
1075 because of lack of function to originate default in ospf6d; sorry
1076 yasu
1077 if (mask < 13)
1078 return partly_match;
1079*/
1080
1081 return exact_match;
1082}
1083
paul22e0a9e2003-07-11 17:55:46 +00001084#endif /* HAVE_IPV6 */
1085
paul718e3742002-12-13 20:15:29 +00001086#define DECIMAL_STRLEN_MAX 10
1087
ajs274a4a42004-12-07 15:39:31 +00001088static int
hasso8c328f12004-10-05 21:01:23 +00001089cmd_range_match (const char *range, const char *str)
paul718e3742002-12-13 20:15:29 +00001090{
1091 char *p;
1092 char buf[DECIMAL_STRLEN_MAX + 1];
1093 char *endptr = NULL;
1094 unsigned long min, max, val;
1095
1096 if (str == NULL)
1097 return 1;
1098
1099 val = strtoul (str, &endptr, 10);
1100 if (*endptr != '\0')
1101 return 0;
1102
1103 range++;
1104 p = strchr (range, '-');
1105 if (p == NULL)
1106 return 0;
1107 if (p - range > DECIMAL_STRLEN_MAX)
1108 return 0;
1109 strncpy (buf, range, p - range);
1110 buf[p - range] = '\0';
1111 min = strtoul (buf, &endptr, 10);
1112 if (*endptr != '\0')
1113 return 0;
1114
1115 range = p + 1;
1116 p = strchr (range, '>');
1117 if (p == NULL)
1118 return 0;
1119 if (p - range > DECIMAL_STRLEN_MAX)
1120 return 0;
1121 strncpy (buf, range, p - range);
1122 buf[p - range] = '\0';
1123 max = strtoul (buf, &endptr, 10);
1124 if (*endptr != '\0')
1125 return 0;
1126
1127 if (val < min || val > max)
1128 return 0;
1129
1130 return 1;
1131}
1132
1133/* Make completion match and return match type flag. */
ajs274a4a42004-12-07 15:39:31 +00001134static enum match_type
hasso8c328f12004-10-05 21:01:23 +00001135cmd_filter_by_completion (char *command, vector v, unsigned int index)
paul718e3742002-12-13 20:15:29 +00001136{
hasso8c328f12004-10-05 21:01:23 +00001137 unsigned int i;
1138 const char *str;
paul718e3742002-12-13 20:15:29 +00001139 struct cmd_element *cmd_element;
1140 enum match_type match_type;
1141 vector descvec;
1142 struct desc *desc;
paul909a2152005-03-14 17:41:45 +00001143
paul718e3742002-12-13 20:15:29 +00001144 match_type = no_match;
1145
1146 /* If command and cmd_element string does not match set NULL to vector */
paul55468c82005-03-14 20:19:01 +00001147 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001148 if ((cmd_element = vector_slot (v, i)) != NULL)
1149 {
paul55468c82005-03-14 20:19:01 +00001150 if (index >= vector_active (cmd_element->strvec))
paul718e3742002-12-13 20:15:29 +00001151 vector_slot (v, i) = NULL;
1152 else
1153 {
hasso8c328f12004-10-05 21:01:23 +00001154 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001155 int matched = 0;
1156
1157 descvec = vector_slot (cmd_element->strvec, index);
paul909a2152005-03-14 17:41:45 +00001158
paul55468c82005-03-14 20:19:01 +00001159 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001160 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001161 {
1162 str = desc->cmd;
1163
1164 if (CMD_VARARG (str))
1165 {
1166 if (match_type < vararg_match)
1167 match_type = vararg_match;
1168 matched++;
1169 }
1170 else if (CMD_RANGE (str))
1171 {
1172 if (cmd_range_match (str, command))
1173 {
1174 if (match_type < range_match)
1175 match_type = range_match;
paul718e3742002-12-13 20:15:29 +00001176
paul909a2152005-03-14 17:41:45 +00001177 matched++;
1178 }
1179 }
paul22e0a9e2003-07-11 17:55:46 +00001180#ifdef HAVE_IPV6
paul909a2152005-03-14 17:41:45 +00001181 else if (CMD_IPV6 (str))
1182 {
1183 if (cmd_ipv6_match (command))
1184 {
1185 if (match_type < ipv6_match)
1186 match_type = ipv6_match;
paul718e3742002-12-13 20:15:29 +00001187
paul909a2152005-03-14 17:41:45 +00001188 matched++;
1189 }
1190 }
1191 else if (CMD_IPV6_PREFIX (str))
1192 {
1193 if (cmd_ipv6_prefix_match (command))
1194 {
1195 if (match_type < ipv6_prefix_match)
1196 match_type = ipv6_prefix_match;
paul718e3742002-12-13 20:15:29 +00001197
paul909a2152005-03-14 17:41:45 +00001198 matched++;
1199 }
1200 }
1201#endif /* HAVE_IPV6 */
1202 else if (CMD_IPV4 (str))
1203 {
1204 if (cmd_ipv4_match (command))
1205 {
1206 if (match_type < ipv4_match)
1207 match_type = ipv4_match;
paul718e3742002-12-13 20:15:29 +00001208
paul909a2152005-03-14 17:41:45 +00001209 matched++;
1210 }
1211 }
1212 else if (CMD_IPV4_PREFIX (str))
1213 {
1214 if (cmd_ipv4_prefix_match (command))
1215 {
1216 if (match_type < ipv4_prefix_match)
1217 match_type = ipv4_prefix_match;
1218 matched++;
1219 }
1220 }
1221 else
1222 /* Check is this point's argument optional ? */
1223 if (CMD_OPTION (str) || CMD_VARIABLE (str))
1224 {
1225 if (match_type < extend_match)
1226 match_type = extend_match;
1227 matched++;
1228 }
1229 else if (strncmp (command, str, strlen (command)) == 0)
1230 {
1231 if (strcmp (command, str) == 0)
1232 match_type = exact_match;
1233 else
1234 {
1235 if (match_type < partly_match)
1236 match_type = partly_match;
1237 }
1238 matched++;
1239 }
1240 }
1241 if (!matched)
paul718e3742002-12-13 20:15:29 +00001242 vector_slot (v, i) = NULL;
1243 }
1244 }
1245 return match_type;
1246}
1247
1248/* Filter vector by command character with index. */
ajs274a4a42004-12-07 15:39:31 +00001249static enum match_type
hasso8c328f12004-10-05 21:01:23 +00001250cmd_filter_by_string (char *command, vector v, unsigned int index)
paul718e3742002-12-13 20:15:29 +00001251{
hasso8c328f12004-10-05 21:01:23 +00001252 unsigned int i;
1253 const char *str;
paul718e3742002-12-13 20:15:29 +00001254 struct cmd_element *cmd_element;
1255 enum match_type match_type;
1256 vector descvec;
1257 struct desc *desc;
paul909a2152005-03-14 17:41:45 +00001258
paul718e3742002-12-13 20:15:29 +00001259 match_type = no_match;
1260
1261 /* If command and cmd_element string does not match set NULL to vector */
paul55468c82005-03-14 20:19:01 +00001262 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001263 if ((cmd_element = vector_slot (v, i)) != NULL)
1264 {
1265 /* If given index is bigger than max string vector of command,
paul909a2152005-03-14 17:41:45 +00001266 set NULL */
paul55468c82005-03-14 20:19:01 +00001267 if (index >= vector_active (cmd_element->strvec))
paul718e3742002-12-13 20:15:29 +00001268 vector_slot (v, i) = NULL;
paul909a2152005-03-14 17:41:45 +00001269 else
paul718e3742002-12-13 20:15:29 +00001270 {
hasso8c328f12004-10-05 21:01:23 +00001271 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001272 int matched = 0;
1273
1274 descvec = vector_slot (cmd_element->strvec, index);
1275
paul55468c82005-03-14 20:19:01 +00001276 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001277 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001278 {
1279 str = desc->cmd;
paul718e3742002-12-13 20:15:29 +00001280
paul909a2152005-03-14 17:41:45 +00001281 if (CMD_VARARG (str))
1282 {
1283 if (match_type < vararg_match)
1284 match_type = vararg_match;
1285 matched++;
1286 }
1287 else if (CMD_RANGE (str))
1288 {
1289 if (cmd_range_match (str, command))
1290 {
1291 if (match_type < range_match)
1292 match_type = range_match;
1293 matched++;
1294 }
1295 }
paul22e0a9e2003-07-11 17:55:46 +00001296#ifdef HAVE_IPV6
paul909a2152005-03-14 17:41:45 +00001297 else if (CMD_IPV6 (str))
1298 {
1299 if (cmd_ipv6_match (command) == exact_match)
1300 {
1301 if (match_type < ipv6_match)
1302 match_type = ipv6_match;
1303 matched++;
1304 }
1305 }
1306 else if (CMD_IPV6_PREFIX (str))
1307 {
1308 if (cmd_ipv6_prefix_match (command) == exact_match)
1309 {
1310 if (match_type < ipv6_prefix_match)
1311 match_type = ipv6_prefix_match;
1312 matched++;
1313 }
1314 }
paul22e0a9e2003-07-11 17:55:46 +00001315#endif /* HAVE_IPV6 */
paul909a2152005-03-14 17:41:45 +00001316 else if (CMD_IPV4 (str))
1317 {
1318 if (cmd_ipv4_match (command) == exact_match)
1319 {
1320 if (match_type < ipv4_match)
1321 match_type = ipv4_match;
1322 matched++;
1323 }
1324 }
1325 else if (CMD_IPV4_PREFIX (str))
1326 {
1327 if (cmd_ipv4_prefix_match (command) == exact_match)
1328 {
1329 if (match_type < ipv4_prefix_match)
1330 match_type = ipv4_prefix_match;
1331 matched++;
1332 }
1333 }
1334 else if (CMD_OPTION (str) || CMD_VARIABLE (str))
1335 {
1336 if (match_type < extend_match)
1337 match_type = extend_match;
1338 matched++;
1339 }
1340 else
1341 {
1342 if (strcmp (command, str) == 0)
1343 {
1344 match_type = exact_match;
1345 matched++;
1346 }
1347 }
1348 }
1349 if (!matched)
paul718e3742002-12-13 20:15:29 +00001350 vector_slot (v, i) = NULL;
1351 }
1352 }
1353 return match_type;
1354}
1355
1356/* Check ambiguous match */
ajs274a4a42004-12-07 15:39:31 +00001357static int
paul718e3742002-12-13 20:15:29 +00001358is_cmd_ambiguous (char *command, vector v, int index, enum match_type type)
1359{
hasso8c328f12004-10-05 21:01:23 +00001360 unsigned int i;
1361 unsigned int j;
1362 const char *str = NULL;
paul718e3742002-12-13 20:15:29 +00001363 struct cmd_element *cmd_element;
hasso8c328f12004-10-05 21:01:23 +00001364 const char *matched = NULL;
paul718e3742002-12-13 20:15:29 +00001365 vector descvec;
1366 struct desc *desc;
paul909a2152005-03-14 17:41:45 +00001367
paul55468c82005-03-14 20:19:01 +00001368 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001369 if ((cmd_element = vector_slot (v, i)) != NULL)
1370 {
1371 int match = 0;
1372
1373 descvec = vector_slot (cmd_element->strvec, index);
1374
paul55468c82005-03-14 20:19:01 +00001375 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001376 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001377 {
1378 enum match_type ret;
1379
1380 str = desc->cmd;
paul718e3742002-12-13 20:15:29 +00001381
paul909a2152005-03-14 17:41:45 +00001382 switch (type)
1383 {
1384 case exact_match:
1385 if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
1386 && strcmp (command, str) == 0)
1387 match++;
1388 break;
1389 case partly_match:
1390 if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
1391 && strncmp (command, str, strlen (command)) == 0)
1392 {
1393 if (matched && strcmp (matched, str) != 0)
1394 return 1; /* There is ambiguous match. */
1395 else
1396 matched = str;
1397 match++;
1398 }
1399 break;
1400 case range_match:
1401 if (cmd_range_match (str, command))
1402 {
1403 if (matched && strcmp (matched, str) != 0)
1404 return 1;
1405 else
1406 matched = str;
1407 match++;
1408 }
1409 break;
1410#ifdef HAVE_IPV6
1411 case ipv6_match:
1412 if (CMD_IPV6 (str))
1413 match++;
1414 break;
1415 case ipv6_prefix_match:
1416 if ((ret = cmd_ipv6_prefix_match (command)) != no_match)
1417 {
1418 if (ret == partly_match)
1419 return 2; /* There is incomplete match. */
paul718e3742002-12-13 20:15:29 +00001420
paul909a2152005-03-14 17:41:45 +00001421 match++;
1422 }
1423 break;
1424#endif /* HAVE_IPV6 */
1425 case ipv4_match:
1426 if (CMD_IPV4 (str))
paul718e3742002-12-13 20:15:29 +00001427 match++;
paul909a2152005-03-14 17:41:45 +00001428 break;
1429 case ipv4_prefix_match:
1430 if ((ret = cmd_ipv4_prefix_match (command)) != no_match)
1431 {
1432 if (ret == partly_match)
1433 return 2; /* There is incomplete match. */
paul718e3742002-12-13 20:15:29 +00001434
paul909a2152005-03-14 17:41:45 +00001435 match++;
1436 }
1437 break;
1438 case extend_match:
1439 if (CMD_OPTION (str) || CMD_VARIABLE (str))
paul718e3742002-12-13 20:15:29 +00001440 match++;
paul909a2152005-03-14 17:41:45 +00001441 break;
1442 case no_match:
1443 default:
1444 break;
1445 }
1446 }
1447 if (!match)
paul718e3742002-12-13 20:15:29 +00001448 vector_slot (v, i) = NULL;
1449 }
1450 return 0;
1451}
1452
1453/* If src matches dst return dst string, otherwise return NULL */
ajs274a4a42004-12-07 15:39:31 +00001454static const char *
hasso8c328f12004-10-05 21:01:23 +00001455cmd_entry_function (const char *src, const char *dst)
paul718e3742002-12-13 20:15:29 +00001456{
1457 /* Skip variable arguments. */
1458 if (CMD_OPTION (dst) || CMD_VARIABLE (dst) || CMD_VARARG (dst) ||
1459 CMD_IPV4 (dst) || CMD_IPV4_PREFIX (dst) || CMD_RANGE (dst))
1460 return NULL;
1461
1462 /* In case of 'command \t', given src is NULL string. */
1463 if (src == NULL)
1464 return dst;
1465
1466 /* Matched with input string. */
1467 if (strncmp (src, dst, strlen (src)) == 0)
1468 return dst;
1469
1470 return NULL;
1471}
1472
1473/* If src matches dst return dst string, otherwise return NULL */
1474/* This version will return the dst string always if it is
1475 CMD_VARIABLE for '?' key processing */
ajs274a4a42004-12-07 15:39:31 +00001476static const char *
hasso8c328f12004-10-05 21:01:23 +00001477cmd_entry_function_desc (const char *src, const char *dst)
paul718e3742002-12-13 20:15:29 +00001478{
1479 if (CMD_VARARG (dst))
1480 return dst;
1481
1482 if (CMD_RANGE (dst))
1483 {
1484 if (cmd_range_match (dst, src))
1485 return dst;
1486 else
1487 return NULL;
1488 }
1489
paul22e0a9e2003-07-11 17:55:46 +00001490#ifdef HAVE_IPV6
paul718e3742002-12-13 20:15:29 +00001491 if (CMD_IPV6 (dst))
1492 {
1493 if (cmd_ipv6_match (src))
1494 return dst;
1495 else
1496 return NULL;
1497 }
1498
1499 if (CMD_IPV6_PREFIX (dst))
1500 {
1501 if (cmd_ipv6_prefix_match (src))
1502 return dst;
1503 else
1504 return NULL;
1505 }
paul22e0a9e2003-07-11 17:55:46 +00001506#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +00001507
1508 if (CMD_IPV4 (dst))
1509 {
1510 if (cmd_ipv4_match (src))
1511 return dst;
1512 else
1513 return NULL;
1514 }
1515
1516 if (CMD_IPV4_PREFIX (dst))
1517 {
1518 if (cmd_ipv4_prefix_match (src))
1519 return dst;
1520 else
1521 return NULL;
1522 }
1523
1524 /* Optional or variable commands always match on '?' */
1525 if (CMD_OPTION (dst) || CMD_VARIABLE (dst))
1526 return dst;
1527
1528 /* In case of 'command \t', given src is NULL string. */
1529 if (src == NULL)
1530 return dst;
1531
1532 if (strncmp (src, dst, strlen (src)) == 0)
1533 return dst;
1534 else
1535 return NULL;
1536}
1537
1538/* Check same string element existence. If it isn't there return
1539 1. */
ajs274a4a42004-12-07 15:39:31 +00001540static int
hasso8c328f12004-10-05 21:01:23 +00001541cmd_unique_string (vector v, const char *str)
paul718e3742002-12-13 20:15:29 +00001542{
hasso8c328f12004-10-05 21:01:23 +00001543 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001544 char *match;
1545
paul55468c82005-03-14 20:19:01 +00001546 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001547 if ((match = vector_slot (v, i)) != NULL)
1548 if (strcmp (match, str) == 0)
1549 return 0;
1550 return 1;
1551}
1552
1553/* Compare string to description vector. If there is same string
1554 return 1 else return 0. */
ajs274a4a42004-12-07 15:39:31 +00001555static int
hasso8c328f12004-10-05 21:01:23 +00001556desc_unique_string (vector v, const char *str)
paul718e3742002-12-13 20:15:29 +00001557{
hasso8c328f12004-10-05 21:01:23 +00001558 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001559 struct desc *desc;
1560
paul55468c82005-03-14 20:19:01 +00001561 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001562 if ((desc = vector_slot (v, i)) != NULL)
1563 if (strcmp (desc->cmd, str) == 0)
1564 return 1;
1565 return 0;
1566}
1567
ajs274a4a42004-12-07 15:39:31 +00001568static int
paulb92938a2002-12-13 21:20:42 +00001569cmd_try_do_shortcut (enum node_type node, char* first_word) {
1570 if ( first_word != NULL &&
1571 node != AUTH_NODE &&
1572 node != VIEW_NODE &&
1573 node != AUTH_ENABLE_NODE &&
1574 node != ENABLE_NODE &&
Paul Jakma62687ff2008-08-23 14:27:06 +01001575 node != RESTRICTED_NODE &&
paulb92938a2002-12-13 21:20:42 +00001576 0 == strcmp( "do", first_word ) )
1577 return 1;
1578 return 0;
1579}
1580
paul718e3742002-12-13 20:15:29 +00001581/* '?' describe command support. */
ajs274a4a42004-12-07 15:39:31 +00001582static vector
paulb92938a2002-12-13 21:20:42 +00001583cmd_describe_command_real (vector vline, struct vty *vty, int *status)
paul718e3742002-12-13 20:15:29 +00001584{
paulb8961472005-03-14 17:35:52 +00001585 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001586 vector cmd_vector;
1587#define INIT_MATCHVEC_SIZE 10
1588 vector matchvec;
1589 struct cmd_element *cmd_element;
paulb8961472005-03-14 17:35:52 +00001590 unsigned int index;
paul54aba542003-08-21 20:28:24 +00001591 int ret;
1592 enum match_type match;
1593 char *command;
paul718e3742002-12-13 20:15:29 +00001594
1595 /* Set index. */
paul55468c82005-03-14 20:19:01 +00001596 if (vector_active (vline) == 0)
paulb8961472005-03-14 17:35:52 +00001597 {
1598 *status = CMD_ERR_NO_MATCH;
1599 return NULL;
1600 }
1601 else
paul55468c82005-03-14 20:19:01 +00001602 index = vector_active (vline) - 1;
paul909a2152005-03-14 17:41:45 +00001603
paul718e3742002-12-13 20:15:29 +00001604 /* Make copy vector of current node's command vector. */
1605 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1606
1607 /* Prepare match vector */
1608 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1609
1610 /* Filter commands. */
paul54aba542003-08-21 20:28:24 +00001611 /* Only words precedes current word will be checked in this loop. */
paul718e3742002-12-13 20:15:29 +00001612 for (i = 0; i < index; i++)
paulb8961472005-03-14 17:35:52 +00001613 if ((command = vector_slot (vline, i)))
paul909a2152005-03-14 17:41:45 +00001614 {
1615 match = cmd_filter_by_completion (command, cmd_vector, i);
1616
1617 if (match == vararg_match)
1618 {
1619 struct cmd_element *cmd_element;
1620 vector descvec;
1621 unsigned int j, k;
paul718e3742002-12-13 20:15:29 +00001622
paul55468c82005-03-14 20:19:01 +00001623 for (j = 0; j < vector_active (cmd_vector); j++)
paulb8961472005-03-14 17:35:52 +00001624 if ((cmd_element = vector_slot (cmd_vector, j)) != NULL
paul55468c82005-03-14 20:19:01 +00001625 && (vector_active (cmd_element->strvec)))
paul909a2152005-03-14 17:41:45 +00001626 {
1627 descvec = vector_slot (cmd_element->strvec,
paul55468c82005-03-14 20:19:01 +00001628 vector_active (cmd_element->strvec) - 1);
1629 for (k = 0; k < vector_active (descvec); k++)
paul909a2152005-03-14 17:41:45 +00001630 {
1631 struct desc *desc = vector_slot (descvec, k);
1632 vector_set (matchvec, desc);
1633 }
1634 }
1635
1636 vector_set (matchvec, &desc_cr);
1637 vector_free (cmd_vector);
paul718e3742002-12-13 20:15:29 +00001638
paul909a2152005-03-14 17:41:45 +00001639 return matchvec;
1640 }
paul718e3742002-12-13 20:15:29 +00001641
paul909a2152005-03-14 17:41:45 +00001642 if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
1643 {
1644 vector_free (cmd_vector);
Paul Jakmae5cd7062006-06-15 12:25:55 +00001645 vector_free (matchvec);
paul909a2152005-03-14 17:41:45 +00001646 *status = CMD_ERR_AMBIGUOUS;
1647 return NULL;
1648 }
1649 else if (ret == 2)
1650 {
1651 vector_free (cmd_vector);
Paul Jakmae5cd7062006-06-15 12:25:55 +00001652 vector_free (matchvec);
paul909a2152005-03-14 17:41:45 +00001653 *status = CMD_ERR_NO_MATCH;
1654 return NULL;
1655 }
1656 }
paul718e3742002-12-13 20:15:29 +00001657
1658 /* Prepare match vector */
1659 /* matchvec = vector_init (INIT_MATCHVEC_SIZE); */
1660
paul54aba542003-08-21 20:28:24 +00001661 /* Make sure that cmd_vector is filtered based on current word */
1662 command = vector_slot (vline, index);
1663 if (command)
1664 match = cmd_filter_by_completion (command, cmd_vector, index);
1665
paul718e3742002-12-13 20:15:29 +00001666 /* Make description vector. */
paul55468c82005-03-14 20:19:01 +00001667 for (i = 0; i < vector_active (cmd_vector); i++)
paul718e3742002-12-13 20:15:29 +00001668 if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
1669 {
paul718e3742002-12-13 20:15:29 +00001670 vector strvec = cmd_element->strvec;
1671
paul55468c82005-03-14 20:19:01 +00001672 /* if command is NULL, index may be equal to vector_active */
1673 if (command && index >= vector_active (strvec))
paul718e3742002-12-13 20:15:29 +00001674 vector_slot (cmd_vector, i) = NULL;
1675 else
1676 {
paul54aba542003-08-21 20:28:24 +00001677 /* Check if command is completed. */
paul55468c82005-03-14 20:19:01 +00001678 if (command == NULL && index == vector_active (strvec))
paul718e3742002-12-13 20:15:29 +00001679 {
Chris Caputo228da422009-07-18 05:44:03 +00001680 if (!desc_unique_string (matchvec, command_cr))
paul718e3742002-12-13 20:15:29 +00001681 vector_set (matchvec, &desc_cr);
1682 }
1683 else
1684 {
hasso8c328f12004-10-05 21:01:23 +00001685 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001686 vector descvec = vector_slot (strvec, index);
1687 struct desc *desc;
1688
paul55468c82005-03-14 20:19:01 +00001689 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001690 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001691 {
Chris Caputo228da422009-07-18 05:44:03 +00001692 const char *string;
1693
paul909a2152005-03-14 17:41:45 +00001694 string = cmd_entry_function_desc (command, desc->cmd);
1695 if (string)
1696 {
1697 /* Uniqueness check */
1698 if (!desc_unique_string (matchvec, string))
1699 vector_set (matchvec, desc);
1700 }
1701 }
paul718e3742002-12-13 20:15:29 +00001702 }
1703 }
1704 }
1705 vector_free (cmd_vector);
1706
1707 if (vector_slot (matchvec, 0) == NULL)
1708 {
1709 vector_free (matchvec);
paul909a2152005-03-14 17:41:45 +00001710 *status = CMD_ERR_NO_MATCH;
Paul Jakma5fc60512006-05-12 23:24:09 +00001711 return NULL;
paul718e3742002-12-13 20:15:29 +00001712 }
paul718e3742002-12-13 20:15:29 +00001713
Paul Jakma5fc60512006-05-12 23:24:09 +00001714 *status = CMD_SUCCESS;
paul718e3742002-12-13 20:15:29 +00001715 return matchvec;
1716}
1717
paulb92938a2002-12-13 21:20:42 +00001718vector
1719cmd_describe_command (vector vline, struct vty *vty, int *status)
1720{
1721 vector ret;
1722
1723 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1724 {
1725 enum node_type onode;
1726 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00001727 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00001728
1729 onode = vty->node;
1730 vty->node = ENABLE_NODE;
1731 /* We can try it on enable node, cos' the vty is authenticated */
1732
1733 shifted_vline = vector_init (vector_count(vline));
1734 /* use memcpy? */
paul55468c82005-03-14 20:19:01 +00001735 for (index = 1; index < vector_active (vline); index++)
paulb92938a2002-12-13 21:20:42 +00001736 {
1737 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1738 }
1739
1740 ret = cmd_describe_command_real (shifted_vline, vty, status);
1741
1742 vector_free(shifted_vline);
1743 vty->node = onode;
1744 return ret;
1745 }
1746
1747
1748 return cmd_describe_command_real (vline, vty, status);
1749}
1750
1751
paul718e3742002-12-13 20:15:29 +00001752/* Check LCD of matched command. */
ajs274a4a42004-12-07 15:39:31 +00001753static int
paul718e3742002-12-13 20:15:29 +00001754cmd_lcd (char **matched)
1755{
1756 int i;
1757 int j;
1758 int lcd = -1;
1759 char *s1, *s2;
1760 char c1, c2;
1761
1762 if (matched[0] == NULL || matched[1] == NULL)
1763 return 0;
1764
1765 for (i = 1; matched[i] != NULL; i++)
1766 {
1767 s1 = matched[i - 1];
1768 s2 = matched[i];
1769
1770 for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
1771 if (c1 != c2)
1772 break;
1773
1774 if (lcd < 0)
1775 lcd = j;
1776 else
1777 {
1778 if (lcd > j)
1779 lcd = j;
1780 }
1781 }
1782 return lcd;
1783}
1784
1785/* Command line completion support. */
ajs274a4a42004-12-07 15:39:31 +00001786static char **
paulb92938a2002-12-13 21:20:42 +00001787cmd_complete_command_real (vector vline, struct vty *vty, int *status)
paul718e3742002-12-13 20:15:29 +00001788{
paulb8961472005-03-14 17:35:52 +00001789 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001790 vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1791#define INIT_MATCHVEC_SIZE 10
1792 vector matchvec;
1793 struct cmd_element *cmd_element;
paulb8961472005-03-14 17:35:52 +00001794 unsigned int index;
paul718e3742002-12-13 20:15:29 +00001795 char **match_str;
1796 struct desc *desc;
1797 vector descvec;
1798 char *command;
1799 int lcd;
1800
paul55468c82005-03-14 20:19:01 +00001801 if (vector_active (vline) == 0)
paulb8961472005-03-14 17:35:52 +00001802 {
Paul Jakmad2519962006-05-12 23:19:37 +00001803 vector_free (cmd_vector);
paulb8961472005-03-14 17:35:52 +00001804 *status = CMD_ERR_NO_MATCH;
1805 return NULL;
1806 }
1807 else
paul55468c82005-03-14 20:19:01 +00001808 index = vector_active (vline) - 1;
paulb8961472005-03-14 17:35:52 +00001809
paul718e3742002-12-13 20:15:29 +00001810 /* First, filter by preceeding command string */
1811 for (i = 0; i < index; i++)
paulb8961472005-03-14 17:35:52 +00001812 if ((command = vector_slot (vline, i)))
paul909a2152005-03-14 17:41:45 +00001813 {
1814 enum match_type match;
1815 int ret;
paul718e3742002-12-13 20:15:29 +00001816
paul909a2152005-03-14 17:41:45 +00001817 /* First try completion match, if there is exactly match return 1 */
1818 match = cmd_filter_by_completion (command, cmd_vector, i);
paul718e3742002-12-13 20:15:29 +00001819
paul909a2152005-03-14 17:41:45 +00001820 /* If there is exact match then filter ambiguous match else check
1821 ambiguousness. */
1822 if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
1823 {
1824 vector_free (cmd_vector);
1825 *status = CMD_ERR_AMBIGUOUS;
1826 return NULL;
1827 }
1828 /*
1829 else if (ret == 2)
1830 {
1831 vector_free (cmd_vector);
1832 *status = CMD_ERR_NO_MATCH;
1833 return NULL;
1834 }
1835 */
1836 }
1837
paul718e3742002-12-13 20:15:29 +00001838 /* Prepare match vector. */
1839 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1840
1841 /* Now we got into completion */
paul55468c82005-03-14 20:19:01 +00001842 for (i = 0; i < vector_active (cmd_vector); i++)
paulb8961472005-03-14 17:35:52 +00001843 if ((cmd_element = vector_slot (cmd_vector, i)))
paul718e3742002-12-13 20:15:29 +00001844 {
hasso8c328f12004-10-05 21:01:23 +00001845 const char *string;
paul718e3742002-12-13 20:15:29 +00001846 vector strvec = cmd_element->strvec;
paul909a2152005-03-14 17:41:45 +00001847
paul718e3742002-12-13 20:15:29 +00001848 /* Check field length */
paul55468c82005-03-14 20:19:01 +00001849 if (index >= vector_active (strvec))
paul718e3742002-12-13 20:15:29 +00001850 vector_slot (cmd_vector, i) = NULL;
paul909a2152005-03-14 17:41:45 +00001851 else
paul718e3742002-12-13 20:15:29 +00001852 {
hasso8c328f12004-10-05 21:01:23 +00001853 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001854
1855 descvec = vector_slot (strvec, index);
paul55468c82005-03-14 20:19:01 +00001856 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001857 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001858 {
paulb8961472005-03-14 17:35:52 +00001859 if ((string =
1860 cmd_entry_function (vector_slot (vline, index),
paul909a2152005-03-14 17:41:45 +00001861 desc->cmd)))
1862 if (cmd_unique_string (matchvec, string))
1863 vector_set (matchvec, XSTRDUP (MTYPE_TMP, string));
1864 }
paul718e3742002-12-13 20:15:29 +00001865 }
1866 }
1867
1868 /* We don't need cmd_vector any more. */
1869 vector_free (cmd_vector);
1870
1871 /* No matched command */
1872 if (vector_slot (matchvec, 0) == NULL)
1873 {
1874 vector_free (matchvec);
1875
1876 /* In case of 'command \t' pattern. Do you need '?' command at
1877 the end of the line. */
1878 if (vector_slot (vline, index) == '\0')
1879 *status = CMD_ERR_NOTHING_TODO;
1880 else
1881 *status = CMD_ERR_NO_MATCH;
1882 return NULL;
1883 }
1884
1885 /* Only one matched */
1886 if (vector_slot (matchvec, 1) == NULL)
1887 {
1888 match_str = (char **) matchvec->index;
1889 vector_only_wrapper_free (matchvec);
1890 *status = CMD_COMPLETE_FULL_MATCH;
1891 return match_str;
1892 }
1893 /* Make it sure last element is NULL. */
1894 vector_set (matchvec, NULL);
1895
1896 /* Check LCD of matched strings. */
1897 if (vector_slot (vline, index) != NULL)
1898 {
1899 lcd = cmd_lcd ((char **) matchvec->index);
1900
1901 if (lcd)
1902 {
1903 int len = strlen (vector_slot (vline, index));
paul909a2152005-03-14 17:41:45 +00001904
paul718e3742002-12-13 20:15:29 +00001905 if (len < lcd)
1906 {
1907 char *lcdstr;
paul909a2152005-03-14 17:41:45 +00001908
paul05865c92005-10-26 05:49:54 +00001909 lcdstr = XMALLOC (MTYPE_STRVEC, lcd + 1);
paul718e3742002-12-13 20:15:29 +00001910 memcpy (lcdstr, matchvec->index[0], lcd);
1911 lcdstr[lcd] = '\0';
1912
1913 /* match_str = (char **) &lcdstr; */
1914
1915 /* Free matchvec. */
paul55468c82005-03-14 20:19:01 +00001916 for (i = 0; i < vector_active (matchvec); i++)
paul718e3742002-12-13 20:15:29 +00001917 {
1918 if (vector_slot (matchvec, i))
paul05865c92005-10-26 05:49:54 +00001919 XFREE (MTYPE_STRVEC, vector_slot (matchvec, i));
paul718e3742002-12-13 20:15:29 +00001920 }
1921 vector_free (matchvec);
1922
paul909a2152005-03-14 17:41:45 +00001923 /* Make new matchvec. */
paul718e3742002-12-13 20:15:29 +00001924 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1925 vector_set (matchvec, lcdstr);
1926 match_str = (char **) matchvec->index;
1927 vector_only_wrapper_free (matchvec);
1928
1929 *status = CMD_COMPLETE_MATCH;
1930 return match_str;
1931 }
1932 }
1933 }
1934
1935 match_str = (char **) matchvec->index;
1936 vector_only_wrapper_free (matchvec);
1937 *status = CMD_COMPLETE_LIST_MATCH;
1938 return match_str;
1939}
1940
paulb92938a2002-12-13 21:20:42 +00001941char **
paul9ab68122003-01-18 01:16:20 +00001942cmd_complete_command (vector vline, struct vty *vty, int *status)
paulb92938a2002-12-13 21:20:42 +00001943{
1944 char **ret;
1945
1946 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1947 {
1948 enum node_type onode;
1949 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00001950 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00001951
1952 onode = vty->node;
1953 vty->node = ENABLE_NODE;
1954 /* We can try it on enable node, cos' the vty is authenticated */
1955
1956 shifted_vline = vector_init (vector_count(vline));
1957 /* use memcpy? */
paul55468c82005-03-14 20:19:01 +00001958 for (index = 1; index < vector_active (vline); index++)
paulb92938a2002-12-13 21:20:42 +00001959 {
1960 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1961 }
1962
1963 ret = cmd_complete_command_real (shifted_vline, vty, status);
1964
1965 vector_free(shifted_vline);
1966 vty->node = onode;
1967 return ret;
1968 }
1969
1970
1971 return cmd_complete_command_real (vline, vty, status);
1972}
1973
1974/* return parent node */
1975/* MUST eventually converge on CONFIG_NODE */
hasso13bfca72005-01-23 21:42:25 +00001976enum node_type
ajs274a4a42004-12-07 15:39:31 +00001977node_parent ( enum node_type node )
paulb92938a2002-12-13 21:20:42 +00001978{
1979 enum node_type ret;
1980
paul9ab68122003-01-18 01:16:20 +00001981 assert (node > CONFIG_NODE);
1982
1983 switch (node)
1984 {
1985 case BGP_VPNV4_NODE:
1986 case BGP_IPV4_NODE:
1987 case BGP_IPV4M_NODE:
1988 case BGP_IPV6_NODE:
paul1e836592005-08-22 22:39:56 +00001989 case BGP_IPV6M_NODE:
paul9ab68122003-01-18 01:16:20 +00001990 ret = BGP_NODE;
1991 break;
1992 case KEYCHAIN_KEY_NODE:
1993 ret = KEYCHAIN_NODE;
1994 break;
1995 default:
1996 ret = CONFIG_NODE;
paulb92938a2002-12-13 21:20:42 +00001997 }
1998
1999 return ret;
2000}
2001
paul718e3742002-12-13 20:15:29 +00002002/* Execute command by argument vline vector. */
ajs274a4a42004-12-07 15:39:31 +00002003static int
paulb8961472005-03-14 17:35:52 +00002004cmd_execute_command_real (vector vline, struct vty *vty,
2005 struct cmd_element **cmd)
paul718e3742002-12-13 20:15:29 +00002006{
hasso8c328f12004-10-05 21:01:23 +00002007 unsigned int i;
2008 unsigned int index;
paul718e3742002-12-13 20:15:29 +00002009 vector cmd_vector;
2010 struct cmd_element *cmd_element;
2011 struct cmd_element *matched_element;
2012 unsigned int matched_count, incomplete_count;
2013 int argc;
paul9035efa2004-10-10 11:56:56 +00002014 const char *argv[CMD_ARGC_MAX];
paul718e3742002-12-13 20:15:29 +00002015 enum match_type match = 0;
2016 int varflag;
2017 char *command;
2018
2019 /* Make copy of command elements. */
2020 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2021
paul55468c82005-03-14 20:19:01 +00002022 for (index = 0; index < vector_active (vline); index++)
paulb8961472005-03-14 17:35:52 +00002023 if ((command = vector_slot (vline, index)))
paul909a2152005-03-14 17:41:45 +00002024 {
2025 int ret;
paul718e3742002-12-13 20:15:29 +00002026
paul909a2152005-03-14 17:41:45 +00002027 match = cmd_filter_by_completion (command, cmd_vector, index);
paul718e3742002-12-13 20:15:29 +00002028
paul909a2152005-03-14 17:41:45 +00002029 if (match == vararg_match)
2030 break;
2031
2032 ret = is_cmd_ambiguous (command, cmd_vector, index, match);
paul718e3742002-12-13 20:15:29 +00002033
paul909a2152005-03-14 17:41:45 +00002034 if (ret == 1)
2035 {
2036 vector_free (cmd_vector);
2037 return CMD_ERR_AMBIGUOUS;
2038 }
2039 else if (ret == 2)
2040 {
2041 vector_free (cmd_vector);
2042 return CMD_ERR_NO_MATCH;
2043 }
2044 }
paul718e3742002-12-13 20:15:29 +00002045
2046 /* Check matched count. */
2047 matched_element = NULL;
2048 matched_count = 0;
2049 incomplete_count = 0;
2050
paul55468c82005-03-14 20:19:01 +00002051 for (i = 0; i < vector_active (cmd_vector); i++)
paulb8961472005-03-14 17:35:52 +00002052 if ((cmd_element = vector_slot (cmd_vector, i)))
paul718e3742002-12-13 20:15:29 +00002053 {
paul718e3742002-12-13 20:15:29 +00002054 if (match == vararg_match || index >= cmd_element->cmdsize)
2055 {
2056 matched_element = cmd_element;
2057#if 0
2058 printf ("DEBUG: %s\n", cmd_element->string);
2059#endif
2060 matched_count++;
2061 }
2062 else
2063 {
2064 incomplete_count++;
2065 }
2066 }
paul909a2152005-03-14 17:41:45 +00002067
paul718e3742002-12-13 20:15:29 +00002068 /* Finish of using cmd_vector. */
2069 vector_free (cmd_vector);
2070
paul909a2152005-03-14 17:41:45 +00002071 /* To execute command, matched_count must be 1. */
2072 if (matched_count == 0)
paul718e3742002-12-13 20:15:29 +00002073 {
2074 if (incomplete_count)
2075 return CMD_ERR_INCOMPLETE;
2076 else
2077 return CMD_ERR_NO_MATCH;
2078 }
2079
paul909a2152005-03-14 17:41:45 +00002080 if (matched_count > 1)
paul718e3742002-12-13 20:15:29 +00002081 return CMD_ERR_AMBIGUOUS;
2082
2083 /* Argument treatment */
2084 varflag = 0;
2085 argc = 0;
2086
paul55468c82005-03-14 20:19:01 +00002087 for (i = 0; i < vector_active (vline); i++)
paul718e3742002-12-13 20:15:29 +00002088 {
2089 if (varflag)
2090 argv[argc++] = vector_slot (vline, i);
2091 else
paul909a2152005-03-14 17:41:45 +00002092 {
paul718e3742002-12-13 20:15:29 +00002093 vector descvec = vector_slot (matched_element->strvec, i);
2094
paul55468c82005-03-14 20:19:01 +00002095 if (vector_active (descvec) == 1)
paul718e3742002-12-13 20:15:29 +00002096 {
2097 struct desc *desc = vector_slot (descvec, 0);
paul718e3742002-12-13 20:15:29 +00002098
hasso8c328f12004-10-05 21:01:23 +00002099 if (CMD_VARARG (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002100 varflag = 1;
2101
hasso8c328f12004-10-05 21:01:23 +00002102 if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002103 argv[argc++] = vector_slot (vline, i);
2104 }
2105 else
2106 argv[argc++] = vector_slot (vline, i);
2107 }
2108
2109 if (argc >= CMD_ARGC_MAX)
2110 return CMD_ERR_EXEED_ARGC_MAX;
2111 }
2112
2113 /* For vtysh execution. */
2114 if (cmd)
2115 *cmd = matched_element;
2116
2117 if (matched_element->daemon)
2118 return CMD_SUCCESS_DAEMON;
2119
2120 /* Execute matched command. */
2121 return (*matched_element->func) (matched_element, vty, argc, argv);
2122}
2123
paulb92938a2002-12-13 21:20:42 +00002124int
hasso87d683b2005-01-16 23:31:54 +00002125cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,
2126 int vtysh) {
paul9ab68122003-01-18 01:16:20 +00002127 int ret, saved_ret, tried = 0;
2128 enum node_type onode, try_node;
2129
2130 onode = try_node = vty->node;
paulb92938a2002-12-13 21:20:42 +00002131
2132 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
2133 {
2134 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00002135 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00002136
2137 vty->node = ENABLE_NODE;
2138 /* We can try it on enable node, cos' the vty is authenticated */
2139
2140 shifted_vline = vector_init (vector_count(vline));
2141 /* use memcpy? */
paul55468c82005-03-14 20:19:01 +00002142 for (index = 1; index < vector_active (vline); index++)
paulb92938a2002-12-13 21:20:42 +00002143 {
2144 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
2145 }
2146
2147 ret = cmd_execute_command_real (shifted_vline, vty, cmd);
2148
2149 vector_free(shifted_vline);
2150 vty->node = onode;
2151 return ret;
2152 }
2153
2154
paul9ab68122003-01-18 01:16:20 +00002155 saved_ret = ret = cmd_execute_command_real (vline, vty, cmd);
paulb92938a2002-12-13 21:20:42 +00002156
hasso87d683b2005-01-16 23:31:54 +00002157 if (vtysh)
2158 return saved_ret;
2159
paulb92938a2002-12-13 21:20:42 +00002160 /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
paul9ab68122003-01-18 01:16:20 +00002161 while ( ret != CMD_SUCCESS && ret != CMD_WARNING
paulb92938a2002-12-13 21:20:42 +00002162 && vty->node > CONFIG_NODE )
2163 {
paul9ab68122003-01-18 01:16:20 +00002164 try_node = node_parent(try_node);
2165 vty->node = try_node;
paulb92938a2002-12-13 21:20:42 +00002166 ret = cmd_execute_command_real (vline, vty, cmd);
paul9ab68122003-01-18 01:16:20 +00002167 tried = 1;
2168 if (ret == CMD_SUCCESS || ret == CMD_WARNING)
paulb92938a2002-12-13 21:20:42 +00002169 {
paul9ab68122003-01-18 01:16:20 +00002170 /* succesfull command, leave the node as is */
paulb92938a2002-12-13 21:20:42 +00002171 return ret;
2172 }
paulb92938a2002-12-13 21:20:42 +00002173 }
paul9ab68122003-01-18 01:16:20 +00002174 /* no command succeeded, reset the vty to the original node and
2175 return the error for this node */
2176 if ( tried )
2177 vty->node = onode;
2178 return saved_ret;
pauleda031f2003-01-18 00:39:19 +00002179}
2180
paul718e3742002-12-13 20:15:29 +00002181/* Execute command by argument readline. */
2182int
paul909a2152005-03-14 17:41:45 +00002183cmd_execute_command_strict (vector vline, struct vty *vty,
paul718e3742002-12-13 20:15:29 +00002184 struct cmd_element **cmd)
2185{
hasso8c328f12004-10-05 21:01:23 +00002186 unsigned int i;
2187 unsigned int index;
paul718e3742002-12-13 20:15:29 +00002188 vector cmd_vector;
2189 struct cmd_element *cmd_element;
2190 struct cmd_element *matched_element;
2191 unsigned int matched_count, incomplete_count;
2192 int argc;
paul9035efa2004-10-10 11:56:56 +00002193 const char *argv[CMD_ARGC_MAX];
paul718e3742002-12-13 20:15:29 +00002194 int varflag;
2195 enum match_type match = 0;
2196 char *command;
2197
2198 /* Make copy of command element */
2199 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2200
paul55468c82005-03-14 20:19:01 +00002201 for (index = 0; index < vector_active (vline); index++)
paulb8961472005-03-14 17:35:52 +00002202 if ((command = vector_slot (vline, index)))
paul909a2152005-03-14 17:41:45 +00002203 {
2204 int ret;
2205
2206 match = cmd_filter_by_string (vector_slot (vline, index),
2207 cmd_vector, index);
paul718e3742002-12-13 20:15:29 +00002208
paul909a2152005-03-14 17:41:45 +00002209 /* If command meets '.VARARG' then finish matching. */
2210 if (match == vararg_match)
2211 break;
2212
2213 ret = is_cmd_ambiguous (command, cmd_vector, index, match);
2214 if (ret == 1)
2215 {
2216 vector_free (cmd_vector);
2217 return CMD_ERR_AMBIGUOUS;
2218 }
2219 if (ret == 2)
2220 {
2221 vector_free (cmd_vector);
2222 return CMD_ERR_NO_MATCH;
2223 }
2224 }
paul718e3742002-12-13 20:15:29 +00002225
2226 /* Check matched count. */
2227 matched_element = NULL;
2228 matched_count = 0;
2229 incomplete_count = 0;
paul55468c82005-03-14 20:19:01 +00002230 for (i = 0; i < vector_active (cmd_vector); i++)
paul909a2152005-03-14 17:41:45 +00002231 if (vector_slot (cmd_vector, i) != NULL)
paul718e3742002-12-13 20:15:29 +00002232 {
paul909a2152005-03-14 17:41:45 +00002233 cmd_element = vector_slot (cmd_vector, i);
paul718e3742002-12-13 20:15:29 +00002234
2235 if (match == vararg_match || index >= cmd_element->cmdsize)
2236 {
2237 matched_element = cmd_element;
2238 matched_count++;
2239 }
2240 else
2241 incomplete_count++;
2242 }
paul909a2152005-03-14 17:41:45 +00002243
paul718e3742002-12-13 20:15:29 +00002244 /* Finish of using cmd_vector. */
2245 vector_free (cmd_vector);
2246
paul909a2152005-03-14 17:41:45 +00002247 /* To execute command, matched_count must be 1. */
2248 if (matched_count == 0)
paul718e3742002-12-13 20:15:29 +00002249 {
2250 if (incomplete_count)
2251 return CMD_ERR_INCOMPLETE;
2252 else
2253 return CMD_ERR_NO_MATCH;
2254 }
2255
paul909a2152005-03-14 17:41:45 +00002256 if (matched_count > 1)
paul718e3742002-12-13 20:15:29 +00002257 return CMD_ERR_AMBIGUOUS;
2258
2259 /* Argument treatment */
2260 varflag = 0;
2261 argc = 0;
2262
paul55468c82005-03-14 20:19:01 +00002263 for (i = 0; i < vector_active (vline); i++)
paul718e3742002-12-13 20:15:29 +00002264 {
2265 if (varflag)
2266 argv[argc++] = vector_slot (vline, i);
2267 else
paul909a2152005-03-14 17:41:45 +00002268 {
paul718e3742002-12-13 20:15:29 +00002269 vector descvec = vector_slot (matched_element->strvec, i);
2270
paul55468c82005-03-14 20:19:01 +00002271 if (vector_active (descvec) == 1)
paul718e3742002-12-13 20:15:29 +00002272 {
2273 struct desc *desc = vector_slot (descvec, 0);
paul718e3742002-12-13 20:15:29 +00002274
hasso8c328f12004-10-05 21:01:23 +00002275 if (CMD_VARARG (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002276 varflag = 1;
paul909a2152005-03-14 17:41:45 +00002277
hasso8c328f12004-10-05 21:01:23 +00002278 if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002279 argv[argc++] = vector_slot (vline, i);
2280 }
2281 else
2282 argv[argc++] = vector_slot (vline, i);
2283 }
2284
2285 if (argc >= CMD_ARGC_MAX)
2286 return CMD_ERR_EXEED_ARGC_MAX;
2287 }
2288
2289 /* For vtysh execution. */
2290 if (cmd)
2291 *cmd = matched_element;
2292
2293 if (matched_element->daemon)
2294 return CMD_SUCCESS_DAEMON;
2295
2296 /* Now execute matched command */
2297 return (*matched_element->func) (matched_element, vty, argc, argv);
2298}
2299
2300/* Configration make from file. */
2301int
2302config_from_file (struct vty *vty, FILE *fp)
2303{
2304 int ret;
2305 vector vline;
2306
2307 while (fgets (vty->buf, VTY_BUFSIZ, fp))
2308 {
2309 vline = cmd_make_strvec (vty->buf);
2310
2311 /* In case of comment line */
2312 if (vline == NULL)
2313 continue;
2314 /* Execute configuration command : this is strict match */
2315 ret = cmd_execute_command_strict (vline, vty, NULL);
2316
2317 /* Try again with setting node to CONFIG_NODE */
paulb92938a2002-12-13 21:20:42 +00002318 while (ret != CMD_SUCCESS && ret != CMD_WARNING
hassoddd85ed2004-10-13 08:18:07 +00002319 && ret != CMD_ERR_NOTHING_TODO && vty->node != CONFIG_NODE)
2320 {
paulb92938a2002-12-13 21:20:42 +00002321 vty->node = node_parent(vty->node);
hassoddd85ed2004-10-13 08:18:07 +00002322 ret = cmd_execute_command_strict (vline, vty, NULL);
2323 }
paul9ab68122003-01-18 01:16:20 +00002324
paul718e3742002-12-13 20:15:29 +00002325 cmd_free_strvec (vline);
2326
hassoddd85ed2004-10-13 08:18:07 +00002327 if (ret != CMD_SUCCESS && ret != CMD_WARNING
2328 && ret != CMD_ERR_NOTHING_TODO)
paul718e3742002-12-13 20:15:29 +00002329 return ret;
2330 }
2331 return CMD_SUCCESS;
2332}
2333
2334/* Configration from terminal */
2335DEFUN (config_terminal,
2336 config_terminal_cmd,
2337 "configure terminal",
2338 "Configuration from vty interface\n"
2339 "Configuration terminal\n")
2340{
2341 if (vty_config_lock (vty))
2342 vty->node = CONFIG_NODE;
2343 else
2344 {
2345 vty_out (vty, "VTY configuration is locked by other VTY%s", VTY_NEWLINE);
2346 return CMD_WARNING;
2347 }
2348 return CMD_SUCCESS;
2349}
2350
2351/* Enable command */
2352DEFUN (enable,
2353 config_enable_cmd,
2354 "enable",
2355 "Turn on privileged mode command\n")
2356{
2357 /* If enable password is NULL, change to ENABLE_NODE */
2358 if ((host.enable == NULL && host.enable_encrypt == NULL) ||
2359 vty->type == VTY_SHELL_SERV)
2360 vty->node = ENABLE_NODE;
2361 else
2362 vty->node = AUTH_ENABLE_NODE;
2363
2364 return CMD_SUCCESS;
2365}
2366
2367/* Disable command */
2368DEFUN (disable,
2369 config_disable_cmd,
2370 "disable",
2371 "Turn off privileged mode command\n")
2372{
2373 if (vty->node == ENABLE_NODE)
2374 vty->node = VIEW_NODE;
2375 return CMD_SUCCESS;
2376}
2377
2378/* Down vty node level. */
2379DEFUN (config_exit,
2380 config_exit_cmd,
2381 "exit",
2382 "Exit current mode and down to previous mode\n")
2383{
2384 switch (vty->node)
2385 {
2386 case VIEW_NODE:
2387 case ENABLE_NODE:
Paul Jakma62687ff2008-08-23 14:27:06 +01002388 case RESTRICTED_NODE:
paul718e3742002-12-13 20:15:29 +00002389 if (vty_shell (vty))
2390 exit (0);
2391 else
2392 vty->status = VTY_CLOSE;
2393 break;
2394 case CONFIG_NODE:
2395 vty->node = ENABLE_NODE;
2396 vty_config_unlock (vty);
2397 break;
2398 case INTERFACE_NODE:
2399 case ZEBRA_NODE:
2400 case BGP_NODE:
2401 case RIP_NODE:
2402 case RIPNG_NODE:
2403 case OSPF_NODE:
2404 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00002405 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00002406 case KEYCHAIN_NODE:
2407 case MASC_NODE:
2408 case RMAP_NODE:
2409 case VTY_NODE:
2410 vty->node = CONFIG_NODE;
2411 break;
2412 case BGP_VPNV4_NODE:
2413 case BGP_IPV4_NODE:
2414 case BGP_IPV4M_NODE:
2415 case BGP_IPV6_NODE:
paul1e836592005-08-22 22:39:56 +00002416 case BGP_IPV6M_NODE:
paul718e3742002-12-13 20:15:29 +00002417 vty->node = BGP_NODE;
2418 break;
2419 case KEYCHAIN_KEY_NODE:
2420 vty->node = KEYCHAIN_NODE;
2421 break;
2422 default:
2423 break;
2424 }
2425 return CMD_SUCCESS;
2426}
2427
2428/* quit is alias of exit. */
2429ALIAS (config_exit,
2430 config_quit_cmd,
2431 "quit",
2432 "Exit current mode and down to previous mode\n")
2433
2434/* End of configuration. */
2435DEFUN (config_end,
2436 config_end_cmd,
2437 "end",
2438 "End current mode and change to enable mode.")
2439{
2440 switch (vty->node)
2441 {
2442 case VIEW_NODE:
2443 case ENABLE_NODE:
Paul Jakma62687ff2008-08-23 14:27:06 +01002444 case RESTRICTED_NODE:
paul718e3742002-12-13 20:15:29 +00002445 /* Nothing to do. */
2446 break;
2447 case CONFIG_NODE:
2448 case INTERFACE_NODE:
2449 case ZEBRA_NODE:
2450 case RIP_NODE:
2451 case RIPNG_NODE:
2452 case BGP_NODE:
2453 case BGP_VPNV4_NODE:
2454 case BGP_IPV4_NODE:
2455 case BGP_IPV4M_NODE:
2456 case BGP_IPV6_NODE:
paul1e836592005-08-22 22:39:56 +00002457 case BGP_IPV6M_NODE:
paul718e3742002-12-13 20:15:29 +00002458 case RMAP_NODE:
2459 case OSPF_NODE:
2460 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00002461 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00002462 case KEYCHAIN_NODE:
2463 case KEYCHAIN_KEY_NODE:
2464 case MASC_NODE:
2465 case VTY_NODE:
2466 vty_config_unlock (vty);
2467 vty->node = ENABLE_NODE;
2468 break;
2469 default:
2470 break;
2471 }
2472 return CMD_SUCCESS;
2473}
2474
2475/* Show version. */
2476DEFUN (show_version,
2477 show_version_cmd,
2478 "show version",
2479 SHOW_STR
2480 "Displays zebra version\n")
2481{
hasso12f6ea22005-03-07 08:35:39 +00002482 vty_out (vty, "Quagga %s (%s).%s", QUAGGA_VERSION, host.name?host.name:"",
2483 VTY_NEWLINE);
hasso6590f2c2004-10-19 20:40:08 +00002484 vty_out (vty, "%s%s", QUAGGA_COPYRIGHT, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00002485
2486 return CMD_SUCCESS;
2487}
2488
2489/* Help display function for all node. */
2490DEFUN (config_help,
2491 config_help_cmd,
2492 "help",
2493 "Description of the interactive help system\n")
2494{
2495 vty_out (vty,
hasso6590f2c2004-10-19 20:40:08 +00002496 "Quagga VTY provides advanced help feature. When you need help,%s\
paul718e3742002-12-13 20:15:29 +00002497anytime at the command line please press '?'.%s\
2498%s\
2499If nothing matches, the help list will be empty and you must backup%s\
2500 until entering a '?' shows the available options.%s\
2501Two styles of help are provided:%s\
25021. Full help is available when you are ready to enter a%s\
2503command argument (e.g. 'show ?') and describes each possible%s\
2504argument.%s\
25052. Partial help is provided when an abbreviated argument is entered%s\
2506 and you want to know what arguments match the input%s\
2507 (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2508 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2509 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
2510 return CMD_SUCCESS;
2511}
2512
2513/* Help display function for all node. */
2514DEFUN (config_list,
2515 config_list_cmd,
2516 "list",
2517 "Print command list\n")
2518{
hasso8c328f12004-10-05 21:01:23 +00002519 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002520 struct cmd_node *cnode = vector_slot (cmdvec, vty->node);
2521 struct cmd_element *cmd;
2522
paul55468c82005-03-14 20:19:01 +00002523 for (i = 0; i < vector_active (cnode->cmd_vector); i++)
paul4275b1d2005-03-09 13:42:23 +00002524 if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL
2525 && !(cmd->attr == CMD_ATTR_DEPRECATED
2526 || cmd->attr == CMD_ATTR_HIDDEN))
paul718e3742002-12-13 20:15:29 +00002527 vty_out (vty, " %s%s", cmd->string,
2528 VTY_NEWLINE);
2529 return CMD_SUCCESS;
2530}
2531
2532/* Write current configuration into file. */
2533DEFUN (config_write_file,
2534 config_write_file_cmd,
2535 "write file",
2536 "Write running configuration to memory, network, or terminal\n"
2537 "Write to configuration file\n")
2538{
hasso8c328f12004-10-05 21:01:23 +00002539 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002540 int fd;
2541 struct cmd_node *node;
2542 char *config_file;
2543 char *config_file_tmp = NULL;
2544 char *config_file_sav = NULL;
paul05865c92005-10-26 05:49:54 +00002545 int ret = CMD_WARNING;
paul718e3742002-12-13 20:15:29 +00002546 struct vty *file_vty;
2547
2548 /* Check and see if we are operating under vtysh configuration */
2549 if (host.config == NULL)
2550 {
2551 vty_out (vty, "Can't save to configuration file, using vtysh.%s",
2552 VTY_NEWLINE);
2553 return CMD_WARNING;
2554 }
2555
2556 /* Get filename. */
2557 config_file = host.config;
2558
paul05865c92005-10-26 05:49:54 +00002559 config_file_sav =
2560 XMALLOC (MTYPE_TMP, strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
paul718e3742002-12-13 20:15:29 +00002561 strcpy (config_file_sav, config_file);
2562 strcat (config_file_sav, CONF_BACKUP_EXT);
2563
2564
paul05865c92005-10-26 05:49:54 +00002565 config_file_tmp = XMALLOC (MTYPE_TMP, strlen (config_file) + 8);
paul718e3742002-12-13 20:15:29 +00002566 sprintf (config_file_tmp, "%s.XXXXXX", config_file);
2567
2568 /* Open file to configuration write. */
2569 fd = mkstemp (config_file_tmp);
2570 if (fd < 0)
2571 {
2572 vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
2573 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002574 goto finished;
paul718e3742002-12-13 20:15:29 +00002575 }
2576
2577 /* Make vty for configuration file. */
2578 file_vty = vty_new ();
2579 file_vty->fd = fd;
2580 file_vty->type = VTY_FILE;
2581
2582 /* Config file header print. */
2583 vty_out (file_vty, "!\n! Zebra configuration saved from vty\n! ");
2584 vty_time_print (file_vty, 1);
2585 vty_out (file_vty, "!\n");
2586
paul55468c82005-03-14 20:19:01 +00002587 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +00002588 if ((node = vector_slot (cmdvec, i)) && node->func)
2589 {
2590 if ((*node->func) (file_vty))
2591 vty_out (file_vty, "!\n");
2592 }
2593 vty_close (file_vty);
2594
2595 if (unlink (config_file_sav) != 0)
2596 if (errno != ENOENT)
2597 {
2598 vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
2599 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002600 goto finished;
paul718e3742002-12-13 20:15:29 +00002601 }
2602 if (link (config_file, config_file_sav) != 0)
2603 {
2604 vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
2605 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002606 goto finished;
paul718e3742002-12-13 20:15:29 +00002607 }
2608 sync ();
2609 if (unlink (config_file) != 0)
2610 {
2611 vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
2612 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002613 goto finished;
paul718e3742002-12-13 20:15:29 +00002614 }
2615 if (link (config_file_tmp, config_file) != 0)
2616 {
2617 vty_out (vty, "Can't save configuration file %s.%s", config_file,
2618 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002619 goto finished;
paul718e3742002-12-13 20:15:29 +00002620 }
paul718e3742002-12-13 20:15:29 +00002621 sync ();
2622
gdtaa593d52003-12-22 20:15:53 +00002623 if (chmod (config_file, CONFIGFILE_MASK) != 0)
2624 {
2625 vty_out (vty, "Can't chmod configuration file %s: %s (%d).%s",
ajs6099b3b2004-11-20 02:06:59 +00002626 config_file, safe_strerror(errno), errno, VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002627 goto finished;
gdtaa593d52003-12-22 20:15:53 +00002628 }
2629
paul718e3742002-12-13 20:15:29 +00002630 vty_out (vty, "Configuration saved to %s%s", config_file,
2631 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002632 ret = CMD_SUCCESS;
2633
2634finished:
2635 unlink (config_file_tmp);
2636 XFREE (MTYPE_TMP, config_file_tmp);
2637 XFREE (MTYPE_TMP, config_file_sav);
2638 return ret;
paul718e3742002-12-13 20:15:29 +00002639}
2640
2641ALIAS (config_write_file,
2642 config_write_cmd,
2643 "write",
2644 "Write running configuration to memory, network, or terminal\n")
2645
2646ALIAS (config_write_file,
2647 config_write_memory_cmd,
2648 "write memory",
2649 "Write running configuration to memory, network, or terminal\n"
2650 "Write configuration to the file (same as write file)\n")
2651
2652ALIAS (config_write_file,
2653 copy_runningconfig_startupconfig_cmd,
2654 "copy running-config startup-config",
2655 "Copy configuration\n"
2656 "Copy running config to... \n"
2657 "Copy running config to startup config (same as write file)\n")
2658
2659/* Write current configuration into the terminal. */
2660DEFUN (config_write_terminal,
2661 config_write_terminal_cmd,
2662 "write terminal",
2663 "Write running configuration to memory, network, or terminal\n"
2664 "Write to terminal\n")
2665{
hasso8c328f12004-10-05 21:01:23 +00002666 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002667 struct cmd_node *node;
2668
2669 if (vty->type == VTY_SHELL_SERV)
2670 {
paul55468c82005-03-14 20:19:01 +00002671 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +00002672 if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
2673 {
2674 if ((*node->func) (vty))
2675 vty_out (vty, "!%s", VTY_NEWLINE);
2676 }
2677 }
2678 else
2679 {
2680 vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
2681 VTY_NEWLINE);
2682 vty_out (vty, "!%s", VTY_NEWLINE);
2683
paul55468c82005-03-14 20:19:01 +00002684 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +00002685 if ((node = vector_slot (cmdvec, i)) && node->func)
2686 {
2687 if ((*node->func) (vty))
2688 vty_out (vty, "!%s", VTY_NEWLINE);
2689 }
2690 vty_out (vty, "end%s",VTY_NEWLINE);
2691 }
2692 return CMD_SUCCESS;
2693}
2694
2695/* Write current configuration into the terminal. */
2696ALIAS (config_write_terminal,
2697 show_running_config_cmd,
2698 "show running-config",
2699 SHOW_STR
2700 "running configuration\n")
2701
2702/* Write startup configuration into the terminal. */
2703DEFUN (show_startup_config,
2704 show_startup_config_cmd,
2705 "show startup-config",
2706 SHOW_STR
2707 "Contentes of startup configuration\n")
2708{
2709 char buf[BUFSIZ];
2710 FILE *confp;
2711
2712 confp = fopen (host.config, "r");
2713 if (confp == NULL)
2714 {
2715 vty_out (vty, "Can't open configuration file [%s]%s",
2716 host.config, VTY_NEWLINE);
2717 return CMD_WARNING;
2718 }
2719
2720 while (fgets (buf, BUFSIZ, confp))
2721 {
2722 char *cp = buf;
2723
2724 while (*cp != '\r' && *cp != '\n' && *cp != '\0')
2725 cp++;
2726 *cp = '\0';
2727
2728 vty_out (vty, "%s%s", buf, VTY_NEWLINE);
2729 }
2730
2731 fclose (confp);
2732
2733 return CMD_SUCCESS;
2734}
2735
2736/* Hostname configuration */
2737DEFUN (config_hostname,
2738 hostname_cmd,
2739 "hostname WORD",
2740 "Set system's network name\n"
2741 "This system's network name\n")
2742{
2743 if (!isalpha((int) *argv[0]))
2744 {
2745 vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
2746 return CMD_WARNING;
2747 }
2748
2749 if (host.name)
paul05865c92005-10-26 05:49:54 +00002750 XFREE (MTYPE_HOST, host.name);
paul718e3742002-12-13 20:15:29 +00002751
paul05865c92005-10-26 05:49:54 +00002752 host.name = XSTRDUP (MTYPE_HOST, argv[0]);
paul718e3742002-12-13 20:15:29 +00002753 return CMD_SUCCESS;
2754}
2755
2756DEFUN (config_no_hostname,
2757 no_hostname_cmd,
2758 "no hostname [HOSTNAME]",
2759 NO_STR
2760 "Reset system's network name\n"
2761 "Host name of this router\n")
2762{
2763 if (host.name)
paul05865c92005-10-26 05:49:54 +00002764 XFREE (MTYPE_HOST, host.name);
paul718e3742002-12-13 20:15:29 +00002765 host.name = NULL;
2766 return CMD_SUCCESS;
2767}
2768
2769/* VTY interface password set. */
2770DEFUN (config_password, password_cmd,
2771 "password (8|) WORD",
2772 "Assign the terminal connection password\n"
2773 "Specifies a HIDDEN password will follow\n"
2774 "dummy string \n"
2775 "The HIDDEN line password string\n")
2776{
2777 /* Argument check. */
2778 if (argc == 0)
2779 {
2780 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2781 return CMD_WARNING;
2782 }
2783
2784 if (argc == 2)
2785 {
2786 if (*argv[0] == '8')
2787 {
2788 if (host.password)
paul05865c92005-10-26 05:49:54 +00002789 XFREE (MTYPE_HOST, host.password);
paul718e3742002-12-13 20:15:29 +00002790 host.password = NULL;
2791 if (host.password_encrypt)
paul05865c92005-10-26 05:49:54 +00002792 XFREE (MTYPE_HOST, host.password_encrypt);
2793 host.password_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
paul718e3742002-12-13 20:15:29 +00002794 return CMD_SUCCESS;
2795 }
2796 else
2797 {
2798 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2799 return CMD_WARNING;
2800 }
2801 }
2802
2803 if (!isalnum ((int) *argv[0]))
2804 {
2805 vty_out (vty,
2806 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2807 return CMD_WARNING;
2808 }
2809
2810 if (host.password)
paul05865c92005-10-26 05:49:54 +00002811 XFREE (MTYPE_HOST, host.password);
paul718e3742002-12-13 20:15:29 +00002812 host.password = NULL;
2813
2814 if (host.encrypt)
2815 {
2816 if (host.password_encrypt)
paul05865c92005-10-26 05:49:54 +00002817 XFREE (MTYPE_HOST, host.password_encrypt);
2818 host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
paul718e3742002-12-13 20:15:29 +00002819 }
2820 else
paul05865c92005-10-26 05:49:54 +00002821 host.password = XSTRDUP (MTYPE_HOST, argv[0]);
paul718e3742002-12-13 20:15:29 +00002822
2823 return CMD_SUCCESS;
2824}
2825
2826ALIAS (config_password, password_text_cmd,
2827 "password LINE",
2828 "Assign the terminal connection password\n"
2829 "The UNENCRYPTED (cleartext) line password\n")
2830
2831/* VTY enable password set. */
2832DEFUN (config_enable_password, enable_password_cmd,
2833 "enable password (8|) WORD",
2834 "Modify enable password parameters\n"
2835 "Assign the privileged level password\n"
2836 "Specifies a HIDDEN password will follow\n"
2837 "dummy string \n"
2838 "The HIDDEN 'enable' password string\n")
2839{
2840 /* Argument check. */
2841 if (argc == 0)
2842 {
2843 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2844 return CMD_WARNING;
2845 }
2846
2847 /* Crypt type is specified. */
2848 if (argc == 2)
2849 {
2850 if (*argv[0] == '8')
2851 {
2852 if (host.enable)
paul05865c92005-10-26 05:49:54 +00002853 XFREE (MTYPE_HOST, host.enable);
paul718e3742002-12-13 20:15:29 +00002854 host.enable = NULL;
2855
2856 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002857 XFREE (MTYPE_HOST, host.enable_encrypt);
2858 host.enable_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
paul718e3742002-12-13 20:15:29 +00002859
2860 return CMD_SUCCESS;
2861 }
2862 else
2863 {
2864 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2865 return CMD_WARNING;
2866 }
2867 }
2868
2869 if (!isalnum ((int) *argv[0]))
2870 {
2871 vty_out (vty,
2872 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2873 return CMD_WARNING;
2874 }
2875
2876 if (host.enable)
paul05865c92005-10-26 05:49:54 +00002877 XFREE (MTYPE_HOST, host.enable);
paul718e3742002-12-13 20:15:29 +00002878 host.enable = NULL;
2879
2880 /* Plain password input. */
2881 if (host.encrypt)
2882 {
2883 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002884 XFREE (MTYPE_HOST, host.enable_encrypt);
2885 host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
paul718e3742002-12-13 20:15:29 +00002886 }
2887 else
paul05865c92005-10-26 05:49:54 +00002888 host.enable = XSTRDUP (MTYPE_HOST, argv[0]);
paul718e3742002-12-13 20:15:29 +00002889
2890 return CMD_SUCCESS;
2891}
2892
2893ALIAS (config_enable_password,
2894 enable_password_text_cmd,
2895 "enable password LINE",
2896 "Modify enable password parameters\n"
2897 "Assign the privileged level password\n"
2898 "The UNENCRYPTED (cleartext) 'enable' password\n")
2899
2900/* VTY enable password delete. */
2901DEFUN (no_config_enable_password, no_enable_password_cmd,
2902 "no enable password",
2903 NO_STR
2904 "Modify enable password parameters\n"
2905 "Assign the privileged level password\n")
2906{
2907 if (host.enable)
paul05865c92005-10-26 05:49:54 +00002908 XFREE (MTYPE_HOST, host.enable);
paul718e3742002-12-13 20:15:29 +00002909 host.enable = NULL;
2910
2911 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002912 XFREE (MTYPE_HOST, host.enable_encrypt);
paul718e3742002-12-13 20:15:29 +00002913 host.enable_encrypt = NULL;
2914
2915 return CMD_SUCCESS;
2916}
2917
2918DEFUN (service_password_encrypt,
2919 service_password_encrypt_cmd,
2920 "service password-encryption",
2921 "Set up miscellaneous service\n"
2922 "Enable encrypted passwords\n")
2923{
2924 if (host.encrypt)
2925 return CMD_SUCCESS;
2926
2927 host.encrypt = 1;
2928
2929 if (host.password)
2930 {
2931 if (host.password_encrypt)
paul05865c92005-10-26 05:49:54 +00002932 XFREE (MTYPE_HOST, host.password_encrypt);
2933 host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.password));
paul718e3742002-12-13 20:15:29 +00002934 }
2935 if (host.enable)
2936 {
2937 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002938 XFREE (MTYPE_HOST, host.enable_encrypt);
2939 host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.enable));
paul718e3742002-12-13 20:15:29 +00002940 }
2941
2942 return CMD_SUCCESS;
2943}
2944
2945DEFUN (no_service_password_encrypt,
2946 no_service_password_encrypt_cmd,
2947 "no service password-encryption",
2948 NO_STR
2949 "Set up miscellaneous service\n"
2950 "Enable encrypted passwords\n")
2951{
2952 if (! host.encrypt)
2953 return CMD_SUCCESS;
2954
2955 host.encrypt = 0;
2956
2957 if (host.password_encrypt)
paul05865c92005-10-26 05:49:54 +00002958 XFREE (MTYPE_HOST, host.password_encrypt);
paul718e3742002-12-13 20:15:29 +00002959 host.password_encrypt = NULL;
2960
2961 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002962 XFREE (MTYPE_HOST, host.enable_encrypt);
paul718e3742002-12-13 20:15:29 +00002963 host.enable_encrypt = NULL;
2964
2965 return CMD_SUCCESS;
2966}
2967
2968DEFUN (config_terminal_length, config_terminal_length_cmd,
2969 "terminal length <0-512>",
2970 "Set terminal line parameters\n"
2971 "Set number of lines on a screen\n"
2972 "Number of lines on screen (0 for no pausing)\n")
2973{
2974 int lines;
2975 char *endptr = NULL;
2976
2977 lines = strtol (argv[0], &endptr, 10);
2978 if (lines < 0 || lines > 512 || *endptr != '\0')
2979 {
2980 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2981 return CMD_WARNING;
2982 }
2983 vty->lines = lines;
2984
2985 return CMD_SUCCESS;
2986}
2987
2988DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
2989 "terminal no length",
2990 "Set terminal line parameters\n"
2991 NO_STR
2992 "Set number of lines on a screen\n")
2993{
2994 vty->lines = -1;
2995 return CMD_SUCCESS;
2996}
2997
2998DEFUN (service_terminal_length, service_terminal_length_cmd,
2999 "service terminal-length <0-512>",
3000 "Set up miscellaneous service\n"
3001 "System wide terminal length configuration\n"
3002 "Number of lines of VTY (0 means no line control)\n")
3003{
3004 int lines;
3005 char *endptr = NULL;
3006
3007 lines = strtol (argv[0], &endptr, 10);
3008 if (lines < 0 || lines > 512 || *endptr != '\0')
3009 {
3010 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
3011 return CMD_WARNING;
3012 }
3013 host.lines = lines;
3014
3015 return CMD_SUCCESS;
3016}
3017
3018DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
3019 "no service terminal-length [<0-512>]",
3020 NO_STR
3021 "Set up miscellaneous service\n"
3022 "System wide terminal length configuration\n"
3023 "Number of lines of VTY (0 means no line control)\n")
3024{
3025 host.lines = -1;
3026 return CMD_SUCCESS;
3027}
3028
ajs2885f722004-12-17 23:16:33 +00003029DEFUN_HIDDEN (do_echo,
3030 echo_cmd,
3031 "echo .MESSAGE",
3032 "Echo a message back to the vty\n"
3033 "The message to echo\n")
3034{
3035 char *message;
3036
ajsf6834d42005-01-28 20:28:35 +00003037 vty_out (vty, "%s%s", ((message = argv_concat(argv, argc, 0)) ? message : ""),
3038 VTY_NEWLINE);
3039 if (message)
3040 XFREE(MTYPE_TMP, message);
ajs2885f722004-12-17 23:16:33 +00003041 return CMD_SUCCESS;
3042}
3043
ajs274a4a42004-12-07 15:39:31 +00003044DEFUN (config_logmsg,
3045 config_logmsg_cmd,
3046 "logmsg "LOG_LEVELS" .MESSAGE",
3047 "Send a message to enabled logging destinations\n"
3048 LOG_LEVEL_DESC
3049 "The message to send\n")
3050{
3051 int level;
3052 char *message;
3053
3054 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3055 return CMD_ERR_NO_MATCH;
3056
Christian Hammersfc951862011-03-23 13:07:55 +03003057 zlog(NULL, level, "%s", ((message = argv_concat(argv, argc, 1)) ? message : ""));
ajsf6834d42005-01-28 20:28:35 +00003058 if (message)
3059 XFREE(MTYPE_TMP, message);
ajs274a4a42004-12-07 15:39:31 +00003060 return CMD_SUCCESS;
3061}
3062
3063DEFUN (show_logging,
3064 show_logging_cmd,
3065 "show logging",
3066 SHOW_STR
3067 "Show current logging configuration\n")
3068{
3069 struct zlog *zl = zlog_default;
3070
3071 vty_out (vty, "Syslog logging: ");
3072 if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED)
3073 vty_out (vty, "disabled");
3074 else
3075 vty_out (vty, "level %s, facility %s, ident %s",
3076 zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]],
3077 facility_name(zl->facility), zl->ident);
3078 vty_out (vty, "%s", VTY_NEWLINE);
3079
3080 vty_out (vty, "Stdout logging: ");
3081 if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED)
3082 vty_out (vty, "disabled");
3083 else
3084 vty_out (vty, "level %s",
3085 zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
3086 vty_out (vty, "%s", VTY_NEWLINE);
3087
3088 vty_out (vty, "Monitor logging: ");
3089 if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
3090 vty_out (vty, "disabled");
3091 else
3092 vty_out (vty, "level %s",
3093 zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
3094 vty_out (vty, "%s", VTY_NEWLINE);
3095
3096 vty_out (vty, "File logging: ");
3097 if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) ||
3098 !zl->fp)
3099 vty_out (vty, "disabled");
3100 else
3101 vty_out (vty, "level %s, filename %s",
3102 zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
3103 zl->filename);
3104 vty_out (vty, "%s", VTY_NEWLINE);
3105
3106 vty_out (vty, "Protocol name: %s%s",
3107 zlog_proto_names[zl->protocol], VTY_NEWLINE);
3108 vty_out (vty, "Record priority: %s%s",
3109 (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE);
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +00003110 vty_out (vty, "Timestamp precision: %d%s",
3111 zl->timestamp_precision, VTY_NEWLINE);
ajs274a4a42004-12-07 15:39:31 +00003112
3113 return CMD_SUCCESS;
3114}
3115
paul718e3742002-12-13 20:15:29 +00003116DEFUN (config_log_stdout,
3117 config_log_stdout_cmd,
3118 "log stdout",
3119 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003120 "Set stdout logging level\n")
paul718e3742002-12-13 20:15:29 +00003121{
ajs274a4a42004-12-07 15:39:31 +00003122 zlog_set_level (NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl);
3123 return CMD_SUCCESS;
3124}
3125
3126DEFUN (config_log_stdout_level,
3127 config_log_stdout_level_cmd,
3128 "log stdout "LOG_LEVELS,
3129 "Logging control\n"
3130 "Set stdout logging level\n"
3131 LOG_LEVEL_DESC)
3132{
3133 int level;
3134
3135 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3136 return CMD_ERR_NO_MATCH;
3137 zlog_set_level (NULL, ZLOG_DEST_STDOUT, level);
paul718e3742002-12-13 20:15:29 +00003138 return CMD_SUCCESS;
3139}
3140
3141DEFUN (no_config_log_stdout,
3142 no_config_log_stdout_cmd,
ajs274a4a42004-12-07 15:39:31 +00003143 "no log stdout [LEVEL]",
paul718e3742002-12-13 20:15:29 +00003144 NO_STR
3145 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003146 "Cancel logging to stdout\n"
3147 "Logging level\n")
paul718e3742002-12-13 20:15:29 +00003148{
ajs274a4a42004-12-07 15:39:31 +00003149 zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED);
paul718e3742002-12-13 20:15:29 +00003150 return CMD_SUCCESS;
3151}
3152
ajs274a4a42004-12-07 15:39:31 +00003153DEFUN (config_log_monitor,
3154 config_log_monitor_cmd,
3155 "log monitor",
paul718e3742002-12-13 20:15:29 +00003156 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003157 "Set terminal line (monitor) logging level\n")
3158{
3159 zlog_set_level (NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl);
3160 return CMD_SUCCESS;
3161}
3162
3163DEFUN (config_log_monitor_level,
3164 config_log_monitor_level_cmd,
3165 "log monitor "LOG_LEVELS,
3166 "Logging control\n"
3167 "Set terminal line (monitor) logging level\n"
3168 LOG_LEVEL_DESC)
3169{
3170 int level;
3171
3172 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3173 return CMD_ERR_NO_MATCH;
3174 zlog_set_level (NULL, ZLOG_DEST_MONITOR, level);
3175 return CMD_SUCCESS;
3176}
3177
3178DEFUN (no_config_log_monitor,
3179 no_config_log_monitor_cmd,
3180 "no log monitor [LEVEL]",
3181 NO_STR
3182 "Logging control\n"
3183 "Disable terminal line (monitor) logging\n"
3184 "Logging level\n")
3185{
3186 zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
3187 return CMD_SUCCESS;
3188}
3189
3190static int
3191set_log_file(struct vty *vty, const char *fname, int loglevel)
paul718e3742002-12-13 20:15:29 +00003192{
3193 int ret;
paul9035efa2004-10-10 11:56:56 +00003194 char *p = NULL;
3195 const char *fullpath;
3196
paul718e3742002-12-13 20:15:29 +00003197 /* Path detection. */
ajs274a4a42004-12-07 15:39:31 +00003198 if (! IS_DIRECTORY_SEP (*fname))
paul718e3742002-12-13 20:15:29 +00003199 {
paul9035efa2004-10-10 11:56:56 +00003200 char cwd[MAXPATHLEN+1];
3201 cwd[MAXPATHLEN] = '\0';
3202
3203 if (getcwd (cwd, MAXPATHLEN) == NULL)
3204 {
3205 zlog_err ("config_log_file: Unable to alloc mem!");
3206 return CMD_WARNING;
3207 }
3208
ajs274a4a42004-12-07 15:39:31 +00003209 if ( (p = XMALLOC (MTYPE_TMP, strlen (cwd) + strlen (fname) + 2))
paul9035efa2004-10-10 11:56:56 +00003210 == NULL)
3211 {
3212 zlog_err ("config_log_file: Unable to alloc mem!");
3213 return CMD_WARNING;
3214 }
ajs274a4a42004-12-07 15:39:31 +00003215 sprintf (p, "%s/%s", cwd, fname);
paul9035efa2004-10-10 11:56:56 +00003216 fullpath = p;
paul718e3742002-12-13 20:15:29 +00003217 }
3218 else
ajs274a4a42004-12-07 15:39:31 +00003219 fullpath = fname;
paul718e3742002-12-13 20:15:29 +00003220
ajs274a4a42004-12-07 15:39:31 +00003221 ret = zlog_set_file (NULL, fullpath, loglevel);
paul718e3742002-12-13 20:15:29 +00003222
paul9035efa2004-10-10 11:56:56 +00003223 if (p)
3224 XFREE (MTYPE_TMP, p);
3225
paul718e3742002-12-13 20:15:29 +00003226 if (!ret)
3227 {
ajs274a4a42004-12-07 15:39:31 +00003228 vty_out (vty, "can't open logfile %s\n", fname);
paul718e3742002-12-13 20:15:29 +00003229 return CMD_WARNING;
3230 }
3231
3232 if (host.logfile)
paul05865c92005-10-26 05:49:54 +00003233 XFREE (MTYPE_HOST, host.logfile);
paul718e3742002-12-13 20:15:29 +00003234
paul05865c92005-10-26 05:49:54 +00003235 host.logfile = XSTRDUP (MTYPE_HOST, fname);
paul718e3742002-12-13 20:15:29 +00003236
3237 return CMD_SUCCESS;
3238}
3239
ajs274a4a42004-12-07 15:39:31 +00003240DEFUN (config_log_file,
3241 config_log_file_cmd,
3242 "log file FILENAME",
3243 "Logging control\n"
3244 "Logging to file\n"
3245 "Logging filename\n")
3246{
3247 return set_log_file(vty, argv[0], zlog_default->default_lvl);
3248}
3249
3250DEFUN (config_log_file_level,
3251 config_log_file_level_cmd,
3252 "log file FILENAME "LOG_LEVELS,
3253 "Logging control\n"
3254 "Logging to file\n"
3255 "Logging filename\n"
3256 LOG_LEVEL_DESC)
3257{
3258 int level;
3259
3260 if ((level = level_match(argv[1])) == ZLOG_DISABLED)
3261 return CMD_ERR_NO_MATCH;
3262 return set_log_file(vty, argv[0], level);
3263}
3264
paul718e3742002-12-13 20:15:29 +00003265DEFUN (no_config_log_file,
3266 no_config_log_file_cmd,
3267 "no log file [FILENAME]",
3268 NO_STR
3269 "Logging control\n"
3270 "Cancel logging to file\n"
3271 "Logging file name\n")
3272{
3273 zlog_reset_file (NULL);
3274
3275 if (host.logfile)
paul05865c92005-10-26 05:49:54 +00003276 XFREE (MTYPE_HOST, host.logfile);
paul718e3742002-12-13 20:15:29 +00003277
3278 host.logfile = NULL;
3279
3280 return CMD_SUCCESS;
3281}
3282
ajs274a4a42004-12-07 15:39:31 +00003283ALIAS (no_config_log_file,
3284 no_config_log_file_level_cmd,
3285 "no log file FILENAME LEVEL",
3286 NO_STR
3287 "Logging control\n"
3288 "Cancel logging to file\n"
3289 "Logging file name\n"
3290 "Logging level\n")
3291
paul718e3742002-12-13 20:15:29 +00003292DEFUN (config_log_syslog,
3293 config_log_syslog_cmd,
3294 "log syslog",
3295 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003296 "Set syslog logging level\n")
paul718e3742002-12-13 20:15:29 +00003297{
ajs274a4a42004-12-07 15:39:31 +00003298 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
paul12ab19f2003-07-26 06:14:55 +00003299 return CMD_SUCCESS;
3300}
3301
ajs274a4a42004-12-07 15:39:31 +00003302DEFUN (config_log_syslog_level,
3303 config_log_syslog_level_cmd,
3304 "log syslog "LOG_LEVELS,
paul12ab19f2003-07-26 06:14:55 +00003305 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003306 "Set syslog logging level\n"
3307 LOG_LEVEL_DESC)
paul12ab19f2003-07-26 06:14:55 +00003308{
ajs274a4a42004-12-07 15:39:31 +00003309 int level;
paul12ab19f2003-07-26 06:14:55 +00003310
ajs274a4a42004-12-07 15:39:31 +00003311 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3312 return CMD_ERR_NO_MATCH;
3313 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, level);
3314 return CMD_SUCCESS;
3315}
paul12ab19f2003-07-26 06:14:55 +00003316
ajs274a4a42004-12-07 15:39:31 +00003317DEFUN_DEPRECATED (config_log_syslog_facility,
3318 config_log_syslog_facility_cmd,
3319 "log syslog facility "LOG_FACILITIES,
3320 "Logging control\n"
3321 "Logging goes to syslog\n"
3322 "(Deprecated) Facility parameter for syslog messages\n"
3323 LOG_FACILITY_DESC)
3324{
3325 int facility;
paul12ab19f2003-07-26 06:14:55 +00003326
ajs274a4a42004-12-07 15:39:31 +00003327 if ((facility = facility_match(argv[0])) < 0)
3328 return CMD_ERR_NO_MATCH;
3329
3330 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
paul12ab19f2003-07-26 06:14:55 +00003331 zlog_default->facility = facility;
paul718e3742002-12-13 20:15:29 +00003332 return CMD_SUCCESS;
3333}
3334
3335DEFUN (no_config_log_syslog,
3336 no_config_log_syslog_cmd,
ajs274a4a42004-12-07 15:39:31 +00003337 "no log syslog [LEVEL]",
paul718e3742002-12-13 20:15:29 +00003338 NO_STR
3339 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003340 "Cancel logging to syslog\n"
3341 "Logging level\n")
paul718e3742002-12-13 20:15:29 +00003342{
ajs274a4a42004-12-07 15:39:31 +00003343 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
paul718e3742002-12-13 20:15:29 +00003344 return CMD_SUCCESS;
3345}
3346
paul12ab19f2003-07-26 06:14:55 +00003347ALIAS (no_config_log_syslog,
3348 no_config_log_syslog_facility_cmd,
ajs274a4a42004-12-07 15:39:31 +00003349 "no log syslog facility "LOG_FACILITIES,
paul12ab19f2003-07-26 06:14:55 +00003350 NO_STR
3351 "Logging control\n"
3352 "Logging goes to syslog\n"
3353 "Facility parameter for syslog messages\n"
ajs274a4a42004-12-07 15:39:31 +00003354 LOG_FACILITY_DESC)
paul12ab19f2003-07-26 06:14:55 +00003355
ajs274a4a42004-12-07 15:39:31 +00003356DEFUN (config_log_facility,
3357 config_log_facility_cmd,
3358 "log facility "LOG_FACILITIES,
paul718e3742002-12-13 20:15:29 +00003359 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003360 "Facility parameter for syslog messages\n"
3361 LOG_FACILITY_DESC)
paul718e3742002-12-13 20:15:29 +00003362{
ajs274a4a42004-12-07 15:39:31 +00003363 int facility;
3364
3365 if ((facility = facility_match(argv[0])) < 0)
3366 return CMD_ERR_NO_MATCH;
3367 zlog_default->facility = facility;
3368 return CMD_SUCCESS;
paul718e3742002-12-13 20:15:29 +00003369}
3370
ajs274a4a42004-12-07 15:39:31 +00003371DEFUN (no_config_log_facility,
3372 no_config_log_facility_cmd,
3373 "no log facility [FACILITY]",
paul718e3742002-12-13 20:15:29 +00003374 NO_STR
3375 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003376 "Reset syslog facility to default (daemon)\n"
3377 "Syslog facility\n")
paul718e3742002-12-13 20:15:29 +00003378{
ajs274a4a42004-12-07 15:39:31 +00003379 zlog_default->facility = LOG_DAEMON;
3380 return CMD_SUCCESS;
3381}
3382
3383DEFUN_DEPRECATED (config_log_trap,
3384 config_log_trap_cmd,
3385 "log trap "LOG_LEVELS,
3386 "Logging control\n"
3387 "(Deprecated) Set logging level and default for all destinations\n"
3388 LOG_LEVEL_DESC)
3389{
3390 int new_level ;
3391 int i;
3392
3393 if ((new_level = level_match(argv[0])) == ZLOG_DISABLED)
3394 return CMD_ERR_NO_MATCH;
3395
3396 zlog_default->default_lvl = new_level;
3397 for (i = 0; i < ZLOG_NUM_DESTS; i++)
3398 if (zlog_default->maxlvl[i] != ZLOG_DISABLED)
3399 zlog_default->maxlvl[i] = new_level;
3400 return CMD_SUCCESS;
3401}
3402
3403DEFUN_DEPRECATED (no_config_log_trap,
3404 no_config_log_trap_cmd,
3405 "no log trap [LEVEL]",
3406 NO_STR
3407 "Logging control\n"
3408 "Permit all logging information\n"
3409 "Logging level\n")
3410{
3411 zlog_default->default_lvl = LOG_DEBUG;
paul718e3742002-12-13 20:15:29 +00003412 return CMD_SUCCESS;
3413}
3414
3415DEFUN (config_log_record_priority,
3416 config_log_record_priority_cmd,
3417 "log record-priority",
3418 "Logging control\n"
3419 "Log the priority of the message within the message\n")
3420{
3421 zlog_default->record_priority = 1 ;
3422 return CMD_SUCCESS;
3423}
3424
3425DEFUN (no_config_log_record_priority,
3426 no_config_log_record_priority_cmd,
3427 "no log record-priority",
3428 NO_STR
3429 "Logging control\n"
3430 "Do not log the priority of the message within the message\n")
3431{
3432 zlog_default->record_priority = 0 ;
3433 return CMD_SUCCESS;
3434}
3435
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +00003436DEFUN (config_log_timestamp_precision,
3437 config_log_timestamp_precision_cmd,
3438 "log timestamp precision <0-6>",
3439 "Logging control\n"
3440 "Timestamp configuration\n"
3441 "Set the timestamp precision\n"
3442 "Number of subsecond digits\n")
3443{
3444 if (argc != 1)
3445 {
3446 vty_out (vty, "Insufficient arguments%s", VTY_NEWLINE);
3447 return CMD_WARNING;
3448 }
3449
3450 VTY_GET_INTEGER_RANGE("Timestamp Precision",
3451 zlog_default->timestamp_precision, argv[0], 0, 6);
3452 return CMD_SUCCESS;
3453}
3454
3455DEFUN (no_config_log_timestamp_precision,
3456 no_config_log_timestamp_precision_cmd,
3457 "no log timestamp precision",
3458 NO_STR
3459 "Logging control\n"
3460 "Timestamp configuration\n"
3461 "Reset the timestamp precision to the default value of 0\n")
3462{
3463 zlog_default->timestamp_precision = 0 ;
3464 return CMD_SUCCESS;
3465}
3466
paul3b0c5d92005-03-08 10:43:43 +00003467DEFUN (banner_motd_file,
3468 banner_motd_file_cmd,
3469 "banner motd file [FILE]",
3470 "Set banner\n"
3471 "Banner for motd\n"
3472 "Banner from a file\n"
3473 "Filename\n")
3474{
paulb45da6f2005-03-08 15:16:57 +00003475 if (host.motdfile)
paul05865c92005-10-26 05:49:54 +00003476 XFREE (MTYPE_HOST, host.motdfile);
3477 host.motdfile = XSTRDUP (MTYPE_HOST, argv[0]);
paulb45da6f2005-03-08 15:16:57 +00003478
paul3b0c5d92005-03-08 10:43:43 +00003479 return CMD_SUCCESS;
3480}
paul718e3742002-12-13 20:15:29 +00003481
3482DEFUN (banner_motd_default,
3483 banner_motd_default_cmd,
3484 "banner motd default",
3485 "Set banner string\n"
3486 "Strings for motd\n"
3487 "Default string\n")
3488{
3489 host.motd = default_motd;
3490 return CMD_SUCCESS;
3491}
3492
3493DEFUN (no_banner_motd,
3494 no_banner_motd_cmd,
3495 "no banner motd",
3496 NO_STR
3497 "Set banner string\n"
3498 "Strings for motd\n")
3499{
3500 host.motd = NULL;
paul22085182005-03-08 16:00:12 +00003501 if (host.motdfile)
paul05865c92005-10-26 05:49:54 +00003502 XFREE (MTYPE_HOST, host.motdfile);
paul3b0c5d92005-03-08 10:43:43 +00003503 host.motdfile = NULL;
paul718e3742002-12-13 20:15:29 +00003504 return CMD_SUCCESS;
3505}
3506
3507/* Set config filename. Called from vty.c */
3508void
3509host_config_set (char *filename)
3510{
Chris Caputo228da422009-07-18 05:44:03 +00003511 if (host.config)
3512 XFREE (MTYPE_HOST, host.config);
paul05865c92005-10-26 05:49:54 +00003513 host.config = XSTRDUP (MTYPE_HOST, filename);
paul718e3742002-12-13 20:15:29 +00003514}
3515
3516void
3517install_default (enum node_type node)
3518{
3519 install_element (node, &config_exit_cmd);
3520 install_element (node, &config_quit_cmd);
3521 install_element (node, &config_end_cmd);
3522 install_element (node, &config_help_cmd);
3523 install_element (node, &config_list_cmd);
3524
3525 install_element (node, &config_write_terminal_cmd);
3526 install_element (node, &config_write_file_cmd);
3527 install_element (node, &config_write_memory_cmd);
3528 install_element (node, &config_write_cmd);
3529 install_element (node, &show_running_config_cmd);
3530}
3531
3532/* Initialize command interface. Install basic nodes and commands. */
3533void
3534cmd_init (int terminal)
3535{
Chris Caputo228da422009-07-18 05:44:03 +00003536 command_cr = XSTRDUP(MTYPE_STRVEC, "<cr>");
3537 desc_cr.cmd = command_cr;
3538 desc_cr.str = XSTRDUP(MTYPE_STRVEC, "");
3539
paul718e3742002-12-13 20:15:29 +00003540 /* Allocate initial top vector of commands. */
3541 cmdvec = vector_init (VECTOR_MIN_SIZE);
3542
3543 /* Default host value settings. */
3544 host.name = NULL;
3545 host.password = NULL;
3546 host.enable = NULL;
3547 host.logfile = NULL;
3548 host.config = NULL;
3549 host.lines = -1;
3550 host.motd = default_motd;
paul3b0c5d92005-03-08 10:43:43 +00003551 host.motdfile = NULL;
paul718e3742002-12-13 20:15:29 +00003552
3553 /* Install top nodes. */
3554 install_node (&view_node, NULL);
3555 install_node (&enable_node, NULL);
3556 install_node (&auth_node, NULL);
3557 install_node (&auth_enable_node, NULL);
Paul Jakma62687ff2008-08-23 14:27:06 +01003558 install_node (&restricted_node, NULL);
paul718e3742002-12-13 20:15:29 +00003559 install_node (&config_node, config_write_host);
3560
3561 /* Each node's basic commands. */
3562 install_element (VIEW_NODE, &show_version_cmd);
3563 if (terminal)
3564 {
3565 install_element (VIEW_NODE, &config_list_cmd);
3566 install_element (VIEW_NODE, &config_exit_cmd);
3567 install_element (VIEW_NODE, &config_quit_cmd);
3568 install_element (VIEW_NODE, &config_help_cmd);
3569 install_element (VIEW_NODE, &config_enable_cmd);
3570 install_element (VIEW_NODE, &config_terminal_length_cmd);
3571 install_element (VIEW_NODE, &config_terminal_no_length_cmd);
ajs274a4a42004-12-07 15:39:31 +00003572 install_element (VIEW_NODE, &show_logging_cmd);
ajs2885f722004-12-17 23:16:33 +00003573 install_element (VIEW_NODE, &echo_cmd);
Paul Jakma62687ff2008-08-23 14:27:06 +01003574
3575 install_element (RESTRICTED_NODE, &config_list_cmd);
3576 install_element (RESTRICTED_NODE, &config_exit_cmd);
3577 install_element (RESTRICTED_NODE, &config_quit_cmd);
3578 install_element (RESTRICTED_NODE, &config_help_cmd);
3579 install_element (RESTRICTED_NODE, &config_enable_cmd);
3580 install_element (RESTRICTED_NODE, &config_terminal_length_cmd);
3581 install_element (RESTRICTED_NODE, &config_terminal_no_length_cmd);
3582 install_element (RESTRICTED_NODE, &echo_cmd);
paul718e3742002-12-13 20:15:29 +00003583 }
3584
3585 if (terminal)
3586 {
3587 install_default (ENABLE_NODE);
3588 install_element (ENABLE_NODE, &config_disable_cmd);
3589 install_element (ENABLE_NODE, &config_terminal_cmd);
3590 install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
3591 }
3592 install_element (ENABLE_NODE, &show_startup_config_cmd);
3593 install_element (ENABLE_NODE, &show_version_cmd);
paul718e3742002-12-13 20:15:29 +00003594
3595 if (terminal)
paul718e3742002-12-13 20:15:29 +00003596 {
hassoe7168df2004-10-03 20:11:32 +00003597 install_element (ENABLE_NODE, &config_terminal_length_cmd);
3598 install_element (ENABLE_NODE, &config_terminal_no_length_cmd);
ajs274a4a42004-12-07 15:39:31 +00003599 install_element (ENABLE_NODE, &show_logging_cmd);
ajs2885f722004-12-17 23:16:33 +00003600 install_element (ENABLE_NODE, &echo_cmd);
ajs274a4a42004-12-07 15:39:31 +00003601 install_element (ENABLE_NODE, &config_logmsg_cmd);
hassoe7168df2004-10-03 20:11:32 +00003602
3603 install_default (CONFIG_NODE);
hassoea8e9d92004-10-07 21:32:14 +00003604 }
3605
3606 install_element (CONFIG_NODE, &hostname_cmd);
3607 install_element (CONFIG_NODE, &no_hostname_cmd);
hassoe7168df2004-10-03 20:11:32 +00003608
hassoea8e9d92004-10-07 21:32:14 +00003609 if (terminal)
3610 {
hassoe7168df2004-10-03 20:11:32 +00003611 install_element (CONFIG_NODE, &password_cmd);
3612 install_element (CONFIG_NODE, &password_text_cmd);
3613 install_element (CONFIG_NODE, &enable_password_cmd);
3614 install_element (CONFIG_NODE, &enable_password_text_cmd);
3615 install_element (CONFIG_NODE, &no_enable_password_cmd);
3616
paul718e3742002-12-13 20:15:29 +00003617 install_element (CONFIG_NODE, &config_log_stdout_cmd);
ajs274a4a42004-12-07 15:39:31 +00003618 install_element (CONFIG_NODE, &config_log_stdout_level_cmd);
paul718e3742002-12-13 20:15:29 +00003619 install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
ajs274a4a42004-12-07 15:39:31 +00003620 install_element (CONFIG_NODE, &config_log_monitor_cmd);
3621 install_element (CONFIG_NODE, &config_log_monitor_level_cmd);
3622 install_element (CONFIG_NODE, &no_config_log_monitor_cmd);
paul718e3742002-12-13 20:15:29 +00003623 install_element (CONFIG_NODE, &config_log_file_cmd);
ajs274a4a42004-12-07 15:39:31 +00003624 install_element (CONFIG_NODE, &config_log_file_level_cmd);
paul718e3742002-12-13 20:15:29 +00003625 install_element (CONFIG_NODE, &no_config_log_file_cmd);
ajs274a4a42004-12-07 15:39:31 +00003626 install_element (CONFIG_NODE, &no_config_log_file_level_cmd);
paul718e3742002-12-13 20:15:29 +00003627 install_element (CONFIG_NODE, &config_log_syslog_cmd);
ajs274a4a42004-12-07 15:39:31 +00003628 install_element (CONFIG_NODE, &config_log_syslog_level_cmd);
paul12ab19f2003-07-26 06:14:55 +00003629 install_element (CONFIG_NODE, &config_log_syslog_facility_cmd);
paul718e3742002-12-13 20:15:29 +00003630 install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
paul12ab19f2003-07-26 06:14:55 +00003631 install_element (CONFIG_NODE, &no_config_log_syslog_facility_cmd);
ajs274a4a42004-12-07 15:39:31 +00003632 install_element (CONFIG_NODE, &config_log_facility_cmd);
3633 install_element (CONFIG_NODE, &no_config_log_facility_cmd);
paul718e3742002-12-13 20:15:29 +00003634 install_element (CONFIG_NODE, &config_log_trap_cmd);
3635 install_element (CONFIG_NODE, &no_config_log_trap_cmd);
3636 install_element (CONFIG_NODE, &config_log_record_priority_cmd);
3637 install_element (CONFIG_NODE, &no_config_log_record_priority_cmd);
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +00003638 install_element (CONFIG_NODE, &config_log_timestamp_precision_cmd);
3639 install_element (CONFIG_NODE, &no_config_log_timestamp_precision_cmd);
paul718e3742002-12-13 20:15:29 +00003640 install_element (CONFIG_NODE, &service_password_encrypt_cmd);
3641 install_element (CONFIG_NODE, &no_service_password_encrypt_cmd);
3642 install_element (CONFIG_NODE, &banner_motd_default_cmd);
paul3b0c5d92005-03-08 10:43:43 +00003643 install_element (CONFIG_NODE, &banner_motd_file_cmd);
paul718e3742002-12-13 20:15:29 +00003644 install_element (CONFIG_NODE, &no_banner_motd_cmd);
3645 install_element (CONFIG_NODE, &service_terminal_length_cmd);
3646 install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
paul718e3742002-12-13 20:15:29 +00003647
paul354d1192005-04-25 16:26:42 +00003648 install_element (VIEW_NODE, &show_thread_cpu_cmd);
3649 install_element (ENABLE_NODE, &show_thread_cpu_cmd);
Paul Jakma62687ff2008-08-23 14:27:06 +01003650 install_element (RESTRICTED_NODE, &show_thread_cpu_cmd);
Paul Jakmae276eb82010-01-09 16:15:00 +00003651
3652 install_element (ENABLE_NODE, &clear_thread_cpu_cmd);
paul354d1192005-04-25 16:26:42 +00003653 install_element (VIEW_NODE, &show_work_queues_cmd);
3654 install_element (ENABLE_NODE, &show_work_queues_cmd);
paul9ab68122003-01-18 01:16:20 +00003655 }
paul718e3742002-12-13 20:15:29 +00003656 srand(time(NULL));
3657}
Chris Caputo228da422009-07-18 05:44:03 +00003658
3659void
3660cmd_terminate ()
3661{
3662 unsigned int i, j, k, l;
3663 struct cmd_node *cmd_node;
3664 struct cmd_element *cmd_element;
3665 struct desc *desc;
3666 vector cmd_node_v, cmd_element_v, desc_v;
3667
3668 if (cmdvec)
3669 {
3670 for (i = 0; i < vector_active (cmdvec); i++)
3671 if ((cmd_node = vector_slot (cmdvec, i)) != NULL)
3672 {
3673 cmd_node_v = cmd_node->cmd_vector;
3674
3675 for (j = 0; j < vector_active (cmd_node_v); j++)
3676 if ((cmd_element = vector_slot (cmd_node_v, j)) != NULL &&
3677 cmd_element->strvec != NULL)
3678 {
3679 cmd_element_v = cmd_element->strvec;
3680
3681 for (k = 0; k < vector_active (cmd_element_v); k++)
3682 if ((desc_v = vector_slot (cmd_element_v, k)) != NULL)
3683 {
3684 for (l = 0; l < vector_active (desc_v); l++)
3685 if ((desc = vector_slot (desc_v, l)) != NULL)
3686 {
3687 if (desc->cmd)
3688 XFREE (MTYPE_STRVEC, desc->cmd);
3689 if (desc->str)
3690 XFREE (MTYPE_STRVEC, desc->str);
3691
3692 XFREE (MTYPE_DESC, desc);
3693 }
3694 vector_free (desc_v);
3695 }
3696
3697 cmd_element->strvec = NULL;
3698 vector_free (cmd_element_v);
3699 }
3700
3701 vector_free (cmd_node_v);
3702 }
3703
3704 vector_free (cmdvec);
3705 cmdvec = NULL;
3706 }
3707
3708 if (command_cr)
3709 XFREE(MTYPE_STRVEC, command_cr);
3710 if (desc_cr.str)
3711 XFREE(MTYPE_STRVEC, desc_cr.str);
3712 if (host.name)
3713 XFREE (MTYPE_HOST, host.name);
3714 if (host.password)
3715 XFREE (MTYPE_HOST, host.password);
3716 if (host.password_encrypt)
3717 XFREE (MTYPE_HOST, host.password_encrypt);
3718 if (host.enable)
3719 XFREE (MTYPE_HOST, host.enable);
3720 if (host.enable_encrypt)
3721 XFREE (MTYPE_HOST, host.enable_encrypt);
3722 if (host.logfile)
3723 XFREE (MTYPE_HOST, host.logfile);
3724 if (host.motdfile)
3725 XFREE (MTYPE_HOST, host.motdfile);
3726 if (host.config)
3727 XFREE (MTYPE_HOST, host.config);
3728}