blob: 4d95e924d73f4685555cb5d25e0e48b3e1e2acf0 [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
Roman Hoog Antink7c9c6ae2012-05-09 06:35:34 +0000871 return no_match;
paul718e3742002-12-13 20:15:29 +0000872}
873
ajs274a4a42004-12-07 15:39:31 +0000874static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000875cmd_ipv6_prefix_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000876{
877 int state = STATE_START;
878 int colons = 0, nums = 0, double_colon = 0;
879 int mask;
hasso8c328f12004-10-05 21:01:23 +0000880 const char *sp = NULL;
paul718e3742002-12-13 20:15:29 +0000881 char *endptr = NULL;
882
883 if (str == NULL)
884 return partly_match;
885
886 if (strspn (str, IPV6_PREFIX_STR) != strlen (str))
887 return no_match;
888
889 while (*str != '\0' && state != STATE_MASK)
890 {
891 switch (state)
892 {
893 case STATE_START:
894 if (*str == ':')
895 {
896 if (*(str + 1) != ':' && *(str + 1) != '\0')
897 return no_match;
898 colons--;
899 state = STATE_COLON;
900 }
901 else
902 {
903 sp = str;
904 state = STATE_ADDR;
905 }
906
907 continue;
908 case STATE_COLON:
909 colons++;
910 if (*(str + 1) == '/')
911 return no_match;
912 else if (*(str + 1) == ':')
913 state = STATE_DOUBLE;
914 else
915 {
916 sp = str + 1;
917 state = STATE_ADDR;
918 }
919 break;
920 case STATE_DOUBLE:
921 if (double_colon)
922 return no_match;
923
924 if (*(str + 1) == ':')
925 return no_match;
926 else
927 {
928 if (*(str + 1) != '\0' && *(str + 1) != '/')
929 colons++;
930 sp = str + 1;
931
932 if (*(str + 1) == '/')
933 state = STATE_SLASH;
934 else
935 state = STATE_ADDR;
936 }
937
938 double_colon++;
939 nums += 1;
940 break;
941 case STATE_ADDR:
942 if (*(str + 1) == ':' || *(str + 1) == '.'
943 || *(str + 1) == '\0' || *(str + 1) == '/')
944 {
945 if (str - sp > 3)
946 return no_match;
947
948 for (; sp <= str; sp++)
949 if (*sp == '/')
950 return no_match;
951
952 nums++;
953
954 if (*(str + 1) == ':')
955 state = STATE_COLON;
956 else if (*(str + 1) == '.')
957 state = STATE_DOT;
958 else if (*(str + 1) == '/')
959 state = STATE_SLASH;
960 }
961 break;
962 case STATE_DOT:
963 state = STATE_ADDR;
964 break;
965 case STATE_SLASH:
966 if (*(str + 1) == '\0')
967 return partly_match;
968
969 state = STATE_MASK;
970 break;
971 default:
972 break;
973 }
974
975 if (nums > 11)
976 return no_match;
977
978 if (colons > 7)
979 return no_match;
980
981 str++;
982 }
983
984 if (state < STATE_MASK)
985 return partly_match;
986
987 mask = strtol (str, &endptr, 10);
988 if (*endptr != '\0')
989 return no_match;
990
991 if (mask < 0 || mask > 128)
992 return no_match;
993
994/* I don't know why mask < 13 makes command match partly.
995 Forgive me to make this comments. I Want to set static default route
996 because of lack of function to originate default in ospf6d; sorry
997 yasu
998 if (mask < 13)
999 return partly_match;
1000*/
1001
1002 return exact_match;
1003}
1004
paul22e0a9e2003-07-11 17:55:46 +00001005#endif /* HAVE_IPV6 */
1006
paul718e3742002-12-13 20:15:29 +00001007#define DECIMAL_STRLEN_MAX 10
1008
ajs274a4a42004-12-07 15:39:31 +00001009static int
hasso8c328f12004-10-05 21:01:23 +00001010cmd_range_match (const char *range, const char *str)
paul718e3742002-12-13 20:15:29 +00001011{
1012 char *p;
1013 char buf[DECIMAL_STRLEN_MAX + 1];
1014 char *endptr = NULL;
1015 unsigned long min, max, val;
1016
1017 if (str == NULL)
1018 return 1;
1019
1020 val = strtoul (str, &endptr, 10);
1021 if (*endptr != '\0')
1022 return 0;
1023
1024 range++;
1025 p = strchr (range, '-');
1026 if (p == NULL)
1027 return 0;
1028 if (p - range > DECIMAL_STRLEN_MAX)
1029 return 0;
1030 strncpy (buf, range, p - range);
1031 buf[p - range] = '\0';
1032 min = strtoul (buf, &endptr, 10);
1033 if (*endptr != '\0')
1034 return 0;
1035
1036 range = p + 1;
1037 p = strchr (range, '>');
1038 if (p == NULL)
1039 return 0;
1040 if (p - range > DECIMAL_STRLEN_MAX)
1041 return 0;
1042 strncpy (buf, range, p - range);
1043 buf[p - range] = '\0';
1044 max = strtoul (buf, &endptr, 10);
1045 if (*endptr != '\0')
1046 return 0;
1047
1048 if (val < min || val > max)
1049 return 0;
1050
1051 return 1;
1052}
1053
1054/* Make completion match and return match type flag. */
ajs274a4a42004-12-07 15:39:31 +00001055static enum match_type
hasso8c328f12004-10-05 21:01:23 +00001056cmd_filter_by_completion (char *command, vector v, unsigned int index)
paul718e3742002-12-13 20:15:29 +00001057{
hasso8c328f12004-10-05 21:01:23 +00001058 unsigned int i;
1059 const char *str;
paul718e3742002-12-13 20:15:29 +00001060 struct cmd_element *cmd_element;
1061 enum match_type match_type;
1062 vector descvec;
1063 struct desc *desc;
paul909a2152005-03-14 17:41:45 +00001064
paul718e3742002-12-13 20:15:29 +00001065 match_type = no_match;
1066
1067 /* If command and cmd_element string does not match set NULL to vector */
paul55468c82005-03-14 20:19:01 +00001068 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001069 if ((cmd_element = vector_slot (v, i)) != NULL)
1070 {
paul55468c82005-03-14 20:19:01 +00001071 if (index >= vector_active (cmd_element->strvec))
paul718e3742002-12-13 20:15:29 +00001072 vector_slot (v, i) = NULL;
1073 else
1074 {
hasso8c328f12004-10-05 21:01:23 +00001075 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001076 int matched = 0;
1077
1078 descvec = vector_slot (cmd_element->strvec, index);
paul909a2152005-03-14 17:41:45 +00001079
paul55468c82005-03-14 20:19:01 +00001080 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001081 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001082 {
1083 str = desc->cmd;
1084
1085 if (CMD_VARARG (str))
1086 {
1087 if (match_type < vararg_match)
1088 match_type = vararg_match;
1089 matched++;
1090 }
1091 else if (CMD_RANGE (str))
1092 {
1093 if (cmd_range_match (str, command))
1094 {
1095 if (match_type < range_match)
1096 match_type = range_match;
paul718e3742002-12-13 20:15:29 +00001097
paul909a2152005-03-14 17:41:45 +00001098 matched++;
1099 }
1100 }
paul22e0a9e2003-07-11 17:55:46 +00001101#ifdef HAVE_IPV6
paul909a2152005-03-14 17:41:45 +00001102 else if (CMD_IPV6 (str))
1103 {
1104 if (cmd_ipv6_match (command))
1105 {
1106 if (match_type < ipv6_match)
1107 match_type = ipv6_match;
paul718e3742002-12-13 20:15:29 +00001108
paul909a2152005-03-14 17:41:45 +00001109 matched++;
1110 }
1111 }
1112 else if (CMD_IPV6_PREFIX (str))
1113 {
1114 if (cmd_ipv6_prefix_match (command))
1115 {
1116 if (match_type < ipv6_prefix_match)
1117 match_type = ipv6_prefix_match;
paul718e3742002-12-13 20:15:29 +00001118
paul909a2152005-03-14 17:41:45 +00001119 matched++;
1120 }
1121 }
1122#endif /* HAVE_IPV6 */
1123 else if (CMD_IPV4 (str))
1124 {
1125 if (cmd_ipv4_match (command))
1126 {
1127 if (match_type < ipv4_match)
1128 match_type = ipv4_match;
paul718e3742002-12-13 20:15:29 +00001129
paul909a2152005-03-14 17:41:45 +00001130 matched++;
1131 }
1132 }
1133 else if (CMD_IPV4_PREFIX (str))
1134 {
1135 if (cmd_ipv4_prefix_match (command))
1136 {
1137 if (match_type < ipv4_prefix_match)
1138 match_type = ipv4_prefix_match;
1139 matched++;
1140 }
1141 }
1142 else
1143 /* Check is this point's argument optional ? */
1144 if (CMD_OPTION (str) || CMD_VARIABLE (str))
1145 {
1146 if (match_type < extend_match)
1147 match_type = extend_match;
1148 matched++;
1149 }
1150 else if (strncmp (command, str, strlen (command)) == 0)
1151 {
1152 if (strcmp (command, str) == 0)
1153 match_type = exact_match;
1154 else
1155 {
1156 if (match_type < partly_match)
1157 match_type = partly_match;
1158 }
1159 matched++;
1160 }
1161 }
1162 if (!matched)
paul718e3742002-12-13 20:15:29 +00001163 vector_slot (v, i) = NULL;
1164 }
1165 }
1166 return match_type;
1167}
1168
1169/* Filter vector by command character with index. */
ajs274a4a42004-12-07 15:39:31 +00001170static enum match_type
hasso8c328f12004-10-05 21:01:23 +00001171cmd_filter_by_string (char *command, vector v, unsigned int index)
paul718e3742002-12-13 20:15:29 +00001172{
hasso8c328f12004-10-05 21:01:23 +00001173 unsigned int i;
1174 const char *str;
paul718e3742002-12-13 20:15:29 +00001175 struct cmd_element *cmd_element;
1176 enum match_type match_type;
1177 vector descvec;
1178 struct desc *desc;
paul909a2152005-03-14 17:41:45 +00001179
paul718e3742002-12-13 20:15:29 +00001180 match_type = no_match;
1181
1182 /* If command and cmd_element string does not match set NULL to vector */
paul55468c82005-03-14 20:19:01 +00001183 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001184 if ((cmd_element = vector_slot (v, i)) != NULL)
1185 {
1186 /* If given index is bigger than max string vector of command,
paul909a2152005-03-14 17:41:45 +00001187 set NULL */
paul55468c82005-03-14 20:19:01 +00001188 if (index >= vector_active (cmd_element->strvec))
paul718e3742002-12-13 20:15:29 +00001189 vector_slot (v, i) = NULL;
paul909a2152005-03-14 17:41:45 +00001190 else
paul718e3742002-12-13 20:15:29 +00001191 {
hasso8c328f12004-10-05 21:01:23 +00001192 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001193 int matched = 0;
1194
1195 descvec = vector_slot (cmd_element->strvec, index);
1196
paul55468c82005-03-14 20:19:01 +00001197 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001198 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001199 {
1200 str = desc->cmd;
paul718e3742002-12-13 20:15:29 +00001201
paul909a2152005-03-14 17:41:45 +00001202 if (CMD_VARARG (str))
1203 {
1204 if (match_type < vararg_match)
1205 match_type = vararg_match;
1206 matched++;
1207 }
1208 else if (CMD_RANGE (str))
1209 {
1210 if (cmd_range_match (str, command))
1211 {
1212 if (match_type < range_match)
1213 match_type = range_match;
1214 matched++;
1215 }
1216 }
paul22e0a9e2003-07-11 17:55:46 +00001217#ifdef HAVE_IPV6
paul909a2152005-03-14 17:41:45 +00001218 else if (CMD_IPV6 (str))
1219 {
1220 if (cmd_ipv6_match (command) == exact_match)
1221 {
1222 if (match_type < ipv6_match)
1223 match_type = ipv6_match;
1224 matched++;
1225 }
1226 }
1227 else if (CMD_IPV6_PREFIX (str))
1228 {
1229 if (cmd_ipv6_prefix_match (command) == exact_match)
1230 {
1231 if (match_type < ipv6_prefix_match)
1232 match_type = ipv6_prefix_match;
1233 matched++;
1234 }
1235 }
paul22e0a9e2003-07-11 17:55:46 +00001236#endif /* HAVE_IPV6 */
paul909a2152005-03-14 17:41:45 +00001237 else if (CMD_IPV4 (str))
1238 {
1239 if (cmd_ipv4_match (command) == exact_match)
1240 {
1241 if (match_type < ipv4_match)
1242 match_type = ipv4_match;
1243 matched++;
1244 }
1245 }
1246 else if (CMD_IPV4_PREFIX (str))
1247 {
1248 if (cmd_ipv4_prefix_match (command) == exact_match)
1249 {
1250 if (match_type < ipv4_prefix_match)
1251 match_type = ipv4_prefix_match;
1252 matched++;
1253 }
1254 }
1255 else if (CMD_OPTION (str) || CMD_VARIABLE (str))
1256 {
1257 if (match_type < extend_match)
1258 match_type = extend_match;
1259 matched++;
1260 }
1261 else
1262 {
1263 if (strcmp (command, str) == 0)
1264 {
1265 match_type = exact_match;
1266 matched++;
1267 }
1268 }
1269 }
1270 if (!matched)
paul718e3742002-12-13 20:15:29 +00001271 vector_slot (v, i) = NULL;
1272 }
1273 }
1274 return match_type;
1275}
1276
1277/* Check ambiguous match */
ajs274a4a42004-12-07 15:39:31 +00001278static int
paul718e3742002-12-13 20:15:29 +00001279is_cmd_ambiguous (char *command, vector v, int index, enum match_type type)
1280{
hasso8c328f12004-10-05 21:01:23 +00001281 unsigned int i;
1282 unsigned int j;
1283 const char *str = NULL;
paul718e3742002-12-13 20:15:29 +00001284 struct cmd_element *cmd_element;
hasso8c328f12004-10-05 21:01:23 +00001285 const char *matched = NULL;
paul718e3742002-12-13 20:15:29 +00001286 vector descvec;
1287 struct desc *desc;
paul909a2152005-03-14 17:41:45 +00001288
paul55468c82005-03-14 20:19:01 +00001289 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001290 if ((cmd_element = vector_slot (v, i)) != NULL)
1291 {
1292 int match = 0;
1293
1294 descvec = vector_slot (cmd_element->strvec, index);
1295
paul55468c82005-03-14 20:19:01 +00001296 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001297 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001298 {
1299 enum match_type ret;
1300
1301 str = desc->cmd;
paul718e3742002-12-13 20:15:29 +00001302
paul909a2152005-03-14 17:41:45 +00001303 switch (type)
1304 {
1305 case exact_match:
1306 if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
1307 && strcmp (command, str) == 0)
1308 match++;
1309 break;
1310 case partly_match:
1311 if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
1312 && strncmp (command, str, strlen (command)) == 0)
1313 {
1314 if (matched && strcmp (matched, str) != 0)
1315 return 1; /* There is ambiguous match. */
1316 else
1317 matched = str;
1318 match++;
1319 }
1320 break;
1321 case range_match:
1322 if (cmd_range_match (str, command))
1323 {
1324 if (matched && strcmp (matched, str) != 0)
1325 return 1;
1326 else
1327 matched = str;
1328 match++;
1329 }
1330 break;
1331#ifdef HAVE_IPV6
1332 case ipv6_match:
1333 if (CMD_IPV6 (str))
1334 match++;
1335 break;
1336 case ipv6_prefix_match:
1337 if ((ret = cmd_ipv6_prefix_match (command)) != no_match)
1338 {
1339 if (ret == partly_match)
1340 return 2; /* There is incomplete match. */
paul718e3742002-12-13 20:15:29 +00001341
paul909a2152005-03-14 17:41:45 +00001342 match++;
1343 }
1344 break;
1345#endif /* HAVE_IPV6 */
1346 case ipv4_match:
1347 if (CMD_IPV4 (str))
paul718e3742002-12-13 20:15:29 +00001348 match++;
paul909a2152005-03-14 17:41:45 +00001349 break;
1350 case ipv4_prefix_match:
1351 if ((ret = cmd_ipv4_prefix_match (command)) != no_match)
1352 {
1353 if (ret == partly_match)
1354 return 2; /* There is incomplete match. */
paul718e3742002-12-13 20:15:29 +00001355
paul909a2152005-03-14 17:41:45 +00001356 match++;
1357 }
1358 break;
1359 case extend_match:
1360 if (CMD_OPTION (str) || CMD_VARIABLE (str))
paul718e3742002-12-13 20:15:29 +00001361 match++;
paul909a2152005-03-14 17:41:45 +00001362 break;
1363 case no_match:
1364 default:
1365 break;
1366 }
1367 }
1368 if (!match)
paul718e3742002-12-13 20:15:29 +00001369 vector_slot (v, i) = NULL;
1370 }
1371 return 0;
1372}
1373
1374/* If src matches dst return dst string, otherwise return NULL */
ajs274a4a42004-12-07 15:39:31 +00001375static const char *
hasso8c328f12004-10-05 21:01:23 +00001376cmd_entry_function (const char *src, const char *dst)
paul718e3742002-12-13 20:15:29 +00001377{
1378 /* Skip variable arguments. */
1379 if (CMD_OPTION (dst) || CMD_VARIABLE (dst) || CMD_VARARG (dst) ||
1380 CMD_IPV4 (dst) || CMD_IPV4_PREFIX (dst) || CMD_RANGE (dst))
1381 return NULL;
1382
1383 /* In case of 'command \t', given src is NULL string. */
1384 if (src == NULL)
1385 return dst;
1386
1387 /* Matched with input string. */
1388 if (strncmp (src, dst, strlen (src)) == 0)
1389 return dst;
1390
1391 return NULL;
1392}
1393
1394/* If src matches dst return dst string, otherwise return NULL */
1395/* This version will return the dst string always if it is
1396 CMD_VARIABLE for '?' key processing */
ajs274a4a42004-12-07 15:39:31 +00001397static const char *
hasso8c328f12004-10-05 21:01:23 +00001398cmd_entry_function_desc (const char *src, const char *dst)
paul718e3742002-12-13 20:15:29 +00001399{
1400 if (CMD_VARARG (dst))
1401 return dst;
1402
1403 if (CMD_RANGE (dst))
1404 {
1405 if (cmd_range_match (dst, src))
1406 return dst;
1407 else
1408 return NULL;
1409 }
1410
paul22e0a9e2003-07-11 17:55:46 +00001411#ifdef HAVE_IPV6
paul718e3742002-12-13 20:15:29 +00001412 if (CMD_IPV6 (dst))
1413 {
1414 if (cmd_ipv6_match (src))
1415 return dst;
1416 else
1417 return NULL;
1418 }
1419
1420 if (CMD_IPV6_PREFIX (dst))
1421 {
1422 if (cmd_ipv6_prefix_match (src))
1423 return dst;
1424 else
1425 return NULL;
1426 }
paul22e0a9e2003-07-11 17:55:46 +00001427#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +00001428
1429 if (CMD_IPV4 (dst))
1430 {
1431 if (cmd_ipv4_match (src))
1432 return dst;
1433 else
1434 return NULL;
1435 }
1436
1437 if (CMD_IPV4_PREFIX (dst))
1438 {
1439 if (cmd_ipv4_prefix_match (src))
1440 return dst;
1441 else
1442 return NULL;
1443 }
1444
1445 /* Optional or variable commands always match on '?' */
1446 if (CMD_OPTION (dst) || CMD_VARIABLE (dst))
1447 return dst;
1448
1449 /* In case of 'command \t', given src is NULL string. */
1450 if (src == NULL)
1451 return dst;
1452
1453 if (strncmp (src, dst, strlen (src)) == 0)
1454 return dst;
1455 else
1456 return NULL;
1457}
1458
1459/* Check same string element existence. If it isn't there return
1460 1. */
ajs274a4a42004-12-07 15:39:31 +00001461static int
hasso8c328f12004-10-05 21:01:23 +00001462cmd_unique_string (vector v, const char *str)
paul718e3742002-12-13 20:15:29 +00001463{
hasso8c328f12004-10-05 21:01:23 +00001464 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001465 char *match;
1466
paul55468c82005-03-14 20:19:01 +00001467 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001468 if ((match = vector_slot (v, i)) != NULL)
1469 if (strcmp (match, str) == 0)
1470 return 0;
1471 return 1;
1472}
1473
1474/* Compare string to description vector. If there is same string
1475 return 1 else return 0. */
ajs274a4a42004-12-07 15:39:31 +00001476static int
hasso8c328f12004-10-05 21:01:23 +00001477desc_unique_string (vector v, const char *str)
paul718e3742002-12-13 20:15:29 +00001478{
hasso8c328f12004-10-05 21:01:23 +00001479 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001480 struct desc *desc;
1481
paul55468c82005-03-14 20:19:01 +00001482 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001483 if ((desc = vector_slot (v, i)) != NULL)
1484 if (strcmp (desc->cmd, str) == 0)
1485 return 1;
1486 return 0;
1487}
1488
ajs274a4a42004-12-07 15:39:31 +00001489static int
paulb92938a2002-12-13 21:20:42 +00001490cmd_try_do_shortcut (enum node_type node, char* first_word) {
1491 if ( first_word != NULL &&
1492 node != AUTH_NODE &&
1493 node != VIEW_NODE &&
1494 node != AUTH_ENABLE_NODE &&
1495 node != ENABLE_NODE &&
Paul Jakma62687ff2008-08-23 14:27:06 +01001496 node != RESTRICTED_NODE &&
paulb92938a2002-12-13 21:20:42 +00001497 0 == strcmp( "do", first_word ) )
1498 return 1;
1499 return 0;
1500}
1501
paul718e3742002-12-13 20:15:29 +00001502/* '?' describe command support. */
ajs274a4a42004-12-07 15:39:31 +00001503static vector
paulb92938a2002-12-13 21:20:42 +00001504cmd_describe_command_real (vector vline, struct vty *vty, int *status)
paul718e3742002-12-13 20:15:29 +00001505{
paulb8961472005-03-14 17:35:52 +00001506 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001507 vector cmd_vector;
1508#define INIT_MATCHVEC_SIZE 10
1509 vector matchvec;
1510 struct cmd_element *cmd_element;
paulb8961472005-03-14 17:35:52 +00001511 unsigned int index;
paul54aba542003-08-21 20:28:24 +00001512 int ret;
1513 enum match_type match;
1514 char *command;
paul718e3742002-12-13 20:15:29 +00001515
1516 /* Set index. */
paul55468c82005-03-14 20:19:01 +00001517 if (vector_active (vline) == 0)
paulb8961472005-03-14 17:35:52 +00001518 {
1519 *status = CMD_ERR_NO_MATCH;
1520 return NULL;
1521 }
1522 else
paul55468c82005-03-14 20:19:01 +00001523 index = vector_active (vline) - 1;
paul909a2152005-03-14 17:41:45 +00001524
paul718e3742002-12-13 20:15:29 +00001525 /* Make copy vector of current node's command vector. */
1526 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1527
1528 /* Prepare match vector */
1529 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1530
1531 /* Filter commands. */
paul54aba542003-08-21 20:28:24 +00001532 /* Only words precedes current word will be checked in this loop. */
paul718e3742002-12-13 20:15:29 +00001533 for (i = 0; i < index; i++)
paulb8961472005-03-14 17:35:52 +00001534 if ((command = vector_slot (vline, i)))
paul909a2152005-03-14 17:41:45 +00001535 {
1536 match = cmd_filter_by_completion (command, cmd_vector, i);
1537
1538 if (match == vararg_match)
1539 {
1540 struct cmd_element *cmd_element;
1541 vector descvec;
1542 unsigned int j, k;
paul718e3742002-12-13 20:15:29 +00001543
paul55468c82005-03-14 20:19:01 +00001544 for (j = 0; j < vector_active (cmd_vector); j++)
paulb8961472005-03-14 17:35:52 +00001545 if ((cmd_element = vector_slot (cmd_vector, j)) != NULL
paul55468c82005-03-14 20:19:01 +00001546 && (vector_active (cmd_element->strvec)))
paul909a2152005-03-14 17:41:45 +00001547 {
1548 descvec = vector_slot (cmd_element->strvec,
paul55468c82005-03-14 20:19:01 +00001549 vector_active (cmd_element->strvec) - 1);
1550 for (k = 0; k < vector_active (descvec); k++)
paul909a2152005-03-14 17:41:45 +00001551 {
1552 struct desc *desc = vector_slot (descvec, k);
1553 vector_set (matchvec, desc);
1554 }
1555 }
1556
1557 vector_set (matchvec, &desc_cr);
1558 vector_free (cmd_vector);
paul718e3742002-12-13 20:15:29 +00001559
paul909a2152005-03-14 17:41:45 +00001560 return matchvec;
1561 }
paul718e3742002-12-13 20:15:29 +00001562
paul909a2152005-03-14 17:41:45 +00001563 if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
1564 {
1565 vector_free (cmd_vector);
Paul Jakmae5cd7062006-06-15 12:25:55 +00001566 vector_free (matchvec);
paul909a2152005-03-14 17:41:45 +00001567 *status = CMD_ERR_AMBIGUOUS;
1568 return NULL;
1569 }
1570 else if (ret == 2)
1571 {
1572 vector_free (cmd_vector);
Paul Jakmae5cd7062006-06-15 12:25:55 +00001573 vector_free (matchvec);
paul909a2152005-03-14 17:41:45 +00001574 *status = CMD_ERR_NO_MATCH;
1575 return NULL;
1576 }
1577 }
paul718e3742002-12-13 20:15:29 +00001578
1579 /* Prepare match vector */
1580 /* matchvec = vector_init (INIT_MATCHVEC_SIZE); */
1581
paul54aba542003-08-21 20:28:24 +00001582 /* Make sure that cmd_vector is filtered based on current word */
1583 command = vector_slot (vline, index);
1584 if (command)
1585 match = cmd_filter_by_completion (command, cmd_vector, index);
1586
paul718e3742002-12-13 20:15:29 +00001587 /* Make description vector. */
paul55468c82005-03-14 20:19:01 +00001588 for (i = 0; i < vector_active (cmd_vector); i++)
paul718e3742002-12-13 20:15:29 +00001589 if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
1590 {
paul718e3742002-12-13 20:15:29 +00001591 vector strvec = cmd_element->strvec;
1592
paul55468c82005-03-14 20:19:01 +00001593 /* if command is NULL, index may be equal to vector_active */
1594 if (command && index >= vector_active (strvec))
paul718e3742002-12-13 20:15:29 +00001595 vector_slot (cmd_vector, i) = NULL;
1596 else
1597 {
paul54aba542003-08-21 20:28:24 +00001598 /* Check if command is completed. */
paul55468c82005-03-14 20:19:01 +00001599 if (command == NULL && index == vector_active (strvec))
paul718e3742002-12-13 20:15:29 +00001600 {
Chris Caputo228da422009-07-18 05:44:03 +00001601 if (!desc_unique_string (matchvec, command_cr))
paul718e3742002-12-13 20:15:29 +00001602 vector_set (matchvec, &desc_cr);
1603 }
1604 else
1605 {
hasso8c328f12004-10-05 21:01:23 +00001606 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001607 vector descvec = vector_slot (strvec, index);
1608 struct desc *desc;
1609
paul55468c82005-03-14 20:19:01 +00001610 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001611 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001612 {
Chris Caputo228da422009-07-18 05:44:03 +00001613 const char *string;
1614
paul909a2152005-03-14 17:41:45 +00001615 string = cmd_entry_function_desc (command, desc->cmd);
1616 if (string)
1617 {
1618 /* Uniqueness check */
1619 if (!desc_unique_string (matchvec, string))
1620 vector_set (matchvec, desc);
1621 }
1622 }
paul718e3742002-12-13 20:15:29 +00001623 }
1624 }
1625 }
1626 vector_free (cmd_vector);
1627
1628 if (vector_slot (matchvec, 0) == NULL)
1629 {
1630 vector_free (matchvec);
paul909a2152005-03-14 17:41:45 +00001631 *status = CMD_ERR_NO_MATCH;
Paul Jakma5fc60512006-05-12 23:24:09 +00001632 return NULL;
paul718e3742002-12-13 20:15:29 +00001633 }
paul718e3742002-12-13 20:15:29 +00001634
Paul Jakma5fc60512006-05-12 23:24:09 +00001635 *status = CMD_SUCCESS;
paul718e3742002-12-13 20:15:29 +00001636 return matchvec;
1637}
1638
paulb92938a2002-12-13 21:20:42 +00001639vector
1640cmd_describe_command (vector vline, struct vty *vty, int *status)
1641{
1642 vector ret;
1643
1644 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1645 {
1646 enum node_type onode;
1647 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00001648 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00001649
1650 onode = vty->node;
1651 vty->node = ENABLE_NODE;
1652 /* We can try it on enable node, cos' the vty is authenticated */
1653
1654 shifted_vline = vector_init (vector_count(vline));
1655 /* use memcpy? */
paul55468c82005-03-14 20:19:01 +00001656 for (index = 1; index < vector_active (vline); index++)
paulb92938a2002-12-13 21:20:42 +00001657 {
1658 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1659 }
1660
1661 ret = cmd_describe_command_real (shifted_vline, vty, status);
1662
1663 vector_free(shifted_vline);
1664 vty->node = onode;
1665 return ret;
1666 }
1667
1668
1669 return cmd_describe_command_real (vline, vty, status);
1670}
1671
1672
paul718e3742002-12-13 20:15:29 +00001673/* Check LCD of matched command. */
ajs274a4a42004-12-07 15:39:31 +00001674static int
paul718e3742002-12-13 20:15:29 +00001675cmd_lcd (char **matched)
1676{
1677 int i;
1678 int j;
1679 int lcd = -1;
1680 char *s1, *s2;
1681 char c1, c2;
1682
1683 if (matched[0] == NULL || matched[1] == NULL)
1684 return 0;
1685
1686 for (i = 1; matched[i] != NULL; i++)
1687 {
1688 s1 = matched[i - 1];
1689 s2 = matched[i];
1690
1691 for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
1692 if (c1 != c2)
1693 break;
1694
1695 if (lcd < 0)
1696 lcd = j;
1697 else
1698 {
1699 if (lcd > j)
1700 lcd = j;
1701 }
1702 }
1703 return lcd;
1704}
1705
1706/* Command line completion support. */
ajs274a4a42004-12-07 15:39:31 +00001707static char **
paulb92938a2002-12-13 21:20:42 +00001708cmd_complete_command_real (vector vline, struct vty *vty, int *status)
paul718e3742002-12-13 20:15:29 +00001709{
paulb8961472005-03-14 17:35:52 +00001710 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001711 vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1712#define INIT_MATCHVEC_SIZE 10
1713 vector matchvec;
1714 struct cmd_element *cmd_element;
paulb8961472005-03-14 17:35:52 +00001715 unsigned int index;
paul718e3742002-12-13 20:15:29 +00001716 char **match_str;
1717 struct desc *desc;
1718 vector descvec;
1719 char *command;
1720 int lcd;
1721
paul55468c82005-03-14 20:19:01 +00001722 if (vector_active (vline) == 0)
paulb8961472005-03-14 17:35:52 +00001723 {
Paul Jakmad2519962006-05-12 23:19:37 +00001724 vector_free (cmd_vector);
paulb8961472005-03-14 17:35:52 +00001725 *status = CMD_ERR_NO_MATCH;
1726 return NULL;
1727 }
1728 else
paul55468c82005-03-14 20:19:01 +00001729 index = vector_active (vline) - 1;
paulb8961472005-03-14 17:35:52 +00001730
paul718e3742002-12-13 20:15:29 +00001731 /* First, filter by preceeding command string */
1732 for (i = 0; i < index; i++)
paulb8961472005-03-14 17:35:52 +00001733 if ((command = vector_slot (vline, i)))
paul909a2152005-03-14 17:41:45 +00001734 {
1735 enum match_type match;
1736 int ret;
paul718e3742002-12-13 20:15:29 +00001737
paul909a2152005-03-14 17:41:45 +00001738 /* First try completion match, if there is exactly match return 1 */
1739 match = cmd_filter_by_completion (command, cmd_vector, i);
paul718e3742002-12-13 20:15:29 +00001740
paul909a2152005-03-14 17:41:45 +00001741 /* If there is exact match then filter ambiguous match else check
1742 ambiguousness. */
1743 if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
1744 {
1745 vector_free (cmd_vector);
1746 *status = CMD_ERR_AMBIGUOUS;
1747 return NULL;
1748 }
1749 /*
1750 else if (ret == 2)
1751 {
1752 vector_free (cmd_vector);
1753 *status = CMD_ERR_NO_MATCH;
1754 return NULL;
1755 }
1756 */
1757 }
1758
paul718e3742002-12-13 20:15:29 +00001759 /* Prepare match vector. */
1760 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1761
1762 /* Now we got into completion */
paul55468c82005-03-14 20:19:01 +00001763 for (i = 0; i < vector_active (cmd_vector); i++)
paulb8961472005-03-14 17:35:52 +00001764 if ((cmd_element = vector_slot (cmd_vector, i)))
paul718e3742002-12-13 20:15:29 +00001765 {
hasso8c328f12004-10-05 21:01:23 +00001766 const char *string;
paul718e3742002-12-13 20:15:29 +00001767 vector strvec = cmd_element->strvec;
paul909a2152005-03-14 17:41:45 +00001768
paul718e3742002-12-13 20:15:29 +00001769 /* Check field length */
paul55468c82005-03-14 20:19:01 +00001770 if (index >= vector_active (strvec))
paul718e3742002-12-13 20:15:29 +00001771 vector_slot (cmd_vector, i) = NULL;
paul909a2152005-03-14 17:41:45 +00001772 else
paul718e3742002-12-13 20:15:29 +00001773 {
hasso8c328f12004-10-05 21:01:23 +00001774 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001775
1776 descvec = vector_slot (strvec, index);
paul55468c82005-03-14 20:19:01 +00001777 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001778 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001779 {
paulb8961472005-03-14 17:35:52 +00001780 if ((string =
1781 cmd_entry_function (vector_slot (vline, index),
paul909a2152005-03-14 17:41:45 +00001782 desc->cmd)))
1783 if (cmd_unique_string (matchvec, string))
1784 vector_set (matchvec, XSTRDUP (MTYPE_TMP, string));
1785 }
paul718e3742002-12-13 20:15:29 +00001786 }
1787 }
1788
1789 /* We don't need cmd_vector any more. */
1790 vector_free (cmd_vector);
1791
1792 /* No matched command */
1793 if (vector_slot (matchvec, 0) == NULL)
1794 {
1795 vector_free (matchvec);
1796
1797 /* In case of 'command \t' pattern. Do you need '?' command at
1798 the end of the line. */
1799 if (vector_slot (vline, index) == '\0')
1800 *status = CMD_ERR_NOTHING_TODO;
1801 else
1802 *status = CMD_ERR_NO_MATCH;
1803 return NULL;
1804 }
1805
1806 /* Only one matched */
1807 if (vector_slot (matchvec, 1) == NULL)
1808 {
1809 match_str = (char **) matchvec->index;
1810 vector_only_wrapper_free (matchvec);
1811 *status = CMD_COMPLETE_FULL_MATCH;
1812 return match_str;
1813 }
1814 /* Make it sure last element is NULL. */
1815 vector_set (matchvec, NULL);
1816
1817 /* Check LCD of matched strings. */
1818 if (vector_slot (vline, index) != NULL)
1819 {
1820 lcd = cmd_lcd ((char **) matchvec->index);
1821
1822 if (lcd)
1823 {
1824 int len = strlen (vector_slot (vline, index));
paul909a2152005-03-14 17:41:45 +00001825
paul718e3742002-12-13 20:15:29 +00001826 if (len < lcd)
1827 {
1828 char *lcdstr;
paul909a2152005-03-14 17:41:45 +00001829
paul05865c92005-10-26 05:49:54 +00001830 lcdstr = XMALLOC (MTYPE_STRVEC, lcd + 1);
paul718e3742002-12-13 20:15:29 +00001831 memcpy (lcdstr, matchvec->index[0], lcd);
1832 lcdstr[lcd] = '\0';
1833
1834 /* match_str = (char **) &lcdstr; */
1835
1836 /* Free matchvec. */
paul55468c82005-03-14 20:19:01 +00001837 for (i = 0; i < vector_active (matchvec); i++)
paul718e3742002-12-13 20:15:29 +00001838 {
1839 if (vector_slot (matchvec, i))
paul05865c92005-10-26 05:49:54 +00001840 XFREE (MTYPE_STRVEC, vector_slot (matchvec, i));
paul718e3742002-12-13 20:15:29 +00001841 }
1842 vector_free (matchvec);
1843
paul909a2152005-03-14 17:41:45 +00001844 /* Make new matchvec. */
paul718e3742002-12-13 20:15:29 +00001845 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1846 vector_set (matchvec, lcdstr);
1847 match_str = (char **) matchvec->index;
1848 vector_only_wrapper_free (matchvec);
1849
1850 *status = CMD_COMPLETE_MATCH;
1851 return match_str;
1852 }
1853 }
1854 }
1855
1856 match_str = (char **) matchvec->index;
1857 vector_only_wrapper_free (matchvec);
1858 *status = CMD_COMPLETE_LIST_MATCH;
1859 return match_str;
1860}
1861
paulb92938a2002-12-13 21:20:42 +00001862char **
paul9ab68122003-01-18 01:16:20 +00001863cmd_complete_command (vector vline, struct vty *vty, int *status)
paulb92938a2002-12-13 21:20:42 +00001864{
1865 char **ret;
1866
1867 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1868 {
1869 enum node_type onode;
1870 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00001871 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00001872
1873 onode = vty->node;
1874 vty->node = ENABLE_NODE;
1875 /* We can try it on enable node, cos' the vty is authenticated */
1876
1877 shifted_vline = vector_init (vector_count(vline));
1878 /* use memcpy? */
paul55468c82005-03-14 20:19:01 +00001879 for (index = 1; index < vector_active (vline); index++)
paulb92938a2002-12-13 21:20:42 +00001880 {
1881 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1882 }
1883
1884 ret = cmd_complete_command_real (shifted_vline, vty, status);
1885
1886 vector_free(shifted_vline);
1887 vty->node = onode;
1888 return ret;
1889 }
1890
1891
1892 return cmd_complete_command_real (vline, vty, status);
1893}
1894
1895/* return parent node */
1896/* MUST eventually converge on CONFIG_NODE */
hasso13bfca72005-01-23 21:42:25 +00001897enum node_type
ajs274a4a42004-12-07 15:39:31 +00001898node_parent ( enum node_type node )
paulb92938a2002-12-13 21:20:42 +00001899{
1900 enum node_type ret;
1901
paul9ab68122003-01-18 01:16:20 +00001902 assert (node > CONFIG_NODE);
1903
1904 switch (node)
1905 {
1906 case BGP_VPNV4_NODE:
1907 case BGP_IPV4_NODE:
1908 case BGP_IPV4M_NODE:
1909 case BGP_IPV6_NODE:
paul1e836592005-08-22 22:39:56 +00001910 case BGP_IPV6M_NODE:
paul9ab68122003-01-18 01:16:20 +00001911 ret = BGP_NODE;
1912 break;
1913 case KEYCHAIN_KEY_NODE:
1914 ret = KEYCHAIN_NODE;
1915 break;
1916 default:
1917 ret = CONFIG_NODE;
paulb92938a2002-12-13 21:20:42 +00001918 }
1919
1920 return ret;
1921}
1922
paul718e3742002-12-13 20:15:29 +00001923/* Execute command by argument vline vector. */
ajs274a4a42004-12-07 15:39:31 +00001924static int
paulb8961472005-03-14 17:35:52 +00001925cmd_execute_command_real (vector vline, struct vty *vty,
1926 struct cmd_element **cmd)
paul718e3742002-12-13 20:15:29 +00001927{
hasso8c328f12004-10-05 21:01:23 +00001928 unsigned int i;
1929 unsigned int index;
paul718e3742002-12-13 20:15:29 +00001930 vector cmd_vector;
1931 struct cmd_element *cmd_element;
1932 struct cmd_element *matched_element;
1933 unsigned int matched_count, incomplete_count;
1934 int argc;
paul9035efa2004-10-10 11:56:56 +00001935 const char *argv[CMD_ARGC_MAX];
paul718e3742002-12-13 20:15:29 +00001936 enum match_type match = 0;
1937 int varflag;
1938 char *command;
1939
1940 /* Make copy of command elements. */
1941 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1942
paul55468c82005-03-14 20:19:01 +00001943 for (index = 0; index < vector_active (vline); index++)
paulb8961472005-03-14 17:35:52 +00001944 if ((command = vector_slot (vline, index)))
paul909a2152005-03-14 17:41:45 +00001945 {
1946 int ret;
paul718e3742002-12-13 20:15:29 +00001947
paul909a2152005-03-14 17:41:45 +00001948 match = cmd_filter_by_completion (command, cmd_vector, index);
paul718e3742002-12-13 20:15:29 +00001949
paul909a2152005-03-14 17:41:45 +00001950 if (match == vararg_match)
1951 break;
1952
1953 ret = is_cmd_ambiguous (command, cmd_vector, index, match);
paul718e3742002-12-13 20:15:29 +00001954
paul909a2152005-03-14 17:41:45 +00001955 if (ret == 1)
1956 {
1957 vector_free (cmd_vector);
1958 return CMD_ERR_AMBIGUOUS;
1959 }
1960 else if (ret == 2)
1961 {
1962 vector_free (cmd_vector);
1963 return CMD_ERR_NO_MATCH;
1964 }
1965 }
paul718e3742002-12-13 20:15:29 +00001966
1967 /* Check matched count. */
1968 matched_element = NULL;
1969 matched_count = 0;
1970 incomplete_count = 0;
1971
paul55468c82005-03-14 20:19:01 +00001972 for (i = 0; i < vector_active (cmd_vector); i++)
paulb8961472005-03-14 17:35:52 +00001973 if ((cmd_element = vector_slot (cmd_vector, i)))
paul718e3742002-12-13 20:15:29 +00001974 {
paul718e3742002-12-13 20:15:29 +00001975 if (match == vararg_match || index >= cmd_element->cmdsize)
1976 {
1977 matched_element = cmd_element;
1978#if 0
1979 printf ("DEBUG: %s\n", cmd_element->string);
1980#endif
1981 matched_count++;
1982 }
1983 else
1984 {
1985 incomplete_count++;
1986 }
1987 }
paul909a2152005-03-14 17:41:45 +00001988
paul718e3742002-12-13 20:15:29 +00001989 /* Finish of using cmd_vector. */
1990 vector_free (cmd_vector);
1991
paul909a2152005-03-14 17:41:45 +00001992 /* To execute command, matched_count must be 1. */
1993 if (matched_count == 0)
paul718e3742002-12-13 20:15:29 +00001994 {
1995 if (incomplete_count)
1996 return CMD_ERR_INCOMPLETE;
1997 else
1998 return CMD_ERR_NO_MATCH;
1999 }
2000
paul909a2152005-03-14 17:41:45 +00002001 if (matched_count > 1)
paul718e3742002-12-13 20:15:29 +00002002 return CMD_ERR_AMBIGUOUS;
2003
2004 /* Argument treatment */
2005 varflag = 0;
2006 argc = 0;
2007
paul55468c82005-03-14 20:19:01 +00002008 for (i = 0; i < vector_active (vline); i++)
paul718e3742002-12-13 20:15:29 +00002009 {
2010 if (varflag)
2011 argv[argc++] = vector_slot (vline, i);
2012 else
paul909a2152005-03-14 17:41:45 +00002013 {
paul718e3742002-12-13 20:15:29 +00002014 vector descvec = vector_slot (matched_element->strvec, i);
2015
paul55468c82005-03-14 20:19:01 +00002016 if (vector_active (descvec) == 1)
paul718e3742002-12-13 20:15:29 +00002017 {
2018 struct desc *desc = vector_slot (descvec, 0);
paul718e3742002-12-13 20:15:29 +00002019
hasso8c328f12004-10-05 21:01:23 +00002020 if (CMD_VARARG (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002021 varflag = 1;
2022
hasso8c328f12004-10-05 21:01:23 +00002023 if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002024 argv[argc++] = vector_slot (vline, i);
2025 }
2026 else
2027 argv[argc++] = vector_slot (vline, i);
2028 }
2029
2030 if (argc >= CMD_ARGC_MAX)
2031 return CMD_ERR_EXEED_ARGC_MAX;
2032 }
2033
2034 /* For vtysh execution. */
2035 if (cmd)
2036 *cmd = matched_element;
2037
2038 if (matched_element->daemon)
2039 return CMD_SUCCESS_DAEMON;
2040
2041 /* Execute matched command. */
2042 return (*matched_element->func) (matched_element, vty, argc, argv);
2043}
2044
paulb92938a2002-12-13 21:20:42 +00002045int
hasso87d683b2005-01-16 23:31:54 +00002046cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,
2047 int vtysh) {
paul9ab68122003-01-18 01:16:20 +00002048 int ret, saved_ret, tried = 0;
2049 enum node_type onode, try_node;
2050
2051 onode = try_node = vty->node;
paulb92938a2002-12-13 21:20:42 +00002052
2053 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
2054 {
2055 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00002056 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00002057
2058 vty->node = ENABLE_NODE;
2059 /* We can try it on enable node, cos' the vty is authenticated */
2060
2061 shifted_vline = vector_init (vector_count(vline));
2062 /* use memcpy? */
paul55468c82005-03-14 20:19:01 +00002063 for (index = 1; index < vector_active (vline); index++)
paulb92938a2002-12-13 21:20:42 +00002064 {
2065 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
2066 }
2067
2068 ret = cmd_execute_command_real (shifted_vline, vty, cmd);
2069
2070 vector_free(shifted_vline);
2071 vty->node = onode;
2072 return ret;
2073 }
2074
2075
paul9ab68122003-01-18 01:16:20 +00002076 saved_ret = ret = cmd_execute_command_real (vline, vty, cmd);
paulb92938a2002-12-13 21:20:42 +00002077
hasso87d683b2005-01-16 23:31:54 +00002078 if (vtysh)
2079 return saved_ret;
2080
paulb92938a2002-12-13 21:20:42 +00002081 /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
paul9ab68122003-01-18 01:16:20 +00002082 while ( ret != CMD_SUCCESS && ret != CMD_WARNING
paulb92938a2002-12-13 21:20:42 +00002083 && vty->node > CONFIG_NODE )
2084 {
paul9ab68122003-01-18 01:16:20 +00002085 try_node = node_parent(try_node);
2086 vty->node = try_node;
paulb92938a2002-12-13 21:20:42 +00002087 ret = cmd_execute_command_real (vline, vty, cmd);
paul9ab68122003-01-18 01:16:20 +00002088 tried = 1;
2089 if (ret == CMD_SUCCESS || ret == CMD_WARNING)
paulb92938a2002-12-13 21:20:42 +00002090 {
paul9ab68122003-01-18 01:16:20 +00002091 /* succesfull command, leave the node as is */
paulb92938a2002-12-13 21:20:42 +00002092 return ret;
2093 }
paulb92938a2002-12-13 21:20:42 +00002094 }
paul9ab68122003-01-18 01:16:20 +00002095 /* no command succeeded, reset the vty to the original node and
2096 return the error for this node */
2097 if ( tried )
2098 vty->node = onode;
2099 return saved_ret;
pauleda031f2003-01-18 00:39:19 +00002100}
2101
paul718e3742002-12-13 20:15:29 +00002102/* Execute command by argument readline. */
2103int
paul909a2152005-03-14 17:41:45 +00002104cmd_execute_command_strict (vector vline, struct vty *vty,
paul718e3742002-12-13 20:15:29 +00002105 struct cmd_element **cmd)
2106{
hasso8c328f12004-10-05 21:01:23 +00002107 unsigned int i;
2108 unsigned int index;
paul718e3742002-12-13 20:15:29 +00002109 vector cmd_vector;
2110 struct cmd_element *cmd_element;
2111 struct cmd_element *matched_element;
2112 unsigned int matched_count, incomplete_count;
2113 int argc;
paul9035efa2004-10-10 11:56:56 +00002114 const char *argv[CMD_ARGC_MAX];
paul718e3742002-12-13 20:15:29 +00002115 int varflag;
2116 enum match_type match = 0;
2117 char *command;
2118
2119 /* Make copy of command element */
2120 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2121
paul55468c82005-03-14 20:19:01 +00002122 for (index = 0; index < vector_active (vline); index++)
paulb8961472005-03-14 17:35:52 +00002123 if ((command = vector_slot (vline, index)))
paul909a2152005-03-14 17:41:45 +00002124 {
2125 int ret;
2126
2127 match = cmd_filter_by_string (vector_slot (vline, index),
2128 cmd_vector, index);
paul718e3742002-12-13 20:15:29 +00002129
paul909a2152005-03-14 17:41:45 +00002130 /* If command meets '.VARARG' then finish matching. */
2131 if (match == vararg_match)
2132 break;
2133
2134 ret = is_cmd_ambiguous (command, cmd_vector, index, match);
2135 if (ret == 1)
2136 {
2137 vector_free (cmd_vector);
2138 return CMD_ERR_AMBIGUOUS;
2139 }
2140 if (ret == 2)
2141 {
2142 vector_free (cmd_vector);
2143 return CMD_ERR_NO_MATCH;
2144 }
2145 }
paul718e3742002-12-13 20:15:29 +00002146
2147 /* Check matched count. */
2148 matched_element = NULL;
2149 matched_count = 0;
2150 incomplete_count = 0;
paul55468c82005-03-14 20:19:01 +00002151 for (i = 0; i < vector_active (cmd_vector); i++)
paul909a2152005-03-14 17:41:45 +00002152 if (vector_slot (cmd_vector, i) != NULL)
paul718e3742002-12-13 20:15:29 +00002153 {
paul909a2152005-03-14 17:41:45 +00002154 cmd_element = vector_slot (cmd_vector, i);
paul718e3742002-12-13 20:15:29 +00002155
2156 if (match == vararg_match || index >= cmd_element->cmdsize)
2157 {
2158 matched_element = cmd_element;
2159 matched_count++;
2160 }
2161 else
2162 incomplete_count++;
2163 }
paul909a2152005-03-14 17:41:45 +00002164
paul718e3742002-12-13 20:15:29 +00002165 /* Finish of using cmd_vector. */
2166 vector_free (cmd_vector);
2167
paul909a2152005-03-14 17:41:45 +00002168 /* To execute command, matched_count must be 1. */
2169 if (matched_count == 0)
paul718e3742002-12-13 20:15:29 +00002170 {
2171 if (incomplete_count)
2172 return CMD_ERR_INCOMPLETE;
2173 else
2174 return CMD_ERR_NO_MATCH;
2175 }
2176
paul909a2152005-03-14 17:41:45 +00002177 if (matched_count > 1)
paul718e3742002-12-13 20:15:29 +00002178 return CMD_ERR_AMBIGUOUS;
2179
2180 /* Argument treatment */
2181 varflag = 0;
2182 argc = 0;
2183
paul55468c82005-03-14 20:19:01 +00002184 for (i = 0; i < vector_active (vline); i++)
paul718e3742002-12-13 20:15:29 +00002185 {
2186 if (varflag)
2187 argv[argc++] = vector_slot (vline, i);
2188 else
paul909a2152005-03-14 17:41:45 +00002189 {
paul718e3742002-12-13 20:15:29 +00002190 vector descvec = vector_slot (matched_element->strvec, i);
2191
paul55468c82005-03-14 20:19:01 +00002192 if (vector_active (descvec) == 1)
paul718e3742002-12-13 20:15:29 +00002193 {
2194 struct desc *desc = vector_slot (descvec, 0);
paul718e3742002-12-13 20:15:29 +00002195
hasso8c328f12004-10-05 21:01:23 +00002196 if (CMD_VARARG (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002197 varflag = 1;
paul909a2152005-03-14 17:41:45 +00002198
hasso8c328f12004-10-05 21:01:23 +00002199 if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002200 argv[argc++] = vector_slot (vline, i);
2201 }
2202 else
2203 argv[argc++] = vector_slot (vline, i);
2204 }
2205
2206 if (argc >= CMD_ARGC_MAX)
2207 return CMD_ERR_EXEED_ARGC_MAX;
2208 }
2209
2210 /* For vtysh execution. */
2211 if (cmd)
2212 *cmd = matched_element;
2213
2214 if (matched_element->daemon)
2215 return CMD_SUCCESS_DAEMON;
2216
2217 /* Now execute matched command */
2218 return (*matched_element->func) (matched_element, vty, argc, argv);
2219}
2220
2221/* Configration make from file. */
2222int
2223config_from_file (struct vty *vty, FILE *fp)
2224{
2225 int ret;
2226 vector vline;
2227
2228 while (fgets (vty->buf, VTY_BUFSIZ, fp))
2229 {
2230 vline = cmd_make_strvec (vty->buf);
2231
2232 /* In case of comment line */
2233 if (vline == NULL)
2234 continue;
2235 /* Execute configuration command : this is strict match */
2236 ret = cmd_execute_command_strict (vline, vty, NULL);
2237
2238 /* Try again with setting node to CONFIG_NODE */
paulb92938a2002-12-13 21:20:42 +00002239 while (ret != CMD_SUCCESS && ret != CMD_WARNING
hassoddd85ed2004-10-13 08:18:07 +00002240 && ret != CMD_ERR_NOTHING_TODO && vty->node != CONFIG_NODE)
2241 {
paulb92938a2002-12-13 21:20:42 +00002242 vty->node = node_parent(vty->node);
hassoddd85ed2004-10-13 08:18:07 +00002243 ret = cmd_execute_command_strict (vline, vty, NULL);
2244 }
paul9ab68122003-01-18 01:16:20 +00002245
paul718e3742002-12-13 20:15:29 +00002246 cmd_free_strvec (vline);
2247
hassoddd85ed2004-10-13 08:18:07 +00002248 if (ret != CMD_SUCCESS && ret != CMD_WARNING
2249 && ret != CMD_ERR_NOTHING_TODO)
paul718e3742002-12-13 20:15:29 +00002250 return ret;
2251 }
2252 return CMD_SUCCESS;
2253}
2254
2255/* Configration from terminal */
2256DEFUN (config_terminal,
2257 config_terminal_cmd,
2258 "configure terminal",
2259 "Configuration from vty interface\n"
2260 "Configuration terminal\n")
2261{
2262 if (vty_config_lock (vty))
2263 vty->node = CONFIG_NODE;
2264 else
2265 {
2266 vty_out (vty, "VTY configuration is locked by other VTY%s", VTY_NEWLINE);
2267 return CMD_WARNING;
2268 }
2269 return CMD_SUCCESS;
2270}
2271
2272/* Enable command */
2273DEFUN (enable,
2274 config_enable_cmd,
2275 "enable",
2276 "Turn on privileged mode command\n")
2277{
2278 /* If enable password is NULL, change to ENABLE_NODE */
2279 if ((host.enable == NULL && host.enable_encrypt == NULL) ||
2280 vty->type == VTY_SHELL_SERV)
2281 vty->node = ENABLE_NODE;
2282 else
2283 vty->node = AUTH_ENABLE_NODE;
2284
2285 return CMD_SUCCESS;
2286}
2287
2288/* Disable command */
2289DEFUN (disable,
2290 config_disable_cmd,
2291 "disable",
2292 "Turn off privileged mode command\n")
2293{
2294 if (vty->node == ENABLE_NODE)
2295 vty->node = VIEW_NODE;
2296 return CMD_SUCCESS;
2297}
2298
2299/* Down vty node level. */
2300DEFUN (config_exit,
2301 config_exit_cmd,
2302 "exit",
2303 "Exit current mode and down to previous mode\n")
2304{
2305 switch (vty->node)
2306 {
2307 case VIEW_NODE:
2308 case ENABLE_NODE:
Paul Jakma62687ff2008-08-23 14:27:06 +01002309 case RESTRICTED_NODE:
paul718e3742002-12-13 20:15:29 +00002310 if (vty_shell (vty))
2311 exit (0);
2312 else
2313 vty->status = VTY_CLOSE;
2314 break;
2315 case CONFIG_NODE:
2316 vty->node = ENABLE_NODE;
2317 vty_config_unlock (vty);
2318 break;
2319 case INTERFACE_NODE:
2320 case ZEBRA_NODE:
2321 case BGP_NODE:
2322 case RIP_NODE:
2323 case RIPNG_NODE:
Paul Jakma57345092011-12-25 17:52:09 +01002324 case BABEL_NODE:
paul718e3742002-12-13 20:15:29 +00002325 case OSPF_NODE:
2326 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00002327 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00002328 case KEYCHAIN_NODE:
2329 case MASC_NODE:
2330 case RMAP_NODE:
2331 case VTY_NODE:
2332 vty->node = CONFIG_NODE;
2333 break;
2334 case BGP_VPNV4_NODE:
2335 case BGP_IPV4_NODE:
2336 case BGP_IPV4M_NODE:
2337 case BGP_IPV6_NODE:
paul1e836592005-08-22 22:39:56 +00002338 case BGP_IPV6M_NODE:
paul718e3742002-12-13 20:15:29 +00002339 vty->node = BGP_NODE;
2340 break;
2341 case KEYCHAIN_KEY_NODE:
2342 vty->node = KEYCHAIN_NODE;
2343 break;
2344 default:
2345 break;
2346 }
2347 return CMD_SUCCESS;
2348}
2349
2350/* quit is alias of exit. */
2351ALIAS (config_exit,
2352 config_quit_cmd,
2353 "quit",
2354 "Exit current mode and down to previous mode\n")
2355
2356/* End of configuration. */
2357DEFUN (config_end,
2358 config_end_cmd,
2359 "end",
2360 "End current mode and change to enable mode.")
2361{
2362 switch (vty->node)
2363 {
2364 case VIEW_NODE:
2365 case ENABLE_NODE:
Paul Jakma62687ff2008-08-23 14:27:06 +01002366 case RESTRICTED_NODE:
paul718e3742002-12-13 20:15:29 +00002367 /* Nothing to do. */
2368 break;
2369 case CONFIG_NODE:
2370 case INTERFACE_NODE:
2371 case ZEBRA_NODE:
2372 case RIP_NODE:
2373 case RIPNG_NODE:
Paul Jakma57345092011-12-25 17:52:09 +01002374 case BABEL_NODE:
paul718e3742002-12-13 20:15:29 +00002375 case BGP_NODE:
2376 case BGP_VPNV4_NODE:
2377 case BGP_IPV4_NODE:
2378 case BGP_IPV4M_NODE:
2379 case BGP_IPV6_NODE:
paul1e836592005-08-22 22:39:56 +00002380 case BGP_IPV6M_NODE:
paul718e3742002-12-13 20:15:29 +00002381 case RMAP_NODE:
2382 case OSPF_NODE:
2383 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00002384 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00002385 case KEYCHAIN_NODE:
2386 case KEYCHAIN_KEY_NODE:
2387 case MASC_NODE:
2388 case VTY_NODE:
2389 vty_config_unlock (vty);
2390 vty->node = ENABLE_NODE;
2391 break;
2392 default:
2393 break;
2394 }
2395 return CMD_SUCCESS;
2396}
2397
2398/* Show version. */
2399DEFUN (show_version,
2400 show_version_cmd,
2401 "show version",
2402 SHOW_STR
2403 "Displays zebra version\n")
2404{
hasso12f6ea22005-03-07 08:35:39 +00002405 vty_out (vty, "Quagga %s (%s).%s", QUAGGA_VERSION, host.name?host.name:"",
2406 VTY_NEWLINE);
hasso6590f2c2004-10-19 20:40:08 +00002407 vty_out (vty, "%s%s", QUAGGA_COPYRIGHT, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00002408
2409 return CMD_SUCCESS;
2410}
2411
2412/* Help display function for all node. */
2413DEFUN (config_help,
2414 config_help_cmd,
2415 "help",
2416 "Description of the interactive help system\n")
2417{
2418 vty_out (vty,
hasso6590f2c2004-10-19 20:40:08 +00002419 "Quagga VTY provides advanced help feature. When you need help,%s\
paul718e3742002-12-13 20:15:29 +00002420anytime at the command line please press '?'.%s\
2421%s\
2422If nothing matches, the help list will be empty and you must backup%s\
2423 until entering a '?' shows the available options.%s\
2424Two styles of help are provided:%s\
24251. Full help is available when you are ready to enter a%s\
2426command argument (e.g. 'show ?') and describes each possible%s\
2427argument.%s\
24282. Partial help is provided when an abbreviated argument is entered%s\
2429 and you want to know what arguments match the input%s\
2430 (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2431 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2432 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
2433 return CMD_SUCCESS;
2434}
2435
2436/* Help display function for all node. */
2437DEFUN (config_list,
2438 config_list_cmd,
2439 "list",
2440 "Print command list\n")
2441{
hasso8c328f12004-10-05 21:01:23 +00002442 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002443 struct cmd_node *cnode = vector_slot (cmdvec, vty->node);
2444 struct cmd_element *cmd;
2445
paul55468c82005-03-14 20:19:01 +00002446 for (i = 0; i < vector_active (cnode->cmd_vector); i++)
paul4275b1d2005-03-09 13:42:23 +00002447 if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL
2448 && !(cmd->attr == CMD_ATTR_DEPRECATED
2449 || cmd->attr == CMD_ATTR_HIDDEN))
paul718e3742002-12-13 20:15:29 +00002450 vty_out (vty, " %s%s", cmd->string,
2451 VTY_NEWLINE);
2452 return CMD_SUCCESS;
2453}
2454
2455/* Write current configuration into file. */
2456DEFUN (config_write_file,
2457 config_write_file_cmd,
2458 "write file",
2459 "Write running configuration to memory, network, or terminal\n"
2460 "Write to configuration file\n")
2461{
hasso8c328f12004-10-05 21:01:23 +00002462 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002463 int fd;
2464 struct cmd_node *node;
2465 char *config_file;
2466 char *config_file_tmp = NULL;
2467 char *config_file_sav = NULL;
paul05865c92005-10-26 05:49:54 +00002468 int ret = CMD_WARNING;
paul718e3742002-12-13 20:15:29 +00002469 struct vty *file_vty;
2470
2471 /* Check and see if we are operating under vtysh configuration */
2472 if (host.config == NULL)
2473 {
2474 vty_out (vty, "Can't save to configuration file, using vtysh.%s",
2475 VTY_NEWLINE);
2476 return CMD_WARNING;
2477 }
2478
2479 /* Get filename. */
2480 config_file = host.config;
2481
paul05865c92005-10-26 05:49:54 +00002482 config_file_sav =
2483 XMALLOC (MTYPE_TMP, strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
paul718e3742002-12-13 20:15:29 +00002484 strcpy (config_file_sav, config_file);
2485 strcat (config_file_sav, CONF_BACKUP_EXT);
2486
2487
paul05865c92005-10-26 05:49:54 +00002488 config_file_tmp = XMALLOC (MTYPE_TMP, strlen (config_file) + 8);
paul718e3742002-12-13 20:15:29 +00002489 sprintf (config_file_tmp, "%s.XXXXXX", config_file);
2490
2491 /* Open file to configuration write. */
2492 fd = mkstemp (config_file_tmp);
2493 if (fd < 0)
2494 {
2495 vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
2496 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002497 goto finished;
paul718e3742002-12-13 20:15:29 +00002498 }
2499
2500 /* Make vty for configuration file. */
2501 file_vty = vty_new ();
2502 file_vty->fd = fd;
2503 file_vty->type = VTY_FILE;
2504
2505 /* Config file header print. */
2506 vty_out (file_vty, "!\n! Zebra configuration saved from vty\n! ");
2507 vty_time_print (file_vty, 1);
2508 vty_out (file_vty, "!\n");
2509
paul55468c82005-03-14 20:19:01 +00002510 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +00002511 if ((node = vector_slot (cmdvec, i)) && node->func)
2512 {
2513 if ((*node->func) (file_vty))
2514 vty_out (file_vty, "!\n");
2515 }
2516 vty_close (file_vty);
2517
2518 if (unlink (config_file_sav) != 0)
2519 if (errno != ENOENT)
2520 {
2521 vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
2522 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002523 goto finished;
paul718e3742002-12-13 20:15:29 +00002524 }
2525 if (link (config_file, config_file_sav) != 0)
2526 {
2527 vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
2528 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002529 goto finished;
paul718e3742002-12-13 20:15:29 +00002530 }
2531 sync ();
2532 if (unlink (config_file) != 0)
2533 {
2534 vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
2535 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002536 goto finished;
paul718e3742002-12-13 20:15:29 +00002537 }
2538 if (link (config_file_tmp, config_file) != 0)
2539 {
2540 vty_out (vty, "Can't save configuration file %s.%s", config_file,
2541 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002542 goto finished;
paul718e3742002-12-13 20:15:29 +00002543 }
paul718e3742002-12-13 20:15:29 +00002544 sync ();
2545
gdtaa593d52003-12-22 20:15:53 +00002546 if (chmod (config_file, CONFIGFILE_MASK) != 0)
2547 {
2548 vty_out (vty, "Can't chmod configuration file %s: %s (%d).%s",
ajs6099b3b2004-11-20 02:06:59 +00002549 config_file, safe_strerror(errno), errno, VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002550 goto finished;
gdtaa593d52003-12-22 20:15:53 +00002551 }
2552
paul718e3742002-12-13 20:15:29 +00002553 vty_out (vty, "Configuration saved to %s%s", config_file,
2554 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002555 ret = CMD_SUCCESS;
2556
2557finished:
2558 unlink (config_file_tmp);
2559 XFREE (MTYPE_TMP, config_file_tmp);
2560 XFREE (MTYPE_TMP, config_file_sav);
2561 return ret;
paul718e3742002-12-13 20:15:29 +00002562}
2563
2564ALIAS (config_write_file,
2565 config_write_cmd,
2566 "write",
2567 "Write running configuration to memory, network, or terminal\n")
2568
2569ALIAS (config_write_file,
2570 config_write_memory_cmd,
2571 "write memory",
2572 "Write running configuration to memory, network, or terminal\n"
2573 "Write configuration to the file (same as write file)\n")
2574
2575ALIAS (config_write_file,
2576 copy_runningconfig_startupconfig_cmd,
2577 "copy running-config startup-config",
2578 "Copy configuration\n"
2579 "Copy running config to... \n"
2580 "Copy running config to startup config (same as write file)\n")
2581
2582/* Write current configuration into the terminal. */
2583DEFUN (config_write_terminal,
2584 config_write_terminal_cmd,
2585 "write terminal",
2586 "Write running configuration to memory, network, or terminal\n"
2587 "Write to terminal\n")
2588{
hasso8c328f12004-10-05 21:01:23 +00002589 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002590 struct cmd_node *node;
2591
2592 if (vty->type == VTY_SHELL_SERV)
2593 {
paul55468c82005-03-14 20:19:01 +00002594 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +00002595 if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
2596 {
2597 if ((*node->func) (vty))
2598 vty_out (vty, "!%s", VTY_NEWLINE);
2599 }
2600 }
2601 else
2602 {
2603 vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
2604 VTY_NEWLINE);
2605 vty_out (vty, "!%s", VTY_NEWLINE);
2606
paul55468c82005-03-14 20:19:01 +00002607 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +00002608 if ((node = vector_slot (cmdvec, i)) && node->func)
2609 {
2610 if ((*node->func) (vty))
2611 vty_out (vty, "!%s", VTY_NEWLINE);
2612 }
2613 vty_out (vty, "end%s",VTY_NEWLINE);
2614 }
2615 return CMD_SUCCESS;
2616}
2617
2618/* Write current configuration into the terminal. */
2619ALIAS (config_write_terminal,
2620 show_running_config_cmd,
2621 "show running-config",
2622 SHOW_STR
2623 "running configuration\n")
2624
2625/* Write startup configuration into the terminal. */
2626DEFUN (show_startup_config,
2627 show_startup_config_cmd,
2628 "show startup-config",
2629 SHOW_STR
2630 "Contentes of startup configuration\n")
2631{
2632 char buf[BUFSIZ];
2633 FILE *confp;
2634
2635 confp = fopen (host.config, "r");
2636 if (confp == NULL)
2637 {
2638 vty_out (vty, "Can't open configuration file [%s]%s",
2639 host.config, VTY_NEWLINE);
2640 return CMD_WARNING;
2641 }
2642
2643 while (fgets (buf, BUFSIZ, confp))
2644 {
2645 char *cp = buf;
2646
2647 while (*cp != '\r' && *cp != '\n' && *cp != '\0')
2648 cp++;
2649 *cp = '\0';
2650
2651 vty_out (vty, "%s%s", buf, VTY_NEWLINE);
2652 }
2653
2654 fclose (confp);
2655
2656 return CMD_SUCCESS;
2657}
2658
2659/* Hostname configuration */
2660DEFUN (config_hostname,
2661 hostname_cmd,
2662 "hostname WORD",
2663 "Set system's network name\n"
2664 "This system's network name\n")
2665{
2666 if (!isalpha((int) *argv[0]))
2667 {
2668 vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
2669 return CMD_WARNING;
2670 }
2671
2672 if (host.name)
paul05865c92005-10-26 05:49:54 +00002673 XFREE (MTYPE_HOST, host.name);
paul718e3742002-12-13 20:15:29 +00002674
paul05865c92005-10-26 05:49:54 +00002675 host.name = XSTRDUP (MTYPE_HOST, argv[0]);
paul718e3742002-12-13 20:15:29 +00002676 return CMD_SUCCESS;
2677}
2678
2679DEFUN (config_no_hostname,
2680 no_hostname_cmd,
2681 "no hostname [HOSTNAME]",
2682 NO_STR
2683 "Reset system's network name\n"
2684 "Host name of this router\n")
2685{
2686 if (host.name)
paul05865c92005-10-26 05:49:54 +00002687 XFREE (MTYPE_HOST, host.name);
paul718e3742002-12-13 20:15:29 +00002688 host.name = NULL;
2689 return CMD_SUCCESS;
2690}
2691
2692/* VTY interface password set. */
2693DEFUN (config_password, password_cmd,
2694 "password (8|) WORD",
2695 "Assign the terminal connection password\n"
2696 "Specifies a HIDDEN password will follow\n"
2697 "dummy string \n"
2698 "The HIDDEN line password string\n")
2699{
2700 /* Argument check. */
2701 if (argc == 0)
2702 {
2703 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2704 return CMD_WARNING;
2705 }
2706
2707 if (argc == 2)
2708 {
2709 if (*argv[0] == '8')
2710 {
2711 if (host.password)
paul05865c92005-10-26 05:49:54 +00002712 XFREE (MTYPE_HOST, host.password);
paul718e3742002-12-13 20:15:29 +00002713 host.password = NULL;
2714 if (host.password_encrypt)
paul05865c92005-10-26 05:49:54 +00002715 XFREE (MTYPE_HOST, host.password_encrypt);
2716 host.password_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
paul718e3742002-12-13 20:15:29 +00002717 return CMD_SUCCESS;
2718 }
2719 else
2720 {
2721 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2722 return CMD_WARNING;
2723 }
2724 }
2725
2726 if (!isalnum ((int) *argv[0]))
2727 {
2728 vty_out (vty,
2729 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2730 return CMD_WARNING;
2731 }
2732
2733 if (host.password)
paul05865c92005-10-26 05:49:54 +00002734 XFREE (MTYPE_HOST, host.password);
paul718e3742002-12-13 20:15:29 +00002735 host.password = NULL;
2736
2737 if (host.encrypt)
2738 {
2739 if (host.password_encrypt)
paul05865c92005-10-26 05:49:54 +00002740 XFREE (MTYPE_HOST, host.password_encrypt);
2741 host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
paul718e3742002-12-13 20:15:29 +00002742 }
2743 else
paul05865c92005-10-26 05:49:54 +00002744 host.password = XSTRDUP (MTYPE_HOST, argv[0]);
paul718e3742002-12-13 20:15:29 +00002745
2746 return CMD_SUCCESS;
2747}
2748
2749ALIAS (config_password, password_text_cmd,
2750 "password LINE",
2751 "Assign the terminal connection password\n"
2752 "The UNENCRYPTED (cleartext) line password\n")
2753
2754/* VTY enable password set. */
2755DEFUN (config_enable_password, enable_password_cmd,
2756 "enable password (8|) WORD",
2757 "Modify enable password parameters\n"
2758 "Assign the privileged level password\n"
2759 "Specifies a HIDDEN password will follow\n"
2760 "dummy string \n"
2761 "The HIDDEN 'enable' password string\n")
2762{
2763 /* Argument check. */
2764 if (argc == 0)
2765 {
2766 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2767 return CMD_WARNING;
2768 }
2769
2770 /* Crypt type is specified. */
2771 if (argc == 2)
2772 {
2773 if (*argv[0] == '8')
2774 {
2775 if (host.enable)
paul05865c92005-10-26 05:49:54 +00002776 XFREE (MTYPE_HOST, host.enable);
paul718e3742002-12-13 20:15:29 +00002777 host.enable = NULL;
2778
2779 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002780 XFREE (MTYPE_HOST, host.enable_encrypt);
2781 host.enable_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
paul718e3742002-12-13 20:15:29 +00002782
2783 return CMD_SUCCESS;
2784 }
2785 else
2786 {
2787 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2788 return CMD_WARNING;
2789 }
2790 }
2791
2792 if (!isalnum ((int) *argv[0]))
2793 {
2794 vty_out (vty,
2795 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2796 return CMD_WARNING;
2797 }
2798
2799 if (host.enable)
paul05865c92005-10-26 05:49:54 +00002800 XFREE (MTYPE_HOST, host.enable);
paul718e3742002-12-13 20:15:29 +00002801 host.enable = NULL;
2802
2803 /* Plain password input. */
2804 if (host.encrypt)
2805 {
2806 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002807 XFREE (MTYPE_HOST, host.enable_encrypt);
2808 host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
paul718e3742002-12-13 20:15:29 +00002809 }
2810 else
paul05865c92005-10-26 05:49:54 +00002811 host.enable = XSTRDUP (MTYPE_HOST, argv[0]);
paul718e3742002-12-13 20:15:29 +00002812
2813 return CMD_SUCCESS;
2814}
2815
2816ALIAS (config_enable_password,
2817 enable_password_text_cmd,
2818 "enable password LINE",
2819 "Modify enable password parameters\n"
2820 "Assign the privileged level password\n"
2821 "The UNENCRYPTED (cleartext) 'enable' password\n")
2822
2823/* VTY enable password delete. */
2824DEFUN (no_config_enable_password, no_enable_password_cmd,
2825 "no enable password",
2826 NO_STR
2827 "Modify enable password parameters\n"
2828 "Assign the privileged level password\n")
2829{
2830 if (host.enable)
paul05865c92005-10-26 05:49:54 +00002831 XFREE (MTYPE_HOST, host.enable);
paul718e3742002-12-13 20:15:29 +00002832 host.enable = NULL;
2833
2834 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002835 XFREE (MTYPE_HOST, host.enable_encrypt);
paul718e3742002-12-13 20:15:29 +00002836 host.enable_encrypt = NULL;
2837
2838 return CMD_SUCCESS;
2839}
2840
2841DEFUN (service_password_encrypt,
2842 service_password_encrypt_cmd,
2843 "service password-encryption",
2844 "Set up miscellaneous service\n"
2845 "Enable encrypted passwords\n")
2846{
2847 if (host.encrypt)
2848 return CMD_SUCCESS;
2849
2850 host.encrypt = 1;
2851
2852 if (host.password)
2853 {
2854 if (host.password_encrypt)
paul05865c92005-10-26 05:49:54 +00002855 XFREE (MTYPE_HOST, host.password_encrypt);
2856 host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.password));
paul718e3742002-12-13 20:15:29 +00002857 }
2858 if (host.enable)
2859 {
2860 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002861 XFREE (MTYPE_HOST, host.enable_encrypt);
2862 host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.enable));
paul718e3742002-12-13 20:15:29 +00002863 }
2864
2865 return CMD_SUCCESS;
2866}
2867
2868DEFUN (no_service_password_encrypt,
2869 no_service_password_encrypt_cmd,
2870 "no service password-encryption",
2871 NO_STR
2872 "Set up miscellaneous service\n"
2873 "Enable encrypted passwords\n")
2874{
2875 if (! host.encrypt)
2876 return CMD_SUCCESS;
2877
2878 host.encrypt = 0;
2879
2880 if (host.password_encrypt)
paul05865c92005-10-26 05:49:54 +00002881 XFREE (MTYPE_HOST, host.password_encrypt);
paul718e3742002-12-13 20:15:29 +00002882 host.password_encrypt = NULL;
2883
2884 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002885 XFREE (MTYPE_HOST, host.enable_encrypt);
paul718e3742002-12-13 20:15:29 +00002886 host.enable_encrypt = NULL;
2887
2888 return CMD_SUCCESS;
2889}
2890
2891DEFUN (config_terminal_length, config_terminal_length_cmd,
2892 "terminal length <0-512>",
2893 "Set terminal line parameters\n"
2894 "Set number of lines on a screen\n"
2895 "Number of lines on screen (0 for no pausing)\n")
2896{
2897 int lines;
2898 char *endptr = NULL;
2899
2900 lines = strtol (argv[0], &endptr, 10);
2901 if (lines < 0 || lines > 512 || *endptr != '\0')
2902 {
2903 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2904 return CMD_WARNING;
2905 }
2906 vty->lines = lines;
2907
2908 return CMD_SUCCESS;
2909}
2910
2911DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
2912 "terminal no length",
2913 "Set terminal line parameters\n"
2914 NO_STR
2915 "Set number of lines on a screen\n")
2916{
2917 vty->lines = -1;
2918 return CMD_SUCCESS;
2919}
2920
2921DEFUN (service_terminal_length, service_terminal_length_cmd,
2922 "service terminal-length <0-512>",
2923 "Set up miscellaneous service\n"
2924 "System wide terminal length configuration\n"
2925 "Number of lines of VTY (0 means no line control)\n")
2926{
2927 int lines;
2928 char *endptr = NULL;
2929
2930 lines = strtol (argv[0], &endptr, 10);
2931 if (lines < 0 || lines > 512 || *endptr != '\0')
2932 {
2933 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2934 return CMD_WARNING;
2935 }
2936 host.lines = lines;
2937
2938 return CMD_SUCCESS;
2939}
2940
2941DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
2942 "no service terminal-length [<0-512>]",
2943 NO_STR
2944 "Set up miscellaneous service\n"
2945 "System wide terminal length configuration\n"
2946 "Number of lines of VTY (0 means no line control)\n")
2947{
2948 host.lines = -1;
2949 return CMD_SUCCESS;
2950}
2951
ajs2885f722004-12-17 23:16:33 +00002952DEFUN_HIDDEN (do_echo,
2953 echo_cmd,
2954 "echo .MESSAGE",
2955 "Echo a message back to the vty\n"
2956 "The message to echo\n")
2957{
2958 char *message;
2959
ajsf6834d42005-01-28 20:28:35 +00002960 vty_out (vty, "%s%s", ((message = argv_concat(argv, argc, 0)) ? message : ""),
2961 VTY_NEWLINE);
2962 if (message)
2963 XFREE(MTYPE_TMP, message);
ajs2885f722004-12-17 23:16:33 +00002964 return CMD_SUCCESS;
2965}
2966
ajs274a4a42004-12-07 15:39:31 +00002967DEFUN (config_logmsg,
2968 config_logmsg_cmd,
2969 "logmsg "LOG_LEVELS" .MESSAGE",
2970 "Send a message to enabled logging destinations\n"
2971 LOG_LEVEL_DESC
2972 "The message to send\n")
2973{
2974 int level;
2975 char *message;
2976
2977 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
2978 return CMD_ERR_NO_MATCH;
2979
Christian Hammersfc951862011-03-23 13:07:55 +03002980 zlog(NULL, level, "%s", ((message = argv_concat(argv, argc, 1)) ? message : ""));
ajsf6834d42005-01-28 20:28:35 +00002981 if (message)
2982 XFREE(MTYPE_TMP, message);
ajs274a4a42004-12-07 15:39:31 +00002983 return CMD_SUCCESS;
2984}
2985
2986DEFUN (show_logging,
2987 show_logging_cmd,
2988 "show logging",
2989 SHOW_STR
2990 "Show current logging configuration\n")
2991{
2992 struct zlog *zl = zlog_default;
2993
2994 vty_out (vty, "Syslog logging: ");
2995 if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED)
2996 vty_out (vty, "disabled");
2997 else
2998 vty_out (vty, "level %s, facility %s, ident %s",
2999 zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]],
3000 facility_name(zl->facility), zl->ident);
3001 vty_out (vty, "%s", VTY_NEWLINE);
3002
3003 vty_out (vty, "Stdout logging: ");
3004 if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED)
3005 vty_out (vty, "disabled");
3006 else
3007 vty_out (vty, "level %s",
3008 zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
3009 vty_out (vty, "%s", VTY_NEWLINE);
3010
3011 vty_out (vty, "Monitor logging: ");
3012 if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
3013 vty_out (vty, "disabled");
3014 else
3015 vty_out (vty, "level %s",
3016 zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
3017 vty_out (vty, "%s", VTY_NEWLINE);
3018
3019 vty_out (vty, "File logging: ");
3020 if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) ||
3021 !zl->fp)
3022 vty_out (vty, "disabled");
3023 else
3024 vty_out (vty, "level %s, filename %s",
3025 zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
3026 zl->filename);
3027 vty_out (vty, "%s", VTY_NEWLINE);
3028
3029 vty_out (vty, "Protocol name: %s%s",
3030 zlog_proto_names[zl->protocol], VTY_NEWLINE);
3031 vty_out (vty, "Record priority: %s%s",
3032 (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE);
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +00003033 vty_out (vty, "Timestamp precision: %d%s",
3034 zl->timestamp_precision, VTY_NEWLINE);
ajs274a4a42004-12-07 15:39:31 +00003035
3036 return CMD_SUCCESS;
3037}
3038
paul718e3742002-12-13 20:15:29 +00003039DEFUN (config_log_stdout,
3040 config_log_stdout_cmd,
3041 "log stdout",
3042 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003043 "Set stdout logging level\n")
paul718e3742002-12-13 20:15:29 +00003044{
ajs274a4a42004-12-07 15:39:31 +00003045 zlog_set_level (NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl);
3046 return CMD_SUCCESS;
3047}
3048
3049DEFUN (config_log_stdout_level,
3050 config_log_stdout_level_cmd,
3051 "log stdout "LOG_LEVELS,
3052 "Logging control\n"
3053 "Set stdout logging level\n"
3054 LOG_LEVEL_DESC)
3055{
3056 int level;
3057
3058 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3059 return CMD_ERR_NO_MATCH;
3060 zlog_set_level (NULL, ZLOG_DEST_STDOUT, level);
paul718e3742002-12-13 20:15:29 +00003061 return CMD_SUCCESS;
3062}
3063
3064DEFUN (no_config_log_stdout,
3065 no_config_log_stdout_cmd,
ajs274a4a42004-12-07 15:39:31 +00003066 "no log stdout [LEVEL]",
paul718e3742002-12-13 20:15:29 +00003067 NO_STR
3068 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003069 "Cancel logging to stdout\n"
3070 "Logging level\n")
paul718e3742002-12-13 20:15:29 +00003071{
ajs274a4a42004-12-07 15:39:31 +00003072 zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED);
paul718e3742002-12-13 20:15:29 +00003073 return CMD_SUCCESS;
3074}
3075
ajs274a4a42004-12-07 15:39:31 +00003076DEFUN (config_log_monitor,
3077 config_log_monitor_cmd,
3078 "log monitor",
paul718e3742002-12-13 20:15:29 +00003079 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003080 "Set terminal line (monitor) logging level\n")
3081{
3082 zlog_set_level (NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl);
3083 return CMD_SUCCESS;
3084}
3085
3086DEFUN (config_log_monitor_level,
3087 config_log_monitor_level_cmd,
3088 "log monitor "LOG_LEVELS,
3089 "Logging control\n"
3090 "Set terminal line (monitor) logging level\n"
3091 LOG_LEVEL_DESC)
3092{
3093 int level;
3094
3095 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3096 return CMD_ERR_NO_MATCH;
3097 zlog_set_level (NULL, ZLOG_DEST_MONITOR, level);
3098 return CMD_SUCCESS;
3099}
3100
3101DEFUN (no_config_log_monitor,
3102 no_config_log_monitor_cmd,
3103 "no log monitor [LEVEL]",
3104 NO_STR
3105 "Logging control\n"
3106 "Disable terminal line (monitor) logging\n"
3107 "Logging level\n")
3108{
3109 zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
3110 return CMD_SUCCESS;
3111}
3112
3113static int
3114set_log_file(struct vty *vty, const char *fname, int loglevel)
paul718e3742002-12-13 20:15:29 +00003115{
3116 int ret;
paul9035efa2004-10-10 11:56:56 +00003117 char *p = NULL;
3118 const char *fullpath;
3119
paul718e3742002-12-13 20:15:29 +00003120 /* Path detection. */
ajs274a4a42004-12-07 15:39:31 +00003121 if (! IS_DIRECTORY_SEP (*fname))
paul718e3742002-12-13 20:15:29 +00003122 {
paul9035efa2004-10-10 11:56:56 +00003123 char cwd[MAXPATHLEN+1];
3124 cwd[MAXPATHLEN] = '\0';
3125
3126 if (getcwd (cwd, MAXPATHLEN) == NULL)
3127 {
3128 zlog_err ("config_log_file: Unable to alloc mem!");
3129 return CMD_WARNING;
3130 }
3131
ajs274a4a42004-12-07 15:39:31 +00003132 if ( (p = XMALLOC (MTYPE_TMP, strlen (cwd) + strlen (fname) + 2))
paul9035efa2004-10-10 11:56:56 +00003133 == NULL)
3134 {
3135 zlog_err ("config_log_file: Unable to alloc mem!");
3136 return CMD_WARNING;
3137 }
ajs274a4a42004-12-07 15:39:31 +00003138 sprintf (p, "%s/%s", cwd, fname);
paul9035efa2004-10-10 11:56:56 +00003139 fullpath = p;
paul718e3742002-12-13 20:15:29 +00003140 }
3141 else
ajs274a4a42004-12-07 15:39:31 +00003142 fullpath = fname;
paul718e3742002-12-13 20:15:29 +00003143
ajs274a4a42004-12-07 15:39:31 +00003144 ret = zlog_set_file (NULL, fullpath, loglevel);
paul718e3742002-12-13 20:15:29 +00003145
paul9035efa2004-10-10 11:56:56 +00003146 if (p)
3147 XFREE (MTYPE_TMP, p);
3148
paul718e3742002-12-13 20:15:29 +00003149 if (!ret)
3150 {
ajs274a4a42004-12-07 15:39:31 +00003151 vty_out (vty, "can't open logfile %s\n", fname);
paul718e3742002-12-13 20:15:29 +00003152 return CMD_WARNING;
3153 }
3154
3155 if (host.logfile)
paul05865c92005-10-26 05:49:54 +00003156 XFREE (MTYPE_HOST, host.logfile);
paul718e3742002-12-13 20:15:29 +00003157
paul05865c92005-10-26 05:49:54 +00003158 host.logfile = XSTRDUP (MTYPE_HOST, fname);
paul718e3742002-12-13 20:15:29 +00003159
3160 return CMD_SUCCESS;
3161}
3162
ajs274a4a42004-12-07 15:39:31 +00003163DEFUN (config_log_file,
3164 config_log_file_cmd,
3165 "log file FILENAME",
3166 "Logging control\n"
3167 "Logging to file\n"
3168 "Logging filename\n")
3169{
3170 return set_log_file(vty, argv[0], zlog_default->default_lvl);
3171}
3172
3173DEFUN (config_log_file_level,
3174 config_log_file_level_cmd,
3175 "log file FILENAME "LOG_LEVELS,
3176 "Logging control\n"
3177 "Logging to file\n"
3178 "Logging filename\n"
3179 LOG_LEVEL_DESC)
3180{
3181 int level;
3182
3183 if ((level = level_match(argv[1])) == ZLOG_DISABLED)
3184 return CMD_ERR_NO_MATCH;
3185 return set_log_file(vty, argv[0], level);
3186}
3187
paul718e3742002-12-13 20:15:29 +00003188DEFUN (no_config_log_file,
3189 no_config_log_file_cmd,
3190 "no log file [FILENAME]",
3191 NO_STR
3192 "Logging control\n"
3193 "Cancel logging to file\n"
3194 "Logging file name\n")
3195{
3196 zlog_reset_file (NULL);
3197
3198 if (host.logfile)
paul05865c92005-10-26 05:49:54 +00003199 XFREE (MTYPE_HOST, host.logfile);
paul718e3742002-12-13 20:15:29 +00003200
3201 host.logfile = NULL;
3202
3203 return CMD_SUCCESS;
3204}
3205
ajs274a4a42004-12-07 15:39:31 +00003206ALIAS (no_config_log_file,
3207 no_config_log_file_level_cmd,
3208 "no log file FILENAME LEVEL",
3209 NO_STR
3210 "Logging control\n"
3211 "Cancel logging to file\n"
3212 "Logging file name\n"
3213 "Logging level\n")
3214
paul718e3742002-12-13 20:15:29 +00003215DEFUN (config_log_syslog,
3216 config_log_syslog_cmd,
3217 "log syslog",
3218 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003219 "Set syslog logging level\n")
paul718e3742002-12-13 20:15:29 +00003220{
ajs274a4a42004-12-07 15:39:31 +00003221 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
paul12ab19f2003-07-26 06:14:55 +00003222 return CMD_SUCCESS;
3223}
3224
ajs274a4a42004-12-07 15:39:31 +00003225DEFUN (config_log_syslog_level,
3226 config_log_syslog_level_cmd,
3227 "log syslog "LOG_LEVELS,
paul12ab19f2003-07-26 06:14:55 +00003228 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003229 "Set syslog logging level\n"
3230 LOG_LEVEL_DESC)
paul12ab19f2003-07-26 06:14:55 +00003231{
ajs274a4a42004-12-07 15:39:31 +00003232 int level;
paul12ab19f2003-07-26 06:14:55 +00003233
ajs274a4a42004-12-07 15:39:31 +00003234 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3235 return CMD_ERR_NO_MATCH;
3236 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, level);
3237 return CMD_SUCCESS;
3238}
paul12ab19f2003-07-26 06:14:55 +00003239
ajs274a4a42004-12-07 15:39:31 +00003240DEFUN_DEPRECATED (config_log_syslog_facility,
3241 config_log_syslog_facility_cmd,
3242 "log syslog facility "LOG_FACILITIES,
3243 "Logging control\n"
3244 "Logging goes to syslog\n"
3245 "(Deprecated) Facility parameter for syslog messages\n"
3246 LOG_FACILITY_DESC)
3247{
3248 int facility;
paul12ab19f2003-07-26 06:14:55 +00003249
ajs274a4a42004-12-07 15:39:31 +00003250 if ((facility = facility_match(argv[0])) < 0)
3251 return CMD_ERR_NO_MATCH;
3252
3253 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
paul12ab19f2003-07-26 06:14:55 +00003254 zlog_default->facility = facility;
paul718e3742002-12-13 20:15:29 +00003255 return CMD_SUCCESS;
3256}
3257
3258DEFUN (no_config_log_syslog,
3259 no_config_log_syslog_cmd,
ajs274a4a42004-12-07 15:39:31 +00003260 "no log syslog [LEVEL]",
paul718e3742002-12-13 20:15:29 +00003261 NO_STR
3262 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003263 "Cancel logging to syslog\n"
3264 "Logging level\n")
paul718e3742002-12-13 20:15:29 +00003265{
ajs274a4a42004-12-07 15:39:31 +00003266 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
paul718e3742002-12-13 20:15:29 +00003267 return CMD_SUCCESS;
3268}
3269
paul12ab19f2003-07-26 06:14:55 +00003270ALIAS (no_config_log_syslog,
3271 no_config_log_syslog_facility_cmd,
ajs274a4a42004-12-07 15:39:31 +00003272 "no log syslog facility "LOG_FACILITIES,
paul12ab19f2003-07-26 06:14:55 +00003273 NO_STR
3274 "Logging control\n"
3275 "Logging goes to syslog\n"
3276 "Facility parameter for syslog messages\n"
ajs274a4a42004-12-07 15:39:31 +00003277 LOG_FACILITY_DESC)
paul12ab19f2003-07-26 06:14:55 +00003278
ajs274a4a42004-12-07 15:39:31 +00003279DEFUN (config_log_facility,
3280 config_log_facility_cmd,
3281 "log facility "LOG_FACILITIES,
paul718e3742002-12-13 20:15:29 +00003282 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003283 "Facility parameter for syslog messages\n"
3284 LOG_FACILITY_DESC)
paul718e3742002-12-13 20:15:29 +00003285{
ajs274a4a42004-12-07 15:39:31 +00003286 int facility;
3287
3288 if ((facility = facility_match(argv[0])) < 0)
3289 return CMD_ERR_NO_MATCH;
3290 zlog_default->facility = facility;
3291 return CMD_SUCCESS;
paul718e3742002-12-13 20:15:29 +00003292}
3293
ajs274a4a42004-12-07 15:39:31 +00003294DEFUN (no_config_log_facility,
3295 no_config_log_facility_cmd,
3296 "no log facility [FACILITY]",
paul718e3742002-12-13 20:15:29 +00003297 NO_STR
3298 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003299 "Reset syslog facility to default (daemon)\n"
3300 "Syslog facility\n")
paul718e3742002-12-13 20:15:29 +00003301{
ajs274a4a42004-12-07 15:39:31 +00003302 zlog_default->facility = LOG_DAEMON;
3303 return CMD_SUCCESS;
3304}
3305
3306DEFUN_DEPRECATED (config_log_trap,
3307 config_log_trap_cmd,
3308 "log trap "LOG_LEVELS,
3309 "Logging control\n"
3310 "(Deprecated) Set logging level and default for all destinations\n"
3311 LOG_LEVEL_DESC)
3312{
3313 int new_level ;
3314 int i;
3315
3316 if ((new_level = level_match(argv[0])) == ZLOG_DISABLED)
3317 return CMD_ERR_NO_MATCH;
3318
3319 zlog_default->default_lvl = new_level;
3320 for (i = 0; i < ZLOG_NUM_DESTS; i++)
3321 if (zlog_default->maxlvl[i] != ZLOG_DISABLED)
3322 zlog_default->maxlvl[i] = new_level;
3323 return CMD_SUCCESS;
3324}
3325
3326DEFUN_DEPRECATED (no_config_log_trap,
3327 no_config_log_trap_cmd,
3328 "no log trap [LEVEL]",
3329 NO_STR
3330 "Logging control\n"
3331 "Permit all logging information\n"
3332 "Logging level\n")
3333{
3334 zlog_default->default_lvl = LOG_DEBUG;
paul718e3742002-12-13 20:15:29 +00003335 return CMD_SUCCESS;
3336}
3337
3338DEFUN (config_log_record_priority,
3339 config_log_record_priority_cmd,
3340 "log record-priority",
3341 "Logging control\n"
3342 "Log the priority of the message within the message\n")
3343{
3344 zlog_default->record_priority = 1 ;
3345 return CMD_SUCCESS;
3346}
3347
3348DEFUN (no_config_log_record_priority,
3349 no_config_log_record_priority_cmd,
3350 "no log record-priority",
3351 NO_STR
3352 "Logging control\n"
3353 "Do not log the priority of the message within the message\n")
3354{
3355 zlog_default->record_priority = 0 ;
3356 return CMD_SUCCESS;
3357}
3358
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +00003359DEFUN (config_log_timestamp_precision,
3360 config_log_timestamp_precision_cmd,
3361 "log timestamp precision <0-6>",
3362 "Logging control\n"
3363 "Timestamp configuration\n"
3364 "Set the timestamp precision\n"
3365 "Number of subsecond digits\n")
3366{
3367 if (argc != 1)
3368 {
3369 vty_out (vty, "Insufficient arguments%s", VTY_NEWLINE);
3370 return CMD_WARNING;
3371 }
3372
3373 VTY_GET_INTEGER_RANGE("Timestamp Precision",
3374 zlog_default->timestamp_precision, argv[0], 0, 6);
3375 return CMD_SUCCESS;
3376}
3377
3378DEFUN (no_config_log_timestamp_precision,
3379 no_config_log_timestamp_precision_cmd,
3380 "no log timestamp precision",
3381 NO_STR
3382 "Logging control\n"
3383 "Timestamp configuration\n"
3384 "Reset the timestamp precision to the default value of 0\n")
3385{
3386 zlog_default->timestamp_precision = 0 ;
3387 return CMD_SUCCESS;
3388}
3389
paul3b0c5d92005-03-08 10:43:43 +00003390DEFUN (banner_motd_file,
3391 banner_motd_file_cmd,
3392 "banner motd file [FILE]",
3393 "Set banner\n"
3394 "Banner for motd\n"
3395 "Banner from a file\n"
3396 "Filename\n")
3397{
paulb45da6f2005-03-08 15:16:57 +00003398 if (host.motdfile)
paul05865c92005-10-26 05:49:54 +00003399 XFREE (MTYPE_HOST, host.motdfile);
3400 host.motdfile = XSTRDUP (MTYPE_HOST, argv[0]);
paulb45da6f2005-03-08 15:16:57 +00003401
paul3b0c5d92005-03-08 10:43:43 +00003402 return CMD_SUCCESS;
3403}
paul718e3742002-12-13 20:15:29 +00003404
3405DEFUN (banner_motd_default,
3406 banner_motd_default_cmd,
3407 "banner motd default",
3408 "Set banner string\n"
3409 "Strings for motd\n"
3410 "Default string\n")
3411{
3412 host.motd = default_motd;
3413 return CMD_SUCCESS;
3414}
3415
3416DEFUN (no_banner_motd,
3417 no_banner_motd_cmd,
3418 "no banner motd",
3419 NO_STR
3420 "Set banner string\n"
3421 "Strings for motd\n")
3422{
3423 host.motd = NULL;
paul22085182005-03-08 16:00:12 +00003424 if (host.motdfile)
paul05865c92005-10-26 05:49:54 +00003425 XFREE (MTYPE_HOST, host.motdfile);
paul3b0c5d92005-03-08 10:43:43 +00003426 host.motdfile = NULL;
paul718e3742002-12-13 20:15:29 +00003427 return CMD_SUCCESS;
3428}
3429
3430/* Set config filename. Called from vty.c */
3431void
3432host_config_set (char *filename)
3433{
Chris Caputo228da422009-07-18 05:44:03 +00003434 if (host.config)
3435 XFREE (MTYPE_HOST, host.config);
paul05865c92005-10-26 05:49:54 +00003436 host.config = XSTRDUP (MTYPE_HOST, filename);
paul718e3742002-12-13 20:15:29 +00003437}
3438
3439void
3440install_default (enum node_type node)
3441{
3442 install_element (node, &config_exit_cmd);
3443 install_element (node, &config_quit_cmd);
3444 install_element (node, &config_end_cmd);
3445 install_element (node, &config_help_cmd);
3446 install_element (node, &config_list_cmd);
3447
3448 install_element (node, &config_write_terminal_cmd);
3449 install_element (node, &config_write_file_cmd);
3450 install_element (node, &config_write_memory_cmd);
3451 install_element (node, &config_write_cmd);
3452 install_element (node, &show_running_config_cmd);
3453}
3454
3455/* Initialize command interface. Install basic nodes and commands. */
3456void
3457cmd_init (int terminal)
3458{
Chris Caputo228da422009-07-18 05:44:03 +00003459 command_cr = XSTRDUP(MTYPE_STRVEC, "<cr>");
3460 desc_cr.cmd = command_cr;
3461 desc_cr.str = XSTRDUP(MTYPE_STRVEC, "");
3462
paul718e3742002-12-13 20:15:29 +00003463 /* Allocate initial top vector of commands. */
3464 cmdvec = vector_init (VECTOR_MIN_SIZE);
3465
3466 /* Default host value settings. */
3467 host.name = NULL;
3468 host.password = NULL;
3469 host.enable = NULL;
3470 host.logfile = NULL;
3471 host.config = NULL;
3472 host.lines = -1;
3473 host.motd = default_motd;
paul3b0c5d92005-03-08 10:43:43 +00003474 host.motdfile = NULL;
paul718e3742002-12-13 20:15:29 +00003475
3476 /* Install top nodes. */
3477 install_node (&view_node, NULL);
3478 install_node (&enable_node, NULL);
3479 install_node (&auth_node, NULL);
3480 install_node (&auth_enable_node, NULL);
Paul Jakma62687ff2008-08-23 14:27:06 +01003481 install_node (&restricted_node, NULL);
paul718e3742002-12-13 20:15:29 +00003482 install_node (&config_node, config_write_host);
3483
3484 /* Each node's basic commands. */
3485 install_element (VIEW_NODE, &show_version_cmd);
3486 if (terminal)
3487 {
3488 install_element (VIEW_NODE, &config_list_cmd);
3489 install_element (VIEW_NODE, &config_exit_cmd);
3490 install_element (VIEW_NODE, &config_quit_cmd);
3491 install_element (VIEW_NODE, &config_help_cmd);
3492 install_element (VIEW_NODE, &config_enable_cmd);
3493 install_element (VIEW_NODE, &config_terminal_length_cmd);
3494 install_element (VIEW_NODE, &config_terminal_no_length_cmd);
ajs274a4a42004-12-07 15:39:31 +00003495 install_element (VIEW_NODE, &show_logging_cmd);
ajs2885f722004-12-17 23:16:33 +00003496 install_element (VIEW_NODE, &echo_cmd);
Paul Jakma62687ff2008-08-23 14:27:06 +01003497
3498 install_element (RESTRICTED_NODE, &config_list_cmd);
3499 install_element (RESTRICTED_NODE, &config_exit_cmd);
3500 install_element (RESTRICTED_NODE, &config_quit_cmd);
3501 install_element (RESTRICTED_NODE, &config_help_cmd);
3502 install_element (RESTRICTED_NODE, &config_enable_cmd);
3503 install_element (RESTRICTED_NODE, &config_terminal_length_cmd);
3504 install_element (RESTRICTED_NODE, &config_terminal_no_length_cmd);
3505 install_element (RESTRICTED_NODE, &echo_cmd);
paul718e3742002-12-13 20:15:29 +00003506 }
3507
3508 if (terminal)
3509 {
3510 install_default (ENABLE_NODE);
3511 install_element (ENABLE_NODE, &config_disable_cmd);
3512 install_element (ENABLE_NODE, &config_terminal_cmd);
3513 install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
3514 }
3515 install_element (ENABLE_NODE, &show_startup_config_cmd);
3516 install_element (ENABLE_NODE, &show_version_cmd);
paul718e3742002-12-13 20:15:29 +00003517
3518 if (terminal)
paul718e3742002-12-13 20:15:29 +00003519 {
hassoe7168df2004-10-03 20:11:32 +00003520 install_element (ENABLE_NODE, &config_terminal_length_cmd);
3521 install_element (ENABLE_NODE, &config_terminal_no_length_cmd);
ajs274a4a42004-12-07 15:39:31 +00003522 install_element (ENABLE_NODE, &show_logging_cmd);
ajs2885f722004-12-17 23:16:33 +00003523 install_element (ENABLE_NODE, &echo_cmd);
ajs274a4a42004-12-07 15:39:31 +00003524 install_element (ENABLE_NODE, &config_logmsg_cmd);
hassoe7168df2004-10-03 20:11:32 +00003525
3526 install_default (CONFIG_NODE);
hassoea8e9d92004-10-07 21:32:14 +00003527 }
3528
3529 install_element (CONFIG_NODE, &hostname_cmd);
3530 install_element (CONFIG_NODE, &no_hostname_cmd);
hassoe7168df2004-10-03 20:11:32 +00003531
hassoea8e9d92004-10-07 21:32:14 +00003532 if (terminal)
3533 {
hassoe7168df2004-10-03 20:11:32 +00003534 install_element (CONFIG_NODE, &password_cmd);
3535 install_element (CONFIG_NODE, &password_text_cmd);
3536 install_element (CONFIG_NODE, &enable_password_cmd);
3537 install_element (CONFIG_NODE, &enable_password_text_cmd);
3538 install_element (CONFIG_NODE, &no_enable_password_cmd);
3539
paul718e3742002-12-13 20:15:29 +00003540 install_element (CONFIG_NODE, &config_log_stdout_cmd);
ajs274a4a42004-12-07 15:39:31 +00003541 install_element (CONFIG_NODE, &config_log_stdout_level_cmd);
paul718e3742002-12-13 20:15:29 +00003542 install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
ajs274a4a42004-12-07 15:39:31 +00003543 install_element (CONFIG_NODE, &config_log_monitor_cmd);
3544 install_element (CONFIG_NODE, &config_log_monitor_level_cmd);
3545 install_element (CONFIG_NODE, &no_config_log_monitor_cmd);
paul718e3742002-12-13 20:15:29 +00003546 install_element (CONFIG_NODE, &config_log_file_cmd);
ajs274a4a42004-12-07 15:39:31 +00003547 install_element (CONFIG_NODE, &config_log_file_level_cmd);
paul718e3742002-12-13 20:15:29 +00003548 install_element (CONFIG_NODE, &no_config_log_file_cmd);
ajs274a4a42004-12-07 15:39:31 +00003549 install_element (CONFIG_NODE, &no_config_log_file_level_cmd);
paul718e3742002-12-13 20:15:29 +00003550 install_element (CONFIG_NODE, &config_log_syslog_cmd);
ajs274a4a42004-12-07 15:39:31 +00003551 install_element (CONFIG_NODE, &config_log_syslog_level_cmd);
paul12ab19f2003-07-26 06:14:55 +00003552 install_element (CONFIG_NODE, &config_log_syslog_facility_cmd);
paul718e3742002-12-13 20:15:29 +00003553 install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
paul12ab19f2003-07-26 06:14:55 +00003554 install_element (CONFIG_NODE, &no_config_log_syslog_facility_cmd);
ajs274a4a42004-12-07 15:39:31 +00003555 install_element (CONFIG_NODE, &config_log_facility_cmd);
3556 install_element (CONFIG_NODE, &no_config_log_facility_cmd);
paul718e3742002-12-13 20:15:29 +00003557 install_element (CONFIG_NODE, &config_log_trap_cmd);
3558 install_element (CONFIG_NODE, &no_config_log_trap_cmd);
3559 install_element (CONFIG_NODE, &config_log_record_priority_cmd);
3560 install_element (CONFIG_NODE, &no_config_log_record_priority_cmd);
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +00003561 install_element (CONFIG_NODE, &config_log_timestamp_precision_cmd);
3562 install_element (CONFIG_NODE, &no_config_log_timestamp_precision_cmd);
paul718e3742002-12-13 20:15:29 +00003563 install_element (CONFIG_NODE, &service_password_encrypt_cmd);
3564 install_element (CONFIG_NODE, &no_service_password_encrypt_cmd);
3565 install_element (CONFIG_NODE, &banner_motd_default_cmd);
paul3b0c5d92005-03-08 10:43:43 +00003566 install_element (CONFIG_NODE, &banner_motd_file_cmd);
paul718e3742002-12-13 20:15:29 +00003567 install_element (CONFIG_NODE, &no_banner_motd_cmd);
3568 install_element (CONFIG_NODE, &service_terminal_length_cmd);
3569 install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
paul718e3742002-12-13 20:15:29 +00003570
paul354d1192005-04-25 16:26:42 +00003571 install_element (VIEW_NODE, &show_thread_cpu_cmd);
3572 install_element (ENABLE_NODE, &show_thread_cpu_cmd);
Paul Jakma62687ff2008-08-23 14:27:06 +01003573 install_element (RESTRICTED_NODE, &show_thread_cpu_cmd);
Paul Jakmae276eb82010-01-09 16:15:00 +00003574
3575 install_element (ENABLE_NODE, &clear_thread_cpu_cmd);
paul354d1192005-04-25 16:26:42 +00003576 install_element (VIEW_NODE, &show_work_queues_cmd);
3577 install_element (ENABLE_NODE, &show_work_queues_cmd);
paul9ab68122003-01-18 01:16:20 +00003578 }
paul718e3742002-12-13 20:15:29 +00003579 srand(time(NULL));
3580}
Chris Caputo228da422009-07-18 05:44:03 +00003581
3582void
3583cmd_terminate ()
3584{
3585 unsigned int i, j, k, l;
3586 struct cmd_node *cmd_node;
3587 struct cmd_element *cmd_element;
3588 struct desc *desc;
3589 vector cmd_node_v, cmd_element_v, desc_v;
3590
3591 if (cmdvec)
3592 {
3593 for (i = 0; i < vector_active (cmdvec); i++)
3594 if ((cmd_node = vector_slot (cmdvec, i)) != NULL)
3595 {
3596 cmd_node_v = cmd_node->cmd_vector;
3597
3598 for (j = 0; j < vector_active (cmd_node_v); j++)
3599 if ((cmd_element = vector_slot (cmd_node_v, j)) != NULL &&
3600 cmd_element->strvec != NULL)
3601 {
3602 cmd_element_v = cmd_element->strvec;
3603
3604 for (k = 0; k < vector_active (cmd_element_v); k++)
3605 if ((desc_v = vector_slot (cmd_element_v, k)) != NULL)
3606 {
3607 for (l = 0; l < vector_active (desc_v); l++)
3608 if ((desc = vector_slot (desc_v, l)) != NULL)
3609 {
3610 if (desc->cmd)
3611 XFREE (MTYPE_STRVEC, desc->cmd);
3612 if (desc->str)
3613 XFREE (MTYPE_STRVEC, desc->str);
3614
3615 XFREE (MTYPE_DESC, desc);
3616 }
3617 vector_free (desc_v);
3618 }
3619
3620 cmd_element->strvec = NULL;
3621 vector_free (cmd_element_v);
3622 }
3623
3624 vector_free (cmd_node_v);
3625 }
3626
3627 vector_free (cmdvec);
3628 cmdvec = NULL;
3629 }
3630
3631 if (command_cr)
3632 XFREE(MTYPE_STRVEC, command_cr);
3633 if (desc_cr.str)
3634 XFREE(MTYPE_STRVEC, desc_cr.str);
3635 if (host.name)
3636 XFREE (MTYPE_HOST, host.name);
3637 if (host.password)
3638 XFREE (MTYPE_HOST, host.password);
3639 if (host.password_encrypt)
3640 XFREE (MTYPE_HOST, host.password_encrypt);
3641 if (host.enable)
3642 XFREE (MTYPE_HOST, host.enable);
3643 if (host.enable_encrypt)
3644 XFREE (MTYPE_HOST, host.enable_encrypt);
3645 if (host.logfile)
3646 XFREE (MTYPE_HOST, host.logfile);
3647 if (host.motdfile)
3648 XFREE (MTYPE_HOST, host.motdfile);
3649 if (host.config)
3650 XFREE (MTYPE_HOST, host.config);
3651}