blob: 4887f94fbddfb09b775cafc49b052efa310265c8 [file] [log] [blame]
ajs274a4a42004-12-07 15:39:31 +00001/*
Paul Jakmae5cd7062006-06-15 12:25:55 +00002 $Id$
paul9e92eea2005-03-09 13:39:26 +00003
ajs274a4a42004-12-07 15:39:31 +00004 Command interpreter routine for virtual terminal [aka TeletYpe]
paul718e3742002-12-13 20:15:29 +00005 Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
6
7This file is part of GNU Zebra.
8
9GNU Zebra is free software; you can redistribute it and/or modify
10it under the terms of the GNU General Public License as published
11by the Free Software Foundation; either version 2, or (at your
12option) any later version.
13
14GNU Zebra is distributed in the hope that it will be useful, but
15WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with GNU Zebra; see the file COPYING. If not, write to the
21Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22Boston, MA 02111-1307, USA. */
23
24#include <zebra.h>
25
paulb21b19c2003-06-15 01:28:29 +000026
paul718e3742002-12-13 20:15:29 +000027#include "memory.h"
28#include "log.h"
gdt5e4fa162004-03-16 14:38:36 +000029#include <lib/version.h>
paul9ab68122003-01-18 01:16:20 +000030#include "thread.h"
paulb21b19c2003-06-15 01:28:29 +000031#include "vector.h"
32#include "vty.h"
33#include "command.h"
paul354d1192005-04-25 16:26:42 +000034#include "workqueue.h"
paul718e3742002-12-13 20:15:29 +000035
36/* Command vector which includes some level of command lists. Normally
37 each daemon maintains each own cmdvec. */
pauleb820af2005-09-05 11:54:13 +000038vector cmdvec = NULL;
paul718e3742002-12-13 20:15:29 +000039
40/* Host information structure. */
41struct host host;
42
paul718e3742002-12-13 20:15:29 +000043/* Standard command node structures. */
44struct cmd_node auth_node =
45{
46 AUTH_NODE,
47 "Password: ",
48};
49
50struct cmd_node view_node =
51{
52 VIEW_NODE,
53 "%s> ",
54};
55
Paul Jakma62687ff2008-08-23 14:27:06 +010056struct cmd_node restricted_node =
57{
58 RESTRICTED_NODE,
59 "%s$ ",
60};
61
paul718e3742002-12-13 20:15:29 +000062struct cmd_node auth_enable_node =
63{
64 AUTH_ENABLE_NODE,
65 "Password: ",
66};
67
68struct cmd_node enable_node =
69{
70 ENABLE_NODE,
71 "%s# ",
72};
73
74struct cmd_node config_node =
75{
76 CONFIG_NODE,
77 "%s(config)# ",
78 1
79};
hasso6590f2c2004-10-19 20:40:08 +000080
81/* Default motd string. */
82const char *default_motd =
83"\r\n\
84Hello, this is " QUAGGA_PROGNAME " (version " QUAGGA_VERSION ").\r\n\
85" QUAGGA_COPYRIGHT "\r\n\
86\r\n";
87
ajs274a4a42004-12-07 15:39:31 +000088
89static struct facility_map {
90 int facility;
91 const char *name;
92 size_t match;
93} syslog_facilities[] =
94 {
95 { LOG_KERN, "kern", 1 },
96 { LOG_USER, "user", 2 },
97 { LOG_MAIL, "mail", 1 },
98 { LOG_DAEMON, "daemon", 1 },
99 { LOG_AUTH, "auth", 1 },
100 { LOG_SYSLOG, "syslog", 1 },
101 { LOG_LPR, "lpr", 2 },
102 { LOG_NEWS, "news", 1 },
103 { LOG_UUCP, "uucp", 2 },
104 { LOG_CRON, "cron", 1 },
105#ifdef LOG_FTP
106 { LOG_FTP, "ftp", 1 },
107#endif
108 { LOG_LOCAL0, "local0", 6 },
109 { LOG_LOCAL1, "local1", 6 },
110 { LOG_LOCAL2, "local2", 6 },
111 { LOG_LOCAL3, "local3", 6 },
112 { LOG_LOCAL4, "local4", 6 },
113 { LOG_LOCAL5, "local5", 6 },
114 { LOG_LOCAL6, "local6", 6 },
115 { LOG_LOCAL7, "local7", 6 },
116 { 0, NULL, 0 },
117 };
118
119static const char *
120facility_name(int facility)
121{
122 struct facility_map *fm;
123
124 for (fm = syslog_facilities; fm->name; fm++)
125 if (fm->facility == facility)
126 return fm->name;
127 return "";
128}
129
130static int
131facility_match(const char *str)
132{
133 struct facility_map *fm;
134
135 for (fm = syslog_facilities; fm->name; fm++)
136 if (!strncmp(str,fm->name,fm->match))
137 return fm->facility;
138 return -1;
139}
140
141static int
142level_match(const char *s)
143{
144 int level ;
145
146 for ( level = 0 ; zlog_priority [level] != NULL ; level ++ )
147 if (!strncmp (s, zlog_priority[level], 2))
148 return level;
149 return ZLOG_DISABLED;
150}
151
ajscb585b62005-01-14 17:09:38 +0000152/* This is called from main when a daemon is invoked with -v or --version. */
hasso6590f2c2004-10-19 20:40:08 +0000153void
154print_version (const char *progname)
155{
ajscb585b62005-01-14 17:09:38 +0000156 printf ("%s version %s\n", progname, QUAGGA_VERSION);
157 printf ("%s\n", QUAGGA_COPYRIGHT);
hasso6590f2c2004-10-19 20:40:08 +0000158}
159
paul718e3742002-12-13 20:15:29 +0000160
161/* Utility function to concatenate argv argument into a single string
162 with inserting ' ' character between each argument. */
163char *
paul42d49862004-10-13 05:22:18 +0000164argv_concat (const char **argv, int argc, int shift)
paul718e3742002-12-13 20:15:29 +0000165{
166 int i;
ajsf6834d42005-01-28 20:28:35 +0000167 size_t len;
paul718e3742002-12-13 20:15:29 +0000168 char *str;
ajsf6834d42005-01-28 20:28:35 +0000169 char *p;
paul718e3742002-12-13 20:15:29 +0000170
ajsf6834d42005-01-28 20:28:35 +0000171 len = 0;
172 for (i = shift; i < argc; i++)
173 len += strlen(argv[i])+1;
174 if (!len)
175 return NULL;
176 p = str = XMALLOC(MTYPE_TMP, len);
paul718e3742002-12-13 20:15:29 +0000177 for (i = shift; i < argc; i++)
178 {
ajsf6834d42005-01-28 20:28:35 +0000179 size_t arglen;
180 memcpy(p, argv[i], (arglen = strlen(argv[i])));
181 p += arglen;
182 *p++ = ' ';
paul718e3742002-12-13 20:15:29 +0000183 }
ajsf6834d42005-01-28 20:28:35 +0000184 *(p-1) = '\0';
paul718e3742002-12-13 20:15:29 +0000185 return str;
186}
187
188/* Install top node of command vector. */
189void
190install_node (struct cmd_node *node,
191 int (*func) (struct vty *))
192{
193 vector_set_index (cmdvec, node->node, node);
194 node->func = func;
195 node->cmd_vector = vector_init (VECTOR_MIN_SIZE);
196}
197
198/* Compare two command's string. Used in sort_node (). */
ajs274a4a42004-12-07 15:39:31 +0000199static int
paul718e3742002-12-13 20:15:29 +0000200cmp_node (const void *p, const void *q)
201{
paul8cc41982005-05-06 21:25:49 +0000202 const struct cmd_element *a = *(struct cmd_element **)p;
203 const struct cmd_element *b = *(struct cmd_element **)q;
paul718e3742002-12-13 20:15:29 +0000204
205 return strcmp (a->string, b->string);
206}
207
ajs274a4a42004-12-07 15:39:31 +0000208static int
paul718e3742002-12-13 20:15:29 +0000209cmp_desc (const void *p, const void *q)
210{
paul8cc41982005-05-06 21:25:49 +0000211 const struct desc *a = *(struct desc **)p;
212 const struct desc *b = *(struct desc **)q;
paul718e3742002-12-13 20:15:29 +0000213
214 return strcmp (a->cmd, b->cmd);
215}
216
217/* Sort each node's command element according to command string. */
218void
219sort_node ()
220{
hasso8c328f12004-10-05 21:01:23 +0000221 unsigned int i, j;
paul718e3742002-12-13 20:15:29 +0000222 struct cmd_node *cnode;
223 vector descvec;
224 struct cmd_element *cmd_element;
225
paul55468c82005-03-14 20:19:01 +0000226 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +0000227 if ((cnode = vector_slot (cmdvec, i)) != NULL)
228 {
229 vector cmd_vector = cnode->cmd_vector;
paul55468c82005-03-14 20:19:01 +0000230 qsort (cmd_vector->index, vector_active (cmd_vector),
paulb8961472005-03-14 17:35:52 +0000231 sizeof (void *), cmp_node);
paul718e3742002-12-13 20:15:29 +0000232
paul55468c82005-03-14 20:19:01 +0000233 for (j = 0; j < vector_active (cmd_vector); j++)
paulb8961472005-03-14 17:35:52 +0000234 if ((cmd_element = vector_slot (cmd_vector, j)) != NULL
paul55468c82005-03-14 20:19:01 +0000235 && vector_active (cmd_element->strvec))
paul718e3742002-12-13 20:15:29 +0000236 {
237 descvec = vector_slot (cmd_element->strvec,
paul55468c82005-03-14 20:19:01 +0000238 vector_active (cmd_element->strvec) - 1);
239 qsort (descvec->index, vector_active (descvec),
paulb8961472005-03-14 17:35:52 +0000240 sizeof (void *), cmp_desc);
paul718e3742002-12-13 20:15:29 +0000241 }
242 }
243}
244
245/* Breaking up string into each command piece. I assume given
246 character is separated by a space character. Return value is a
247 vector which includes char ** data element. */
248vector
hassoea8e9d92004-10-07 21:32:14 +0000249cmd_make_strvec (const char *string)
paul718e3742002-12-13 20:15:29 +0000250{
hassoea8e9d92004-10-07 21:32:14 +0000251 const char *cp, *start;
252 char *token;
paul718e3742002-12-13 20:15:29 +0000253 int strlen;
254 vector strvec;
255
256 if (string == NULL)
257 return NULL;
258
259 cp = string;
260
261 /* Skip white spaces. */
262 while (isspace ((int) *cp) && *cp != '\0')
263 cp++;
264
265 /* Return if there is only white spaces */
266 if (*cp == '\0')
267 return NULL;
268
269 if (*cp == '!' || *cp == '#')
270 return NULL;
271
272 /* Prepare return vector. */
273 strvec = vector_init (VECTOR_MIN_SIZE);
274
275 /* Copy each command piece and set into vector. */
276 while (1)
277 {
278 start = cp;
279 while (!(isspace ((int) *cp) || *cp == '\r' || *cp == '\n') &&
280 *cp != '\0')
281 cp++;
282 strlen = cp - start;
283 token = XMALLOC (MTYPE_STRVEC, strlen + 1);
284 memcpy (token, start, strlen);
285 *(token + strlen) = '\0';
286 vector_set (strvec, token);
287
288 while ((isspace ((int) *cp) || *cp == '\n' || *cp == '\r') &&
289 *cp != '\0')
290 cp++;
291
292 if (*cp == '\0')
293 return strvec;
294 }
295}
296
297/* Free allocated string vector. */
298void
299cmd_free_strvec (vector v)
300{
hasso8c328f12004-10-05 21:01:23 +0000301 unsigned int i;
paul718e3742002-12-13 20:15:29 +0000302 char *cp;
303
304 if (!v)
305 return;
306
paul55468c82005-03-14 20:19:01 +0000307 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +0000308 if ((cp = vector_slot (v, i)) != NULL)
309 XFREE (MTYPE_STRVEC, cp);
310
311 vector_free (v);
312}
313
314/* Fetch next description. Used in cmd_make_descvec(). */
ajs274a4a42004-12-07 15:39:31 +0000315static char *
hasso6ad96ea2004-10-07 19:33:46 +0000316cmd_desc_str (const char **string)
paul718e3742002-12-13 20:15:29 +0000317{
hasso6ad96ea2004-10-07 19:33:46 +0000318 const char *cp, *start;
319 char *token;
paul718e3742002-12-13 20:15:29 +0000320 int strlen;
321
322 cp = *string;
323
324 if (cp == NULL)
325 return NULL;
326
327 /* Skip white spaces. */
328 while (isspace ((int) *cp) && *cp != '\0')
329 cp++;
330
331 /* Return if there is only white spaces */
332 if (*cp == '\0')
333 return NULL;
334
335 start = cp;
336
337 while (!(*cp == '\r' || *cp == '\n') && *cp != '\0')
338 cp++;
339
340 strlen = cp - start;
341 token = XMALLOC (MTYPE_STRVEC, strlen + 1);
342 memcpy (token, start, strlen);
343 *(token + strlen) = '\0';
344
345 *string = cp;
346
347 return token;
348}
349
350/* New string vector. */
ajs274a4a42004-12-07 15:39:31 +0000351static vector
hasso8c328f12004-10-05 21:01:23 +0000352cmd_make_descvec (const char *string, const char *descstr)
paul718e3742002-12-13 20:15:29 +0000353{
354 int multiple = 0;
hasso8c328f12004-10-05 21:01:23 +0000355 const char *sp;
paul718e3742002-12-13 20:15:29 +0000356 char *token;
357 int len;
hasso8c328f12004-10-05 21:01:23 +0000358 const char *cp;
359 const char *dp;
paul718e3742002-12-13 20:15:29 +0000360 vector allvec;
361 vector strvec = NULL;
362 struct desc *desc;
363
364 cp = string;
365 dp = descstr;
366
367 if (cp == NULL)
368 return NULL;
369
370 allvec = vector_init (VECTOR_MIN_SIZE);
371
372 while (1)
373 {
374 while (isspace ((int) *cp) && *cp != '\0')
375 cp++;
376
377 if (*cp == '(')
378 {
379 multiple = 1;
380 cp++;
381 }
382 if (*cp == ')')
383 {
384 multiple = 0;
385 cp++;
386 }
387 if (*cp == '|')
388 {
389 if (! multiple)
390 {
391 fprintf (stderr, "Command parse error!: %s\n", string);
392 exit (1);
393 }
394 cp++;
395 }
396
397 while (isspace ((int) *cp) && *cp != '\0')
398 cp++;
399
400 if (*cp == '(')
401 {
402 multiple = 1;
403 cp++;
404 }
405
406 if (*cp == '\0')
407 return allvec;
408
409 sp = cp;
410
411 while (! (isspace ((int) *cp) || *cp == '\r' || *cp == '\n' || *cp == ')' || *cp == '|') && *cp != '\0')
412 cp++;
413
414 len = cp - sp;
415
416 token = XMALLOC (MTYPE_STRVEC, len + 1);
417 memcpy (token, sp, len);
418 *(token + len) = '\0';
419
420 desc = XCALLOC (MTYPE_DESC, sizeof (struct desc));
421 desc->cmd = token;
422 desc->str = cmd_desc_str (&dp);
423
424 if (multiple)
425 {
426 if (multiple == 1)
427 {
428 strvec = vector_init (VECTOR_MIN_SIZE);
429 vector_set (allvec, strvec);
430 }
431 multiple++;
432 }
433 else
434 {
435 strvec = vector_init (VECTOR_MIN_SIZE);
436 vector_set (allvec, strvec);
437 }
438 vector_set (strvec, desc);
439 }
440}
441
442/* Count mandantory string vector size. This is to determine inputed
443 command has enough command length. */
ajs274a4a42004-12-07 15:39:31 +0000444static int
paul718e3742002-12-13 20:15:29 +0000445cmd_cmdsize (vector strvec)
446{
hasso8c328f12004-10-05 21:01:23 +0000447 unsigned int i;
paul718e3742002-12-13 20:15:29 +0000448 int size = 0;
449 vector descvec;
paulb8961472005-03-14 17:35:52 +0000450 struct desc *desc;
paul718e3742002-12-13 20:15:29 +0000451
paul55468c82005-03-14 20:19:01 +0000452 for (i = 0; i < vector_active (strvec); i++)
paulb8961472005-03-14 17:35:52 +0000453 if ((descvec = vector_slot (strvec, i)) != NULL)
paul718e3742002-12-13 20:15:29 +0000454 {
paul55468c82005-03-14 20:19:01 +0000455 if ((vector_active (descvec)) == 1
paulb8961472005-03-14 17:35:52 +0000456 && (desc = vector_slot (descvec, 0)) != NULL)
paul718e3742002-12-13 20:15:29 +0000457 {
hasso8c328f12004-10-05 21:01:23 +0000458 if (desc->cmd == NULL || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +0000459 return size;
460 else
461 size++;
462 }
463 else
464 size++;
465 }
466 return size;
467}
468
469/* Return prompt character of specified node. */
hasso8c328f12004-10-05 21:01:23 +0000470const char *
paul718e3742002-12-13 20:15:29 +0000471cmd_prompt (enum node_type node)
472{
473 struct cmd_node *cnode;
474
475 cnode = vector_slot (cmdvec, node);
476 return cnode->prompt;
477}
478
479/* Install a command into a node. */
480void
481install_element (enum node_type ntype, struct cmd_element *cmd)
482{
483 struct cmd_node *cnode;
pauleb820af2005-09-05 11:54:13 +0000484
485 /* cmd_init hasn't been called */
486 if (!cmdvec)
487 return;
488
paul718e3742002-12-13 20:15:29 +0000489 cnode = vector_slot (cmdvec, ntype);
490
491 if (cnode == NULL)
492 {
493 fprintf (stderr, "Command node %d doesn't exist, please check it\n",
494 ntype);
495 exit (1);
496 }
497
498 vector_set (cnode->cmd_vector, cmd);
499
500 cmd->strvec = cmd_make_descvec (cmd->string, cmd->doc);
501 cmd->cmdsize = cmd_cmdsize (cmd->strvec);
502}
503
504static unsigned char itoa64[] =
505"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
506
ajs274a4a42004-12-07 15:39:31 +0000507static void
paul718e3742002-12-13 20:15:29 +0000508to64(char *s, long v, int n)
509{
510 while (--n >= 0)
511 {
512 *s++ = itoa64[v&0x3f];
513 v >>= 6;
514 }
515}
516
ajs274a4a42004-12-07 15:39:31 +0000517static char *
518zencrypt (const char *passwd)
paul718e3742002-12-13 20:15:29 +0000519{
520 char salt[6];
521 struct timeval tv;
522 char *crypt (const char *, const char *);
523
524 gettimeofday(&tv,0);
525
526 to64(&salt[0], random(), 3);
527 to64(&salt[3], tv.tv_usec, 3);
528 salt[5] = '\0';
529
530 return crypt (passwd, salt);
531}
532
533/* This function write configuration of this host. */
ajs274a4a42004-12-07 15:39:31 +0000534static int
paul718e3742002-12-13 20:15:29 +0000535config_write_host (struct vty *vty)
536{
537 if (host.name)
538 vty_out (vty, "hostname %s%s", host.name, VTY_NEWLINE);
539
540 if (host.encrypt)
541 {
542 if (host.password_encrypt)
543 vty_out (vty, "password 8 %s%s", host.password_encrypt, VTY_NEWLINE);
544 if (host.enable_encrypt)
545 vty_out (vty, "enable password 8 %s%s", host.enable_encrypt, VTY_NEWLINE);
546 }
547 else
548 {
549 if (host.password)
550 vty_out (vty, "password %s%s", host.password, VTY_NEWLINE);
551 if (host.enable)
552 vty_out (vty, "enable password %s%s", host.enable, VTY_NEWLINE);
553 }
554
ajs274a4a42004-12-07 15:39:31 +0000555 if (zlog_default->default_lvl != LOG_DEBUG)
ajs82146b82004-12-07 17:15:55 +0000556 {
557 vty_out (vty, "! N.B. The 'log trap' command is deprecated.%s",
558 VTY_NEWLINE);
559 vty_out (vty, "log trap %s%s",
560 zlog_priority[zlog_default->default_lvl], VTY_NEWLINE);
561 }
paul718e3742002-12-13 20:15:29 +0000562
ajs274a4a42004-12-07 15:39:31 +0000563 if (host.logfile && (zlog_default->maxlvl[ZLOG_DEST_FILE] != ZLOG_DISABLED))
paul12ab19f2003-07-26 06:14:55 +0000564 {
ajs274a4a42004-12-07 15:39:31 +0000565 vty_out (vty, "log file %s", host.logfile);
566 if (zlog_default->maxlvl[ZLOG_DEST_FILE] != zlog_default->default_lvl)
567 vty_out (vty, " %s",
568 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_FILE]]);
paul12ab19f2003-07-26 06:14:55 +0000569 vty_out (vty, "%s", VTY_NEWLINE);
570 }
ajs274a4a42004-12-07 15:39:31 +0000571
572 if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != ZLOG_DISABLED)
573 {
574 vty_out (vty, "log stdout");
575 if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != zlog_default->default_lvl)
576 vty_out (vty, " %s",
577 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_STDOUT]]);
578 vty_out (vty, "%s", VTY_NEWLINE);
579 }
580
581 if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
582 vty_out(vty,"no log monitor%s",VTY_NEWLINE);
583 else if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] != zlog_default->default_lvl)
584 vty_out(vty,"log monitor %s%s",
585 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_MONITOR]],VTY_NEWLINE);
586
587 if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED)
588 {
589 vty_out (vty, "log syslog");
590 if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != zlog_default->default_lvl)
591 vty_out (vty, " %s",
592 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_SYSLOG]]);
593 vty_out (vty, "%s", VTY_NEWLINE);
594 }
595
596 if (zlog_default->facility != LOG_DAEMON)
597 vty_out (vty, "log facility %s%s",
598 facility_name(zlog_default->facility), VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +0000599
600 if (zlog_default->record_priority == 1)
601 vty_out (vty, "log record-priority%s", VTY_NEWLINE);
602
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +0000603 if (zlog_default->timestamp_precision > 0)
604 vty_out (vty, "log timestamp precision %d%s",
605 zlog_default->timestamp_precision, VTY_NEWLINE);
606
paul718e3742002-12-13 20:15:29 +0000607 if (host.advanced)
608 vty_out (vty, "service advanced-vty%s", VTY_NEWLINE);
609
610 if (host.encrypt)
611 vty_out (vty, "service password-encryption%s", VTY_NEWLINE);
612
613 if (host.lines >= 0)
614 vty_out (vty, "service terminal-length %d%s", host.lines,
615 VTY_NEWLINE);
616
paul3b0c5d92005-03-08 10:43:43 +0000617 if (host.motdfile)
618 vty_out (vty, "banner motd file %s%s", host.motdfile, VTY_NEWLINE);
619 else if (! host.motd)
paul718e3742002-12-13 20:15:29 +0000620 vty_out (vty, "no banner motd%s", VTY_NEWLINE);
621
622 return 1;
623}
624
625/* Utility function for getting command vector. */
ajs274a4a42004-12-07 15:39:31 +0000626static vector
paul718e3742002-12-13 20:15:29 +0000627cmd_node_vector (vector v, enum node_type ntype)
628{
629 struct cmd_node *cnode = vector_slot (v, ntype);
630 return cnode->cmd_vector;
631}
632
ajs274a4a42004-12-07 15:39:31 +0000633#if 0
634/* Filter command vector by symbol. This function is not actually used;
635 * should it be deleted? */
636static int
paul718e3742002-12-13 20:15:29 +0000637cmd_filter_by_symbol (char *command, char *symbol)
638{
639 int i, lim;
640
641 if (strcmp (symbol, "IPV4_ADDRESS") == 0)
642 {
643 i = 0;
644 lim = strlen (command);
645 while (i < lim)
646 {
647 if (! (isdigit ((int) command[i]) || command[i] == '.' || command[i] == '/'))
648 return 1;
649 i++;
650 }
651 return 0;
652 }
653 if (strcmp (symbol, "STRING") == 0)
654 {
655 i = 0;
656 lim = strlen (command);
657 while (i < lim)
658 {
659 if (! (isalpha ((int) command[i]) || command[i] == '_' || command[i] == '-'))
660 return 1;
661 i++;
662 }
663 return 0;
664 }
665 if (strcmp (symbol, "IFNAME") == 0)
666 {
667 i = 0;
668 lim = strlen (command);
669 while (i < lim)
670 {
671 if (! isalnum ((int) command[i]))
672 return 1;
673 i++;
674 }
675 return 0;
676 }
677 return 0;
678}
ajs274a4a42004-12-07 15:39:31 +0000679#endif
paul718e3742002-12-13 20:15:29 +0000680
681/* Completion match types. */
682enum match_type
683{
684 no_match,
685 extend_match,
686 ipv4_prefix_match,
687 ipv4_match,
688 ipv6_prefix_match,
689 ipv6_match,
690 range_match,
691 vararg_match,
692 partly_match,
693 exact_match
694};
695
ajs274a4a42004-12-07 15:39:31 +0000696static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000697cmd_ipv4_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000698{
hasso8c328f12004-10-05 21:01:23 +0000699 const char *sp;
paul718e3742002-12-13 20:15:29 +0000700 int dots = 0, nums = 0;
701 char buf[4];
702
703 if (str == NULL)
704 return partly_match;
705
706 for (;;)
707 {
708 memset (buf, 0, sizeof (buf));
709 sp = str;
710 while (*str != '\0')
711 {
712 if (*str == '.')
713 {
714 if (dots >= 3)
715 return no_match;
716
717 if (*(str + 1) == '.')
718 return no_match;
719
720 if (*(str + 1) == '\0')
721 return partly_match;
722
723 dots++;
724 break;
725 }
726 if (!isdigit ((int) *str))
727 return no_match;
728
729 str++;
730 }
731
732 if (str - sp > 3)
733 return no_match;
734
735 strncpy (buf, sp, str - sp);
736 if (atoi (buf) > 255)
737 return no_match;
738
739 nums++;
740
741 if (*str == '\0')
742 break;
743
744 str++;
745 }
746
747 if (nums < 4)
748 return partly_match;
749
750 return exact_match;
751}
752
ajs274a4a42004-12-07 15:39:31 +0000753static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000754cmd_ipv4_prefix_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000755{
hasso8c328f12004-10-05 21:01:23 +0000756 const char *sp;
paul718e3742002-12-13 20:15:29 +0000757 int dots = 0;
758 char buf[4];
759
760 if (str == NULL)
761 return partly_match;
762
763 for (;;)
764 {
765 memset (buf, 0, sizeof (buf));
766 sp = str;
767 while (*str != '\0' && *str != '/')
768 {
769 if (*str == '.')
770 {
771 if (dots == 3)
772 return no_match;
773
774 if (*(str + 1) == '.' || *(str + 1) == '/')
775 return no_match;
776
777 if (*(str + 1) == '\0')
778 return partly_match;
779
780 dots++;
781 break;
782 }
783
784 if (!isdigit ((int) *str))
785 return no_match;
786
787 str++;
788 }
789
790 if (str - sp > 3)
791 return no_match;
792
793 strncpy (buf, sp, str - sp);
794 if (atoi (buf) > 255)
795 return no_match;
796
797 if (dots == 3)
798 {
799 if (*str == '/')
800 {
801 if (*(str + 1) == '\0')
802 return partly_match;
803
804 str++;
805 break;
806 }
807 else if (*str == '\0')
808 return partly_match;
809 }
810
811 if (*str == '\0')
812 return partly_match;
813
814 str++;
815 }
816
817 sp = str;
818 while (*str != '\0')
819 {
820 if (!isdigit ((int) *str))
821 return no_match;
822
823 str++;
824 }
825
826 if (atoi (sp) > 32)
827 return no_match;
828
829 return exact_match;
830}
831
832#define IPV6_ADDR_STR "0123456789abcdefABCDEF:.%"
833#define IPV6_PREFIX_STR "0123456789abcdefABCDEF:.%/"
834#define STATE_START 1
835#define STATE_COLON 2
836#define STATE_DOUBLE 3
837#define STATE_ADDR 4
838#define STATE_DOT 5
839#define STATE_SLASH 6
840#define STATE_MASK 7
841
paul22e0a9e2003-07-11 17:55:46 +0000842#ifdef HAVE_IPV6
843
ajs274a4a42004-12-07 15:39:31 +0000844static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000845cmd_ipv6_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000846{
847 int state = STATE_START;
848 int colons = 0, nums = 0, double_colon = 0;
hasso8c328f12004-10-05 21:01:23 +0000849 const char *sp = NULL;
hasso726f9b22003-05-25 21:04:54 +0000850 struct sockaddr_in6 sin6_dummy;
851 int ret;
paul718e3742002-12-13 20:15:29 +0000852
853 if (str == NULL)
854 return partly_match;
855
856 if (strspn (str, IPV6_ADDR_STR) != strlen (str))
857 return no_match;
858
hasso726f9b22003-05-25 21:04:54 +0000859 /* use inet_pton that has a better support,
860 * for example inet_pton can support the automatic addresses:
861 * ::1.2.3.4
862 */
863 ret = inet_pton(AF_INET6, str, &sin6_dummy.sin6_addr);
864
865 if (ret == 1)
866 return exact_match;
867
paul718e3742002-12-13 20:15:29 +0000868 while (*str != '\0')
869 {
870 switch (state)
871 {
872 case STATE_START:
873 if (*str == ':')
874 {
875 if (*(str + 1) != ':' && *(str + 1) != '\0')
876 return no_match;
877 colons--;
878 state = STATE_COLON;
879 }
880 else
881 {
882 sp = str;
883 state = STATE_ADDR;
884 }
885
886 continue;
887 case STATE_COLON:
888 colons++;
889 if (*(str + 1) == ':')
890 state = STATE_DOUBLE;
891 else
892 {
893 sp = str + 1;
894 state = STATE_ADDR;
895 }
896 break;
897 case STATE_DOUBLE:
898 if (double_colon)
899 return no_match;
900
901 if (*(str + 1) == ':')
902 return no_match;
903 else
904 {
905 if (*(str + 1) != '\0')
906 colons++;
907 sp = str + 1;
908 state = STATE_ADDR;
909 }
910
911 double_colon++;
912 nums++;
913 break;
914 case STATE_ADDR:
915 if (*(str + 1) == ':' || *(str + 1) == '\0')
916 {
917 if (str - sp > 3)
918 return no_match;
919
920 nums++;
921 state = STATE_COLON;
922 }
923 if (*(str + 1) == '.')
924 state = STATE_DOT;
925 break;
926 case STATE_DOT:
927 state = STATE_ADDR;
928 break;
929 default:
930 break;
931 }
932
933 if (nums > 8)
934 return no_match;
935
936 if (colons > 7)
937 return no_match;
938
939 str++;
940 }
941
942#if 0
943 if (nums < 11)
944 return partly_match;
945#endif /* 0 */
946
947 return exact_match;
948}
949
ajs274a4a42004-12-07 15:39:31 +0000950static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000951cmd_ipv6_prefix_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000952{
953 int state = STATE_START;
954 int colons = 0, nums = 0, double_colon = 0;
955 int mask;
hasso8c328f12004-10-05 21:01:23 +0000956 const char *sp = NULL;
paul718e3742002-12-13 20:15:29 +0000957 char *endptr = NULL;
958
959 if (str == NULL)
960 return partly_match;
961
962 if (strspn (str, IPV6_PREFIX_STR) != strlen (str))
963 return no_match;
964
965 while (*str != '\0' && state != STATE_MASK)
966 {
967 switch (state)
968 {
969 case STATE_START:
970 if (*str == ':')
971 {
972 if (*(str + 1) != ':' && *(str + 1) != '\0')
973 return no_match;
974 colons--;
975 state = STATE_COLON;
976 }
977 else
978 {
979 sp = str;
980 state = STATE_ADDR;
981 }
982
983 continue;
984 case STATE_COLON:
985 colons++;
986 if (*(str + 1) == '/')
987 return no_match;
988 else if (*(str + 1) == ':')
989 state = STATE_DOUBLE;
990 else
991 {
992 sp = str + 1;
993 state = STATE_ADDR;
994 }
995 break;
996 case STATE_DOUBLE:
997 if (double_colon)
998 return no_match;
999
1000 if (*(str + 1) == ':')
1001 return no_match;
1002 else
1003 {
1004 if (*(str + 1) != '\0' && *(str + 1) != '/')
1005 colons++;
1006 sp = str + 1;
1007
1008 if (*(str + 1) == '/')
1009 state = STATE_SLASH;
1010 else
1011 state = STATE_ADDR;
1012 }
1013
1014 double_colon++;
1015 nums += 1;
1016 break;
1017 case STATE_ADDR:
1018 if (*(str + 1) == ':' || *(str + 1) == '.'
1019 || *(str + 1) == '\0' || *(str + 1) == '/')
1020 {
1021 if (str - sp > 3)
1022 return no_match;
1023
1024 for (; sp <= str; sp++)
1025 if (*sp == '/')
1026 return no_match;
1027
1028 nums++;
1029
1030 if (*(str + 1) == ':')
1031 state = STATE_COLON;
1032 else if (*(str + 1) == '.')
1033 state = STATE_DOT;
1034 else if (*(str + 1) == '/')
1035 state = STATE_SLASH;
1036 }
1037 break;
1038 case STATE_DOT:
1039 state = STATE_ADDR;
1040 break;
1041 case STATE_SLASH:
1042 if (*(str + 1) == '\0')
1043 return partly_match;
1044
1045 state = STATE_MASK;
1046 break;
1047 default:
1048 break;
1049 }
1050
1051 if (nums > 11)
1052 return no_match;
1053
1054 if (colons > 7)
1055 return no_match;
1056
1057 str++;
1058 }
1059
1060 if (state < STATE_MASK)
1061 return partly_match;
1062
1063 mask = strtol (str, &endptr, 10);
1064 if (*endptr != '\0')
1065 return no_match;
1066
1067 if (mask < 0 || mask > 128)
1068 return no_match;
1069
1070/* I don't know why mask < 13 makes command match partly.
1071 Forgive me to make this comments. I Want to set static default route
1072 because of lack of function to originate default in ospf6d; sorry
1073 yasu
1074 if (mask < 13)
1075 return partly_match;
1076*/
1077
1078 return exact_match;
1079}
1080
paul22e0a9e2003-07-11 17:55:46 +00001081#endif /* HAVE_IPV6 */
1082
paul718e3742002-12-13 20:15:29 +00001083#define DECIMAL_STRLEN_MAX 10
1084
ajs274a4a42004-12-07 15:39:31 +00001085static int
hasso8c328f12004-10-05 21:01:23 +00001086cmd_range_match (const char *range, const char *str)
paul718e3742002-12-13 20:15:29 +00001087{
1088 char *p;
1089 char buf[DECIMAL_STRLEN_MAX + 1];
1090 char *endptr = NULL;
1091 unsigned long min, max, val;
1092
1093 if (str == NULL)
1094 return 1;
1095
1096 val = strtoul (str, &endptr, 10);
1097 if (*endptr != '\0')
1098 return 0;
1099
1100 range++;
1101 p = strchr (range, '-');
1102 if (p == NULL)
1103 return 0;
1104 if (p - range > DECIMAL_STRLEN_MAX)
1105 return 0;
1106 strncpy (buf, range, p - range);
1107 buf[p - range] = '\0';
1108 min = strtoul (buf, &endptr, 10);
1109 if (*endptr != '\0')
1110 return 0;
1111
1112 range = p + 1;
1113 p = strchr (range, '>');
1114 if (p == NULL)
1115 return 0;
1116 if (p - range > DECIMAL_STRLEN_MAX)
1117 return 0;
1118 strncpy (buf, range, p - range);
1119 buf[p - range] = '\0';
1120 max = strtoul (buf, &endptr, 10);
1121 if (*endptr != '\0')
1122 return 0;
1123
1124 if (val < min || val > max)
1125 return 0;
1126
1127 return 1;
1128}
1129
1130/* Make completion match and return match type flag. */
ajs274a4a42004-12-07 15:39:31 +00001131static enum match_type
hasso8c328f12004-10-05 21:01:23 +00001132cmd_filter_by_completion (char *command, vector v, unsigned int index)
paul718e3742002-12-13 20:15:29 +00001133{
hasso8c328f12004-10-05 21:01:23 +00001134 unsigned int i;
1135 const char *str;
paul718e3742002-12-13 20:15:29 +00001136 struct cmd_element *cmd_element;
1137 enum match_type match_type;
1138 vector descvec;
1139 struct desc *desc;
paul909a2152005-03-14 17:41:45 +00001140
paul718e3742002-12-13 20:15:29 +00001141 match_type = no_match;
1142
1143 /* If command and cmd_element string does not match set NULL to vector */
paul55468c82005-03-14 20:19:01 +00001144 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001145 if ((cmd_element = vector_slot (v, i)) != NULL)
1146 {
paul55468c82005-03-14 20:19:01 +00001147 if (index >= vector_active (cmd_element->strvec))
paul718e3742002-12-13 20:15:29 +00001148 vector_slot (v, i) = NULL;
1149 else
1150 {
hasso8c328f12004-10-05 21:01:23 +00001151 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001152 int matched = 0;
1153
1154 descvec = vector_slot (cmd_element->strvec, index);
paul909a2152005-03-14 17:41:45 +00001155
paul55468c82005-03-14 20:19:01 +00001156 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001157 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001158 {
1159 str = desc->cmd;
1160
1161 if (CMD_VARARG (str))
1162 {
1163 if (match_type < vararg_match)
1164 match_type = vararg_match;
1165 matched++;
1166 }
1167 else if (CMD_RANGE (str))
1168 {
1169 if (cmd_range_match (str, command))
1170 {
1171 if (match_type < range_match)
1172 match_type = range_match;
paul718e3742002-12-13 20:15:29 +00001173
paul909a2152005-03-14 17:41:45 +00001174 matched++;
1175 }
1176 }
paul22e0a9e2003-07-11 17:55:46 +00001177#ifdef HAVE_IPV6
paul909a2152005-03-14 17:41:45 +00001178 else if (CMD_IPV6 (str))
1179 {
1180 if (cmd_ipv6_match (command))
1181 {
1182 if (match_type < ipv6_match)
1183 match_type = ipv6_match;
paul718e3742002-12-13 20:15:29 +00001184
paul909a2152005-03-14 17:41:45 +00001185 matched++;
1186 }
1187 }
1188 else if (CMD_IPV6_PREFIX (str))
1189 {
1190 if (cmd_ipv6_prefix_match (command))
1191 {
1192 if (match_type < ipv6_prefix_match)
1193 match_type = ipv6_prefix_match;
paul718e3742002-12-13 20:15:29 +00001194
paul909a2152005-03-14 17:41:45 +00001195 matched++;
1196 }
1197 }
1198#endif /* HAVE_IPV6 */
1199 else if (CMD_IPV4 (str))
1200 {
1201 if (cmd_ipv4_match (command))
1202 {
1203 if (match_type < ipv4_match)
1204 match_type = ipv4_match;
paul718e3742002-12-13 20:15:29 +00001205
paul909a2152005-03-14 17:41:45 +00001206 matched++;
1207 }
1208 }
1209 else if (CMD_IPV4_PREFIX (str))
1210 {
1211 if (cmd_ipv4_prefix_match (command))
1212 {
1213 if (match_type < ipv4_prefix_match)
1214 match_type = ipv4_prefix_match;
1215 matched++;
1216 }
1217 }
1218 else
1219 /* Check is this point's argument optional ? */
1220 if (CMD_OPTION (str) || CMD_VARIABLE (str))
1221 {
1222 if (match_type < extend_match)
1223 match_type = extend_match;
1224 matched++;
1225 }
1226 else if (strncmp (command, str, strlen (command)) == 0)
1227 {
1228 if (strcmp (command, str) == 0)
1229 match_type = exact_match;
1230 else
1231 {
1232 if (match_type < partly_match)
1233 match_type = partly_match;
1234 }
1235 matched++;
1236 }
1237 }
1238 if (!matched)
paul718e3742002-12-13 20:15:29 +00001239 vector_slot (v, i) = NULL;
1240 }
1241 }
1242 return match_type;
1243}
1244
1245/* Filter vector by command character with index. */
ajs274a4a42004-12-07 15:39:31 +00001246static enum match_type
hasso8c328f12004-10-05 21:01:23 +00001247cmd_filter_by_string (char *command, vector v, unsigned int index)
paul718e3742002-12-13 20:15:29 +00001248{
hasso8c328f12004-10-05 21:01:23 +00001249 unsigned int i;
1250 const char *str;
paul718e3742002-12-13 20:15:29 +00001251 struct cmd_element *cmd_element;
1252 enum match_type match_type;
1253 vector descvec;
1254 struct desc *desc;
paul909a2152005-03-14 17:41:45 +00001255
paul718e3742002-12-13 20:15:29 +00001256 match_type = no_match;
1257
1258 /* If command and cmd_element string does not match set NULL to vector */
paul55468c82005-03-14 20:19:01 +00001259 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001260 if ((cmd_element = vector_slot (v, i)) != NULL)
1261 {
1262 /* If given index is bigger than max string vector of command,
paul909a2152005-03-14 17:41:45 +00001263 set NULL */
paul55468c82005-03-14 20:19:01 +00001264 if (index >= vector_active (cmd_element->strvec))
paul718e3742002-12-13 20:15:29 +00001265 vector_slot (v, i) = NULL;
paul909a2152005-03-14 17:41:45 +00001266 else
paul718e3742002-12-13 20:15:29 +00001267 {
hasso8c328f12004-10-05 21:01:23 +00001268 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001269 int matched = 0;
1270
1271 descvec = vector_slot (cmd_element->strvec, index);
1272
paul55468c82005-03-14 20:19:01 +00001273 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001274 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001275 {
1276 str = desc->cmd;
paul718e3742002-12-13 20:15:29 +00001277
paul909a2152005-03-14 17:41:45 +00001278 if (CMD_VARARG (str))
1279 {
1280 if (match_type < vararg_match)
1281 match_type = vararg_match;
1282 matched++;
1283 }
1284 else if (CMD_RANGE (str))
1285 {
1286 if (cmd_range_match (str, command))
1287 {
1288 if (match_type < range_match)
1289 match_type = range_match;
1290 matched++;
1291 }
1292 }
paul22e0a9e2003-07-11 17:55:46 +00001293#ifdef HAVE_IPV6
paul909a2152005-03-14 17:41:45 +00001294 else if (CMD_IPV6 (str))
1295 {
1296 if (cmd_ipv6_match (command) == exact_match)
1297 {
1298 if (match_type < ipv6_match)
1299 match_type = ipv6_match;
1300 matched++;
1301 }
1302 }
1303 else if (CMD_IPV6_PREFIX (str))
1304 {
1305 if (cmd_ipv6_prefix_match (command) == exact_match)
1306 {
1307 if (match_type < ipv6_prefix_match)
1308 match_type = ipv6_prefix_match;
1309 matched++;
1310 }
1311 }
paul22e0a9e2003-07-11 17:55:46 +00001312#endif /* HAVE_IPV6 */
paul909a2152005-03-14 17:41:45 +00001313 else if (CMD_IPV4 (str))
1314 {
1315 if (cmd_ipv4_match (command) == exact_match)
1316 {
1317 if (match_type < ipv4_match)
1318 match_type = ipv4_match;
1319 matched++;
1320 }
1321 }
1322 else if (CMD_IPV4_PREFIX (str))
1323 {
1324 if (cmd_ipv4_prefix_match (command) == exact_match)
1325 {
1326 if (match_type < ipv4_prefix_match)
1327 match_type = ipv4_prefix_match;
1328 matched++;
1329 }
1330 }
1331 else if (CMD_OPTION (str) || CMD_VARIABLE (str))
1332 {
1333 if (match_type < extend_match)
1334 match_type = extend_match;
1335 matched++;
1336 }
1337 else
1338 {
1339 if (strcmp (command, str) == 0)
1340 {
1341 match_type = exact_match;
1342 matched++;
1343 }
1344 }
1345 }
1346 if (!matched)
paul718e3742002-12-13 20:15:29 +00001347 vector_slot (v, i) = NULL;
1348 }
1349 }
1350 return match_type;
1351}
1352
1353/* Check ambiguous match */
ajs274a4a42004-12-07 15:39:31 +00001354static int
paul718e3742002-12-13 20:15:29 +00001355is_cmd_ambiguous (char *command, vector v, int index, enum match_type type)
1356{
hasso8c328f12004-10-05 21:01:23 +00001357 unsigned int i;
1358 unsigned int j;
1359 const char *str = NULL;
paul718e3742002-12-13 20:15:29 +00001360 struct cmd_element *cmd_element;
hasso8c328f12004-10-05 21:01:23 +00001361 const char *matched = NULL;
paul718e3742002-12-13 20:15:29 +00001362 vector descvec;
1363 struct desc *desc;
paul909a2152005-03-14 17:41:45 +00001364
paul55468c82005-03-14 20:19:01 +00001365 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001366 if ((cmd_element = vector_slot (v, i)) != NULL)
1367 {
1368 int match = 0;
1369
1370 descvec = vector_slot (cmd_element->strvec, index);
1371
paul55468c82005-03-14 20:19:01 +00001372 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001373 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001374 {
1375 enum match_type ret;
1376
1377 str = desc->cmd;
paul718e3742002-12-13 20:15:29 +00001378
paul909a2152005-03-14 17:41:45 +00001379 switch (type)
1380 {
1381 case exact_match:
1382 if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
1383 && strcmp (command, str) == 0)
1384 match++;
1385 break;
1386 case partly_match:
1387 if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
1388 && strncmp (command, str, strlen (command)) == 0)
1389 {
1390 if (matched && strcmp (matched, str) != 0)
1391 return 1; /* There is ambiguous match. */
1392 else
1393 matched = str;
1394 match++;
1395 }
1396 break;
1397 case range_match:
1398 if (cmd_range_match (str, command))
1399 {
1400 if (matched && strcmp (matched, str) != 0)
1401 return 1;
1402 else
1403 matched = str;
1404 match++;
1405 }
1406 break;
1407#ifdef HAVE_IPV6
1408 case ipv6_match:
1409 if (CMD_IPV6 (str))
1410 match++;
1411 break;
1412 case ipv6_prefix_match:
1413 if ((ret = cmd_ipv6_prefix_match (command)) != no_match)
1414 {
1415 if (ret == partly_match)
1416 return 2; /* There is incomplete match. */
paul718e3742002-12-13 20:15:29 +00001417
paul909a2152005-03-14 17:41:45 +00001418 match++;
1419 }
1420 break;
1421#endif /* HAVE_IPV6 */
1422 case ipv4_match:
1423 if (CMD_IPV4 (str))
paul718e3742002-12-13 20:15:29 +00001424 match++;
paul909a2152005-03-14 17:41:45 +00001425 break;
1426 case ipv4_prefix_match:
1427 if ((ret = cmd_ipv4_prefix_match (command)) != no_match)
1428 {
1429 if (ret == partly_match)
1430 return 2; /* There is incomplete match. */
paul718e3742002-12-13 20:15:29 +00001431
paul909a2152005-03-14 17:41:45 +00001432 match++;
1433 }
1434 break;
1435 case extend_match:
1436 if (CMD_OPTION (str) || CMD_VARIABLE (str))
paul718e3742002-12-13 20:15:29 +00001437 match++;
paul909a2152005-03-14 17:41:45 +00001438 break;
1439 case no_match:
1440 default:
1441 break;
1442 }
1443 }
1444 if (!match)
paul718e3742002-12-13 20:15:29 +00001445 vector_slot (v, i) = NULL;
1446 }
1447 return 0;
1448}
1449
1450/* If src matches dst return dst string, otherwise return NULL */
ajs274a4a42004-12-07 15:39:31 +00001451static const char *
hasso8c328f12004-10-05 21:01:23 +00001452cmd_entry_function (const char *src, const char *dst)
paul718e3742002-12-13 20:15:29 +00001453{
1454 /* Skip variable arguments. */
1455 if (CMD_OPTION (dst) || CMD_VARIABLE (dst) || CMD_VARARG (dst) ||
1456 CMD_IPV4 (dst) || CMD_IPV4_PREFIX (dst) || CMD_RANGE (dst))
1457 return NULL;
1458
1459 /* In case of 'command \t', given src is NULL string. */
1460 if (src == NULL)
1461 return dst;
1462
1463 /* Matched with input string. */
1464 if (strncmp (src, dst, strlen (src)) == 0)
1465 return dst;
1466
1467 return NULL;
1468}
1469
1470/* If src matches dst return dst string, otherwise return NULL */
1471/* This version will return the dst string always if it is
1472 CMD_VARIABLE for '?' key processing */
ajs274a4a42004-12-07 15:39:31 +00001473static const char *
hasso8c328f12004-10-05 21:01:23 +00001474cmd_entry_function_desc (const char *src, const char *dst)
paul718e3742002-12-13 20:15:29 +00001475{
1476 if (CMD_VARARG (dst))
1477 return dst;
1478
1479 if (CMD_RANGE (dst))
1480 {
1481 if (cmd_range_match (dst, src))
1482 return dst;
1483 else
1484 return NULL;
1485 }
1486
paul22e0a9e2003-07-11 17:55:46 +00001487#ifdef HAVE_IPV6
paul718e3742002-12-13 20:15:29 +00001488 if (CMD_IPV6 (dst))
1489 {
1490 if (cmd_ipv6_match (src))
1491 return dst;
1492 else
1493 return NULL;
1494 }
1495
1496 if (CMD_IPV6_PREFIX (dst))
1497 {
1498 if (cmd_ipv6_prefix_match (src))
1499 return dst;
1500 else
1501 return NULL;
1502 }
paul22e0a9e2003-07-11 17:55:46 +00001503#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +00001504
1505 if (CMD_IPV4 (dst))
1506 {
1507 if (cmd_ipv4_match (src))
1508 return dst;
1509 else
1510 return NULL;
1511 }
1512
1513 if (CMD_IPV4_PREFIX (dst))
1514 {
1515 if (cmd_ipv4_prefix_match (src))
1516 return dst;
1517 else
1518 return NULL;
1519 }
1520
1521 /* Optional or variable commands always match on '?' */
1522 if (CMD_OPTION (dst) || CMD_VARIABLE (dst))
1523 return dst;
1524
1525 /* In case of 'command \t', given src is NULL string. */
1526 if (src == NULL)
1527 return dst;
1528
1529 if (strncmp (src, dst, strlen (src)) == 0)
1530 return dst;
1531 else
1532 return NULL;
1533}
1534
1535/* Check same string element existence. If it isn't there return
1536 1. */
ajs274a4a42004-12-07 15:39:31 +00001537static int
hasso8c328f12004-10-05 21:01:23 +00001538cmd_unique_string (vector v, const char *str)
paul718e3742002-12-13 20:15:29 +00001539{
hasso8c328f12004-10-05 21:01:23 +00001540 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001541 char *match;
1542
paul55468c82005-03-14 20:19:01 +00001543 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001544 if ((match = vector_slot (v, i)) != NULL)
1545 if (strcmp (match, str) == 0)
1546 return 0;
1547 return 1;
1548}
1549
1550/* Compare string to description vector. If there is same string
1551 return 1 else return 0. */
ajs274a4a42004-12-07 15:39:31 +00001552static int
hasso8c328f12004-10-05 21:01:23 +00001553desc_unique_string (vector v, const char *str)
paul718e3742002-12-13 20:15:29 +00001554{
hasso8c328f12004-10-05 21:01:23 +00001555 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001556 struct desc *desc;
1557
paul55468c82005-03-14 20:19:01 +00001558 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001559 if ((desc = vector_slot (v, i)) != NULL)
1560 if (strcmp (desc->cmd, str) == 0)
1561 return 1;
1562 return 0;
1563}
1564
ajs274a4a42004-12-07 15:39:31 +00001565static int
paulb92938a2002-12-13 21:20:42 +00001566cmd_try_do_shortcut (enum node_type node, char* first_word) {
1567 if ( first_word != NULL &&
1568 node != AUTH_NODE &&
1569 node != VIEW_NODE &&
1570 node != AUTH_ENABLE_NODE &&
1571 node != ENABLE_NODE &&
Paul Jakma62687ff2008-08-23 14:27:06 +01001572 node != RESTRICTED_NODE &&
paulb92938a2002-12-13 21:20:42 +00001573 0 == strcmp( "do", first_word ) )
1574 return 1;
1575 return 0;
1576}
1577
paul718e3742002-12-13 20:15:29 +00001578/* '?' describe command support. */
ajs274a4a42004-12-07 15:39:31 +00001579static vector
paulb92938a2002-12-13 21:20:42 +00001580cmd_describe_command_real (vector vline, struct vty *vty, int *status)
paul718e3742002-12-13 20:15:29 +00001581{
paulb8961472005-03-14 17:35:52 +00001582 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001583 vector cmd_vector;
1584#define INIT_MATCHVEC_SIZE 10
1585 vector matchvec;
1586 struct cmd_element *cmd_element;
paulb8961472005-03-14 17:35:52 +00001587 unsigned int index;
paul54aba542003-08-21 20:28:24 +00001588 int ret;
1589 enum match_type match;
1590 char *command;
paul718e3742002-12-13 20:15:29 +00001591 static struct desc desc_cr = { "<cr>", "" };
1592
1593 /* Set index. */
paul55468c82005-03-14 20:19:01 +00001594 if (vector_active (vline) == 0)
paulb8961472005-03-14 17:35:52 +00001595 {
1596 *status = CMD_ERR_NO_MATCH;
1597 return NULL;
1598 }
1599 else
paul55468c82005-03-14 20:19:01 +00001600 index = vector_active (vline) - 1;
paul909a2152005-03-14 17:41:45 +00001601
paul718e3742002-12-13 20:15:29 +00001602 /* Make copy vector of current node's command vector. */
1603 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1604
1605 /* Prepare match vector */
1606 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1607
1608 /* Filter commands. */
paul54aba542003-08-21 20:28:24 +00001609 /* Only words precedes current word will be checked in this loop. */
paul718e3742002-12-13 20:15:29 +00001610 for (i = 0; i < index; i++)
paulb8961472005-03-14 17:35:52 +00001611 if ((command = vector_slot (vline, i)))
paul909a2152005-03-14 17:41:45 +00001612 {
1613 match = cmd_filter_by_completion (command, cmd_vector, i);
1614
1615 if (match == vararg_match)
1616 {
1617 struct cmd_element *cmd_element;
1618 vector descvec;
1619 unsigned int j, k;
paul718e3742002-12-13 20:15:29 +00001620
paul55468c82005-03-14 20:19:01 +00001621 for (j = 0; j < vector_active (cmd_vector); j++)
paulb8961472005-03-14 17:35:52 +00001622 if ((cmd_element = vector_slot (cmd_vector, j)) != NULL
paul55468c82005-03-14 20:19:01 +00001623 && (vector_active (cmd_element->strvec)))
paul909a2152005-03-14 17:41:45 +00001624 {
1625 descvec = vector_slot (cmd_element->strvec,
paul55468c82005-03-14 20:19:01 +00001626 vector_active (cmd_element->strvec) - 1);
1627 for (k = 0; k < vector_active (descvec); k++)
paul909a2152005-03-14 17:41:45 +00001628 {
1629 struct desc *desc = vector_slot (descvec, k);
1630 vector_set (matchvec, desc);
1631 }
1632 }
1633
1634 vector_set (matchvec, &desc_cr);
1635 vector_free (cmd_vector);
paul718e3742002-12-13 20:15:29 +00001636
paul909a2152005-03-14 17:41:45 +00001637 return matchvec;
1638 }
paul718e3742002-12-13 20:15:29 +00001639
paul909a2152005-03-14 17:41:45 +00001640 if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
1641 {
1642 vector_free (cmd_vector);
Paul Jakmae5cd7062006-06-15 12:25:55 +00001643 vector_free (matchvec);
paul909a2152005-03-14 17:41:45 +00001644 *status = CMD_ERR_AMBIGUOUS;
1645 return NULL;
1646 }
1647 else if (ret == 2)
1648 {
1649 vector_free (cmd_vector);
Paul Jakmae5cd7062006-06-15 12:25:55 +00001650 vector_free (matchvec);
paul909a2152005-03-14 17:41:45 +00001651 *status = CMD_ERR_NO_MATCH;
1652 return NULL;
1653 }
1654 }
paul718e3742002-12-13 20:15:29 +00001655
1656 /* Prepare match vector */
1657 /* matchvec = vector_init (INIT_MATCHVEC_SIZE); */
1658
paul54aba542003-08-21 20:28:24 +00001659 /* Make sure that cmd_vector is filtered based on current word */
1660 command = vector_slot (vline, index);
1661 if (command)
1662 match = cmd_filter_by_completion (command, cmd_vector, index);
1663
paul718e3742002-12-13 20:15:29 +00001664 /* Make description vector. */
paul55468c82005-03-14 20:19:01 +00001665 for (i = 0; i < vector_active (cmd_vector); i++)
paul718e3742002-12-13 20:15:29 +00001666 if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
1667 {
hasso8c328f12004-10-05 21:01:23 +00001668 const char *string = NULL;
paul718e3742002-12-13 20:15:29 +00001669 vector strvec = cmd_element->strvec;
1670
paul55468c82005-03-14 20:19:01 +00001671 /* if command is NULL, index may be equal to vector_active */
1672 if (command && index >= vector_active (strvec))
paul718e3742002-12-13 20:15:29 +00001673 vector_slot (cmd_vector, i) = NULL;
1674 else
1675 {
paul54aba542003-08-21 20:28:24 +00001676 /* Check if command is completed. */
paul55468c82005-03-14 20:19:01 +00001677 if (command == NULL && index == vector_active (strvec))
paul718e3742002-12-13 20:15:29 +00001678 {
1679 string = "<cr>";
paul909a2152005-03-14 17:41:45 +00001680 if (!desc_unique_string (matchvec, string))
paul718e3742002-12-13 20:15:29 +00001681 vector_set (matchvec, &desc_cr);
1682 }
1683 else
1684 {
hasso8c328f12004-10-05 21:01:23 +00001685 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001686 vector descvec = vector_slot (strvec, index);
1687 struct desc *desc;
1688
paul55468c82005-03-14 20:19:01 +00001689 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001690 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001691 {
1692 string = cmd_entry_function_desc (command, desc->cmd);
1693 if (string)
1694 {
1695 /* Uniqueness check */
1696 if (!desc_unique_string (matchvec, string))
1697 vector_set (matchvec, desc);
1698 }
1699 }
paul718e3742002-12-13 20:15:29 +00001700 }
1701 }
1702 }
1703 vector_free (cmd_vector);
1704
1705 if (vector_slot (matchvec, 0) == NULL)
1706 {
1707 vector_free (matchvec);
paul909a2152005-03-14 17:41:45 +00001708 *status = CMD_ERR_NO_MATCH;
Paul Jakma5fc60512006-05-12 23:24:09 +00001709 return NULL;
paul718e3742002-12-13 20:15:29 +00001710 }
paul718e3742002-12-13 20:15:29 +00001711
Paul Jakma5fc60512006-05-12 23:24:09 +00001712 *status = CMD_SUCCESS;
paul718e3742002-12-13 20:15:29 +00001713 return matchvec;
1714}
1715
paulb92938a2002-12-13 21:20:42 +00001716vector
1717cmd_describe_command (vector vline, struct vty *vty, int *status)
1718{
1719 vector ret;
1720
1721 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1722 {
1723 enum node_type onode;
1724 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00001725 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00001726
1727 onode = vty->node;
1728 vty->node = ENABLE_NODE;
1729 /* We can try it on enable node, cos' the vty is authenticated */
1730
1731 shifted_vline = vector_init (vector_count(vline));
1732 /* use memcpy? */
paul55468c82005-03-14 20:19:01 +00001733 for (index = 1; index < vector_active (vline); index++)
paulb92938a2002-12-13 21:20:42 +00001734 {
1735 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1736 }
1737
1738 ret = cmd_describe_command_real (shifted_vline, vty, status);
1739
1740 vector_free(shifted_vline);
1741 vty->node = onode;
1742 return ret;
1743 }
1744
1745
1746 return cmd_describe_command_real (vline, vty, status);
1747}
1748
1749
paul718e3742002-12-13 20:15:29 +00001750/* Check LCD of matched command. */
ajs274a4a42004-12-07 15:39:31 +00001751static int
paul718e3742002-12-13 20:15:29 +00001752cmd_lcd (char **matched)
1753{
1754 int i;
1755 int j;
1756 int lcd = -1;
1757 char *s1, *s2;
1758 char c1, c2;
1759
1760 if (matched[0] == NULL || matched[1] == NULL)
1761 return 0;
1762
1763 for (i = 1; matched[i] != NULL; i++)
1764 {
1765 s1 = matched[i - 1];
1766 s2 = matched[i];
1767
1768 for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
1769 if (c1 != c2)
1770 break;
1771
1772 if (lcd < 0)
1773 lcd = j;
1774 else
1775 {
1776 if (lcd > j)
1777 lcd = j;
1778 }
1779 }
1780 return lcd;
1781}
1782
1783/* Command line completion support. */
ajs274a4a42004-12-07 15:39:31 +00001784static char **
paulb92938a2002-12-13 21:20:42 +00001785cmd_complete_command_real (vector vline, struct vty *vty, int *status)
paul718e3742002-12-13 20:15:29 +00001786{
paulb8961472005-03-14 17:35:52 +00001787 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001788 vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1789#define INIT_MATCHVEC_SIZE 10
1790 vector matchvec;
1791 struct cmd_element *cmd_element;
paulb8961472005-03-14 17:35:52 +00001792 unsigned int index;
paul718e3742002-12-13 20:15:29 +00001793 char **match_str;
1794 struct desc *desc;
1795 vector descvec;
1796 char *command;
1797 int lcd;
1798
paul55468c82005-03-14 20:19:01 +00001799 if (vector_active (vline) == 0)
paulb8961472005-03-14 17:35:52 +00001800 {
Paul Jakmad2519962006-05-12 23:19:37 +00001801 vector_free (cmd_vector);
paulb8961472005-03-14 17:35:52 +00001802 *status = CMD_ERR_NO_MATCH;
1803 return NULL;
1804 }
1805 else
paul55468c82005-03-14 20:19:01 +00001806 index = vector_active (vline) - 1;
paulb8961472005-03-14 17:35:52 +00001807
paul718e3742002-12-13 20:15:29 +00001808 /* First, filter by preceeding command string */
1809 for (i = 0; i < index; i++)
paulb8961472005-03-14 17:35:52 +00001810 if ((command = vector_slot (vline, i)))
paul909a2152005-03-14 17:41:45 +00001811 {
1812 enum match_type match;
1813 int ret;
paul718e3742002-12-13 20:15:29 +00001814
paul909a2152005-03-14 17:41:45 +00001815 /* First try completion match, if there is exactly match return 1 */
1816 match = cmd_filter_by_completion (command, cmd_vector, i);
paul718e3742002-12-13 20:15:29 +00001817
paul909a2152005-03-14 17:41:45 +00001818 /* If there is exact match then filter ambiguous match else check
1819 ambiguousness. */
1820 if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
1821 {
1822 vector_free (cmd_vector);
1823 *status = CMD_ERR_AMBIGUOUS;
1824 return NULL;
1825 }
1826 /*
1827 else if (ret == 2)
1828 {
1829 vector_free (cmd_vector);
1830 *status = CMD_ERR_NO_MATCH;
1831 return NULL;
1832 }
1833 */
1834 }
1835
paul718e3742002-12-13 20:15:29 +00001836 /* Prepare match vector. */
1837 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1838
1839 /* Now we got into completion */
paul55468c82005-03-14 20:19:01 +00001840 for (i = 0; i < vector_active (cmd_vector); i++)
paulb8961472005-03-14 17:35:52 +00001841 if ((cmd_element = vector_slot (cmd_vector, i)))
paul718e3742002-12-13 20:15:29 +00001842 {
hasso8c328f12004-10-05 21:01:23 +00001843 const char *string;
paul718e3742002-12-13 20:15:29 +00001844 vector strvec = cmd_element->strvec;
paul909a2152005-03-14 17:41:45 +00001845
paul718e3742002-12-13 20:15:29 +00001846 /* Check field length */
paul55468c82005-03-14 20:19:01 +00001847 if (index >= vector_active (strvec))
paul718e3742002-12-13 20:15:29 +00001848 vector_slot (cmd_vector, i) = NULL;
paul909a2152005-03-14 17:41:45 +00001849 else
paul718e3742002-12-13 20:15:29 +00001850 {
hasso8c328f12004-10-05 21:01:23 +00001851 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001852
1853 descvec = vector_slot (strvec, index);
paul55468c82005-03-14 20:19:01 +00001854 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001855 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001856 {
paulb8961472005-03-14 17:35:52 +00001857 if ((string =
1858 cmd_entry_function (vector_slot (vline, index),
paul909a2152005-03-14 17:41:45 +00001859 desc->cmd)))
1860 if (cmd_unique_string (matchvec, string))
1861 vector_set (matchvec, XSTRDUP (MTYPE_TMP, string));
1862 }
paul718e3742002-12-13 20:15:29 +00001863 }
1864 }
1865
1866 /* We don't need cmd_vector any more. */
1867 vector_free (cmd_vector);
1868
1869 /* No matched command */
1870 if (vector_slot (matchvec, 0) == NULL)
1871 {
1872 vector_free (matchvec);
1873
1874 /* In case of 'command \t' pattern. Do you need '?' command at
1875 the end of the line. */
1876 if (vector_slot (vline, index) == '\0')
1877 *status = CMD_ERR_NOTHING_TODO;
1878 else
1879 *status = CMD_ERR_NO_MATCH;
1880 return NULL;
1881 }
1882
1883 /* Only one matched */
1884 if (vector_slot (matchvec, 1) == NULL)
1885 {
1886 match_str = (char **) matchvec->index;
1887 vector_only_wrapper_free (matchvec);
1888 *status = CMD_COMPLETE_FULL_MATCH;
1889 return match_str;
1890 }
1891 /* Make it sure last element is NULL. */
1892 vector_set (matchvec, NULL);
1893
1894 /* Check LCD of matched strings. */
1895 if (vector_slot (vline, index) != NULL)
1896 {
1897 lcd = cmd_lcd ((char **) matchvec->index);
1898
1899 if (lcd)
1900 {
1901 int len = strlen (vector_slot (vline, index));
paul909a2152005-03-14 17:41:45 +00001902
paul718e3742002-12-13 20:15:29 +00001903 if (len < lcd)
1904 {
1905 char *lcdstr;
paul909a2152005-03-14 17:41:45 +00001906
paul05865c92005-10-26 05:49:54 +00001907 lcdstr = XMALLOC (MTYPE_STRVEC, lcd + 1);
paul718e3742002-12-13 20:15:29 +00001908 memcpy (lcdstr, matchvec->index[0], lcd);
1909 lcdstr[lcd] = '\0';
1910
1911 /* match_str = (char **) &lcdstr; */
1912
1913 /* Free matchvec. */
paul55468c82005-03-14 20:19:01 +00001914 for (i = 0; i < vector_active (matchvec); i++)
paul718e3742002-12-13 20:15:29 +00001915 {
1916 if (vector_slot (matchvec, i))
paul05865c92005-10-26 05:49:54 +00001917 XFREE (MTYPE_STRVEC, vector_slot (matchvec, i));
paul718e3742002-12-13 20:15:29 +00001918 }
1919 vector_free (matchvec);
1920
paul909a2152005-03-14 17:41:45 +00001921 /* Make new matchvec. */
paul718e3742002-12-13 20:15:29 +00001922 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1923 vector_set (matchvec, lcdstr);
1924 match_str = (char **) matchvec->index;
1925 vector_only_wrapper_free (matchvec);
1926
1927 *status = CMD_COMPLETE_MATCH;
1928 return match_str;
1929 }
1930 }
1931 }
1932
1933 match_str = (char **) matchvec->index;
1934 vector_only_wrapper_free (matchvec);
1935 *status = CMD_COMPLETE_LIST_MATCH;
1936 return match_str;
1937}
1938
paulb92938a2002-12-13 21:20:42 +00001939char **
paul9ab68122003-01-18 01:16:20 +00001940cmd_complete_command (vector vline, struct vty *vty, int *status)
paulb92938a2002-12-13 21:20:42 +00001941{
1942 char **ret;
1943
1944 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1945 {
1946 enum node_type onode;
1947 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00001948 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00001949
1950 onode = vty->node;
1951 vty->node = ENABLE_NODE;
1952 /* We can try it on enable node, cos' the vty is authenticated */
1953
1954 shifted_vline = vector_init (vector_count(vline));
1955 /* use memcpy? */
paul55468c82005-03-14 20:19:01 +00001956 for (index = 1; index < vector_active (vline); index++)
paulb92938a2002-12-13 21:20:42 +00001957 {
1958 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1959 }
1960
1961 ret = cmd_complete_command_real (shifted_vline, vty, status);
1962
1963 vector_free(shifted_vline);
1964 vty->node = onode;
1965 return ret;
1966 }
1967
1968
1969 return cmd_complete_command_real (vline, vty, status);
1970}
1971
1972/* return parent node */
1973/* MUST eventually converge on CONFIG_NODE */
hasso13bfca72005-01-23 21:42:25 +00001974enum node_type
ajs274a4a42004-12-07 15:39:31 +00001975node_parent ( enum node_type node )
paulb92938a2002-12-13 21:20:42 +00001976{
1977 enum node_type ret;
1978
paul9ab68122003-01-18 01:16:20 +00001979 assert (node > CONFIG_NODE);
1980
1981 switch (node)
1982 {
1983 case BGP_VPNV4_NODE:
1984 case BGP_IPV4_NODE:
1985 case BGP_IPV4M_NODE:
1986 case BGP_IPV6_NODE:
paul1e836592005-08-22 22:39:56 +00001987 case BGP_IPV6M_NODE:
paul9ab68122003-01-18 01:16:20 +00001988 ret = BGP_NODE;
1989 break;
1990 case KEYCHAIN_KEY_NODE:
1991 ret = KEYCHAIN_NODE;
1992 break;
1993 default:
1994 ret = CONFIG_NODE;
paulb92938a2002-12-13 21:20:42 +00001995 }
1996
1997 return ret;
1998}
1999
paul718e3742002-12-13 20:15:29 +00002000/* Execute command by argument vline vector. */
ajs274a4a42004-12-07 15:39:31 +00002001static int
paulb8961472005-03-14 17:35:52 +00002002cmd_execute_command_real (vector vline, struct vty *vty,
2003 struct cmd_element **cmd)
paul718e3742002-12-13 20:15:29 +00002004{
hasso8c328f12004-10-05 21:01:23 +00002005 unsigned int i;
2006 unsigned int index;
paul718e3742002-12-13 20:15:29 +00002007 vector cmd_vector;
2008 struct cmd_element *cmd_element;
2009 struct cmd_element *matched_element;
2010 unsigned int matched_count, incomplete_count;
2011 int argc;
paul9035efa2004-10-10 11:56:56 +00002012 const char *argv[CMD_ARGC_MAX];
paul718e3742002-12-13 20:15:29 +00002013 enum match_type match = 0;
2014 int varflag;
2015 char *command;
2016
2017 /* Make copy of command elements. */
2018 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2019
paul55468c82005-03-14 20:19:01 +00002020 for (index = 0; index < vector_active (vline); index++)
paulb8961472005-03-14 17:35:52 +00002021 if ((command = vector_slot (vline, index)))
paul909a2152005-03-14 17:41:45 +00002022 {
2023 int ret;
paul718e3742002-12-13 20:15:29 +00002024
paul909a2152005-03-14 17:41:45 +00002025 match = cmd_filter_by_completion (command, cmd_vector, index);
paul718e3742002-12-13 20:15:29 +00002026
paul909a2152005-03-14 17:41:45 +00002027 if (match == vararg_match)
2028 break;
2029
2030 ret = is_cmd_ambiguous (command, cmd_vector, index, match);
paul718e3742002-12-13 20:15:29 +00002031
paul909a2152005-03-14 17:41:45 +00002032 if (ret == 1)
2033 {
2034 vector_free (cmd_vector);
2035 return CMD_ERR_AMBIGUOUS;
2036 }
2037 else if (ret == 2)
2038 {
2039 vector_free (cmd_vector);
2040 return CMD_ERR_NO_MATCH;
2041 }
2042 }
paul718e3742002-12-13 20:15:29 +00002043
2044 /* Check matched count. */
2045 matched_element = NULL;
2046 matched_count = 0;
2047 incomplete_count = 0;
2048
paul55468c82005-03-14 20:19:01 +00002049 for (i = 0; i < vector_active (cmd_vector); i++)
paulb8961472005-03-14 17:35:52 +00002050 if ((cmd_element = vector_slot (cmd_vector, i)))
paul718e3742002-12-13 20:15:29 +00002051 {
paul718e3742002-12-13 20:15:29 +00002052 if (match == vararg_match || index >= cmd_element->cmdsize)
2053 {
2054 matched_element = cmd_element;
2055#if 0
2056 printf ("DEBUG: %s\n", cmd_element->string);
2057#endif
2058 matched_count++;
2059 }
2060 else
2061 {
2062 incomplete_count++;
2063 }
2064 }
paul909a2152005-03-14 17:41:45 +00002065
paul718e3742002-12-13 20:15:29 +00002066 /* Finish of using cmd_vector. */
2067 vector_free (cmd_vector);
2068
paul909a2152005-03-14 17:41:45 +00002069 /* To execute command, matched_count must be 1. */
2070 if (matched_count == 0)
paul718e3742002-12-13 20:15:29 +00002071 {
2072 if (incomplete_count)
2073 return CMD_ERR_INCOMPLETE;
2074 else
2075 return CMD_ERR_NO_MATCH;
2076 }
2077
paul909a2152005-03-14 17:41:45 +00002078 if (matched_count > 1)
paul718e3742002-12-13 20:15:29 +00002079 return CMD_ERR_AMBIGUOUS;
2080
2081 /* Argument treatment */
2082 varflag = 0;
2083 argc = 0;
2084
paul55468c82005-03-14 20:19:01 +00002085 for (i = 0; i < vector_active (vline); i++)
paul718e3742002-12-13 20:15:29 +00002086 {
2087 if (varflag)
2088 argv[argc++] = vector_slot (vline, i);
2089 else
paul909a2152005-03-14 17:41:45 +00002090 {
paul718e3742002-12-13 20:15:29 +00002091 vector descvec = vector_slot (matched_element->strvec, i);
2092
paul55468c82005-03-14 20:19:01 +00002093 if (vector_active (descvec) == 1)
paul718e3742002-12-13 20:15:29 +00002094 {
2095 struct desc *desc = vector_slot (descvec, 0);
paul718e3742002-12-13 20:15:29 +00002096
hasso8c328f12004-10-05 21:01:23 +00002097 if (CMD_VARARG (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002098 varflag = 1;
2099
hasso8c328f12004-10-05 21:01:23 +00002100 if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002101 argv[argc++] = vector_slot (vline, i);
2102 }
2103 else
2104 argv[argc++] = vector_slot (vline, i);
2105 }
2106
2107 if (argc >= CMD_ARGC_MAX)
2108 return CMD_ERR_EXEED_ARGC_MAX;
2109 }
2110
2111 /* For vtysh execution. */
2112 if (cmd)
2113 *cmd = matched_element;
2114
2115 if (matched_element->daemon)
2116 return CMD_SUCCESS_DAEMON;
2117
2118 /* Execute matched command. */
2119 return (*matched_element->func) (matched_element, vty, argc, argv);
2120}
2121
paulb92938a2002-12-13 21:20:42 +00002122int
hasso87d683b2005-01-16 23:31:54 +00002123cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,
2124 int vtysh) {
paul9ab68122003-01-18 01:16:20 +00002125 int ret, saved_ret, tried = 0;
2126 enum node_type onode, try_node;
2127
2128 onode = try_node = vty->node;
paulb92938a2002-12-13 21:20:42 +00002129
2130 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
2131 {
2132 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00002133 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00002134
2135 vty->node = ENABLE_NODE;
2136 /* We can try it on enable node, cos' the vty is authenticated */
2137
2138 shifted_vline = vector_init (vector_count(vline));
2139 /* use memcpy? */
paul55468c82005-03-14 20:19:01 +00002140 for (index = 1; index < vector_active (vline); index++)
paulb92938a2002-12-13 21:20:42 +00002141 {
2142 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
2143 }
2144
2145 ret = cmd_execute_command_real (shifted_vline, vty, cmd);
2146
2147 vector_free(shifted_vline);
2148 vty->node = onode;
2149 return ret;
2150 }
2151
2152
paul9ab68122003-01-18 01:16:20 +00002153 saved_ret = ret = cmd_execute_command_real (vline, vty, cmd);
paulb92938a2002-12-13 21:20:42 +00002154
hasso87d683b2005-01-16 23:31:54 +00002155 if (vtysh)
2156 return saved_ret;
2157
paulb92938a2002-12-13 21:20:42 +00002158 /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
paul9ab68122003-01-18 01:16:20 +00002159 while ( ret != CMD_SUCCESS && ret != CMD_WARNING
paulb92938a2002-12-13 21:20:42 +00002160 && vty->node > CONFIG_NODE )
2161 {
paul9ab68122003-01-18 01:16:20 +00002162 try_node = node_parent(try_node);
2163 vty->node = try_node;
paulb92938a2002-12-13 21:20:42 +00002164 ret = cmd_execute_command_real (vline, vty, cmd);
paul9ab68122003-01-18 01:16:20 +00002165 tried = 1;
2166 if (ret == CMD_SUCCESS || ret == CMD_WARNING)
paulb92938a2002-12-13 21:20:42 +00002167 {
paul9ab68122003-01-18 01:16:20 +00002168 /* succesfull command, leave the node as is */
paulb92938a2002-12-13 21:20:42 +00002169 return ret;
2170 }
paulb92938a2002-12-13 21:20:42 +00002171 }
paul9ab68122003-01-18 01:16:20 +00002172 /* no command succeeded, reset the vty to the original node and
2173 return the error for this node */
2174 if ( tried )
2175 vty->node = onode;
2176 return saved_ret;
pauleda031f2003-01-18 00:39:19 +00002177}
2178
paul718e3742002-12-13 20:15:29 +00002179/* Execute command by argument readline. */
2180int
paul909a2152005-03-14 17:41:45 +00002181cmd_execute_command_strict (vector vline, struct vty *vty,
paul718e3742002-12-13 20:15:29 +00002182 struct cmd_element **cmd)
2183{
hasso8c328f12004-10-05 21:01:23 +00002184 unsigned int i;
2185 unsigned int index;
paul718e3742002-12-13 20:15:29 +00002186 vector cmd_vector;
2187 struct cmd_element *cmd_element;
2188 struct cmd_element *matched_element;
2189 unsigned int matched_count, incomplete_count;
2190 int argc;
paul9035efa2004-10-10 11:56:56 +00002191 const char *argv[CMD_ARGC_MAX];
paul718e3742002-12-13 20:15:29 +00002192 int varflag;
2193 enum match_type match = 0;
2194 char *command;
2195
2196 /* Make copy of command element */
2197 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2198
paul55468c82005-03-14 20:19:01 +00002199 for (index = 0; index < vector_active (vline); index++)
paulb8961472005-03-14 17:35:52 +00002200 if ((command = vector_slot (vline, index)))
paul909a2152005-03-14 17:41:45 +00002201 {
2202 int ret;
2203
2204 match = cmd_filter_by_string (vector_slot (vline, index),
2205 cmd_vector, index);
paul718e3742002-12-13 20:15:29 +00002206
paul909a2152005-03-14 17:41:45 +00002207 /* If command meets '.VARARG' then finish matching. */
2208 if (match == vararg_match)
2209 break;
2210
2211 ret = is_cmd_ambiguous (command, cmd_vector, index, match);
2212 if (ret == 1)
2213 {
2214 vector_free (cmd_vector);
2215 return CMD_ERR_AMBIGUOUS;
2216 }
2217 if (ret == 2)
2218 {
2219 vector_free (cmd_vector);
2220 return CMD_ERR_NO_MATCH;
2221 }
2222 }
paul718e3742002-12-13 20:15:29 +00002223
2224 /* Check matched count. */
2225 matched_element = NULL;
2226 matched_count = 0;
2227 incomplete_count = 0;
paul55468c82005-03-14 20:19:01 +00002228 for (i = 0; i < vector_active (cmd_vector); i++)
paul909a2152005-03-14 17:41:45 +00002229 if (vector_slot (cmd_vector, i) != NULL)
paul718e3742002-12-13 20:15:29 +00002230 {
paul909a2152005-03-14 17:41:45 +00002231 cmd_element = vector_slot (cmd_vector, i);
paul718e3742002-12-13 20:15:29 +00002232
2233 if (match == vararg_match || index >= cmd_element->cmdsize)
2234 {
2235 matched_element = cmd_element;
2236 matched_count++;
2237 }
2238 else
2239 incomplete_count++;
2240 }
paul909a2152005-03-14 17:41:45 +00002241
paul718e3742002-12-13 20:15:29 +00002242 /* Finish of using cmd_vector. */
2243 vector_free (cmd_vector);
2244
paul909a2152005-03-14 17:41:45 +00002245 /* To execute command, matched_count must be 1. */
2246 if (matched_count == 0)
paul718e3742002-12-13 20:15:29 +00002247 {
2248 if (incomplete_count)
2249 return CMD_ERR_INCOMPLETE;
2250 else
2251 return CMD_ERR_NO_MATCH;
2252 }
2253
paul909a2152005-03-14 17:41:45 +00002254 if (matched_count > 1)
paul718e3742002-12-13 20:15:29 +00002255 return CMD_ERR_AMBIGUOUS;
2256
2257 /* Argument treatment */
2258 varflag = 0;
2259 argc = 0;
2260
paul55468c82005-03-14 20:19:01 +00002261 for (i = 0; i < vector_active (vline); i++)
paul718e3742002-12-13 20:15:29 +00002262 {
2263 if (varflag)
2264 argv[argc++] = vector_slot (vline, i);
2265 else
paul909a2152005-03-14 17:41:45 +00002266 {
paul718e3742002-12-13 20:15:29 +00002267 vector descvec = vector_slot (matched_element->strvec, i);
2268
paul55468c82005-03-14 20:19:01 +00002269 if (vector_active (descvec) == 1)
paul718e3742002-12-13 20:15:29 +00002270 {
2271 struct desc *desc = vector_slot (descvec, 0);
paul718e3742002-12-13 20:15:29 +00002272
hasso8c328f12004-10-05 21:01:23 +00002273 if (CMD_VARARG (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002274 varflag = 1;
paul909a2152005-03-14 17:41:45 +00002275
hasso8c328f12004-10-05 21:01:23 +00002276 if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002277 argv[argc++] = vector_slot (vline, i);
2278 }
2279 else
2280 argv[argc++] = vector_slot (vline, i);
2281 }
2282
2283 if (argc >= CMD_ARGC_MAX)
2284 return CMD_ERR_EXEED_ARGC_MAX;
2285 }
2286
2287 /* For vtysh execution. */
2288 if (cmd)
2289 *cmd = matched_element;
2290
2291 if (matched_element->daemon)
2292 return CMD_SUCCESS_DAEMON;
2293
2294 /* Now execute matched command */
2295 return (*matched_element->func) (matched_element, vty, argc, argv);
2296}
2297
2298/* Configration make from file. */
2299int
2300config_from_file (struct vty *vty, FILE *fp)
2301{
2302 int ret;
2303 vector vline;
2304
2305 while (fgets (vty->buf, VTY_BUFSIZ, fp))
2306 {
2307 vline = cmd_make_strvec (vty->buf);
2308
2309 /* In case of comment line */
2310 if (vline == NULL)
2311 continue;
2312 /* Execute configuration command : this is strict match */
2313 ret = cmd_execute_command_strict (vline, vty, NULL);
2314
2315 /* Try again with setting node to CONFIG_NODE */
paulb92938a2002-12-13 21:20:42 +00002316 while (ret != CMD_SUCCESS && ret != CMD_WARNING
hassoddd85ed2004-10-13 08:18:07 +00002317 && ret != CMD_ERR_NOTHING_TODO && vty->node != CONFIG_NODE)
2318 {
paulb92938a2002-12-13 21:20:42 +00002319 vty->node = node_parent(vty->node);
hassoddd85ed2004-10-13 08:18:07 +00002320 ret = cmd_execute_command_strict (vline, vty, NULL);
2321 }
paul9ab68122003-01-18 01:16:20 +00002322
paul718e3742002-12-13 20:15:29 +00002323 cmd_free_strvec (vline);
2324
hassoddd85ed2004-10-13 08:18:07 +00002325 if (ret != CMD_SUCCESS && ret != CMD_WARNING
2326 && ret != CMD_ERR_NOTHING_TODO)
paul718e3742002-12-13 20:15:29 +00002327 return ret;
2328 }
2329 return CMD_SUCCESS;
2330}
2331
2332/* Configration from terminal */
2333DEFUN (config_terminal,
2334 config_terminal_cmd,
2335 "configure terminal",
2336 "Configuration from vty interface\n"
2337 "Configuration terminal\n")
2338{
2339 if (vty_config_lock (vty))
2340 vty->node = CONFIG_NODE;
2341 else
2342 {
2343 vty_out (vty, "VTY configuration is locked by other VTY%s", VTY_NEWLINE);
2344 return CMD_WARNING;
2345 }
2346 return CMD_SUCCESS;
2347}
2348
2349/* Enable command */
2350DEFUN (enable,
2351 config_enable_cmd,
2352 "enable",
2353 "Turn on privileged mode command\n")
2354{
2355 /* If enable password is NULL, change to ENABLE_NODE */
2356 if ((host.enable == NULL && host.enable_encrypt == NULL) ||
2357 vty->type == VTY_SHELL_SERV)
2358 vty->node = ENABLE_NODE;
2359 else
2360 vty->node = AUTH_ENABLE_NODE;
2361
2362 return CMD_SUCCESS;
2363}
2364
2365/* Disable command */
2366DEFUN (disable,
2367 config_disable_cmd,
2368 "disable",
2369 "Turn off privileged mode command\n")
2370{
2371 if (vty->node == ENABLE_NODE)
2372 vty->node = VIEW_NODE;
2373 return CMD_SUCCESS;
2374}
2375
2376/* Down vty node level. */
2377DEFUN (config_exit,
2378 config_exit_cmd,
2379 "exit",
2380 "Exit current mode and down to previous mode\n")
2381{
2382 switch (vty->node)
2383 {
2384 case VIEW_NODE:
2385 case ENABLE_NODE:
Paul Jakma62687ff2008-08-23 14:27:06 +01002386 case RESTRICTED_NODE:
paul718e3742002-12-13 20:15:29 +00002387 if (vty_shell (vty))
2388 exit (0);
2389 else
2390 vty->status = VTY_CLOSE;
2391 break;
2392 case CONFIG_NODE:
2393 vty->node = ENABLE_NODE;
2394 vty_config_unlock (vty);
2395 break;
2396 case INTERFACE_NODE:
2397 case ZEBRA_NODE:
2398 case BGP_NODE:
2399 case RIP_NODE:
2400 case RIPNG_NODE:
2401 case OSPF_NODE:
2402 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00002403 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00002404 case KEYCHAIN_NODE:
2405 case MASC_NODE:
2406 case RMAP_NODE:
2407 case VTY_NODE:
2408 vty->node = CONFIG_NODE;
2409 break;
2410 case BGP_VPNV4_NODE:
2411 case BGP_IPV4_NODE:
2412 case BGP_IPV4M_NODE:
2413 case BGP_IPV6_NODE:
paul1e836592005-08-22 22:39:56 +00002414 case BGP_IPV6M_NODE:
paul718e3742002-12-13 20:15:29 +00002415 vty->node = BGP_NODE;
2416 break;
2417 case KEYCHAIN_KEY_NODE:
2418 vty->node = KEYCHAIN_NODE;
2419 break;
2420 default:
2421 break;
2422 }
2423 return CMD_SUCCESS;
2424}
2425
2426/* quit is alias of exit. */
2427ALIAS (config_exit,
2428 config_quit_cmd,
2429 "quit",
2430 "Exit current mode and down to previous mode\n")
2431
2432/* End of configuration. */
2433DEFUN (config_end,
2434 config_end_cmd,
2435 "end",
2436 "End current mode and change to enable mode.")
2437{
2438 switch (vty->node)
2439 {
2440 case VIEW_NODE:
2441 case ENABLE_NODE:
Paul Jakma62687ff2008-08-23 14:27:06 +01002442 case RESTRICTED_NODE:
paul718e3742002-12-13 20:15:29 +00002443 /* Nothing to do. */
2444 break;
2445 case CONFIG_NODE:
2446 case INTERFACE_NODE:
2447 case ZEBRA_NODE:
2448 case RIP_NODE:
2449 case RIPNG_NODE:
2450 case BGP_NODE:
2451 case BGP_VPNV4_NODE:
2452 case BGP_IPV4_NODE:
2453 case BGP_IPV4M_NODE:
2454 case BGP_IPV6_NODE:
paul1e836592005-08-22 22:39:56 +00002455 case BGP_IPV6M_NODE:
paul718e3742002-12-13 20:15:29 +00002456 case RMAP_NODE:
2457 case OSPF_NODE:
2458 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00002459 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00002460 case KEYCHAIN_NODE:
2461 case KEYCHAIN_KEY_NODE:
2462 case MASC_NODE:
2463 case VTY_NODE:
2464 vty_config_unlock (vty);
2465 vty->node = ENABLE_NODE;
2466 break;
2467 default:
2468 break;
2469 }
2470 return CMD_SUCCESS;
2471}
2472
2473/* Show version. */
2474DEFUN (show_version,
2475 show_version_cmd,
2476 "show version",
2477 SHOW_STR
2478 "Displays zebra version\n")
2479{
hasso12f6ea22005-03-07 08:35:39 +00002480 vty_out (vty, "Quagga %s (%s).%s", QUAGGA_VERSION, host.name?host.name:"",
2481 VTY_NEWLINE);
hasso6590f2c2004-10-19 20:40:08 +00002482 vty_out (vty, "%s%s", QUAGGA_COPYRIGHT, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00002483
2484 return CMD_SUCCESS;
2485}
2486
2487/* Help display function for all node. */
2488DEFUN (config_help,
2489 config_help_cmd,
2490 "help",
2491 "Description of the interactive help system\n")
2492{
2493 vty_out (vty,
hasso6590f2c2004-10-19 20:40:08 +00002494 "Quagga VTY provides advanced help feature. When you need help,%s\
paul718e3742002-12-13 20:15:29 +00002495anytime at the command line please press '?'.%s\
2496%s\
2497If nothing matches, the help list will be empty and you must backup%s\
2498 until entering a '?' shows the available options.%s\
2499Two styles of help are provided:%s\
25001. Full help is available when you are ready to enter a%s\
2501command argument (e.g. 'show ?') and describes each possible%s\
2502argument.%s\
25032. Partial help is provided when an abbreviated argument is entered%s\
2504 and you want to know what arguments match the input%s\
2505 (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2506 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2507 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
2508 return CMD_SUCCESS;
2509}
2510
2511/* Help display function for all node. */
2512DEFUN (config_list,
2513 config_list_cmd,
2514 "list",
2515 "Print command list\n")
2516{
hasso8c328f12004-10-05 21:01:23 +00002517 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002518 struct cmd_node *cnode = vector_slot (cmdvec, vty->node);
2519 struct cmd_element *cmd;
2520
paul55468c82005-03-14 20:19:01 +00002521 for (i = 0; i < vector_active (cnode->cmd_vector); i++)
paul4275b1d2005-03-09 13:42:23 +00002522 if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL
2523 && !(cmd->attr == CMD_ATTR_DEPRECATED
2524 || cmd->attr == CMD_ATTR_HIDDEN))
paul718e3742002-12-13 20:15:29 +00002525 vty_out (vty, " %s%s", cmd->string,
2526 VTY_NEWLINE);
2527 return CMD_SUCCESS;
2528}
2529
2530/* Write current configuration into file. */
2531DEFUN (config_write_file,
2532 config_write_file_cmd,
2533 "write file",
2534 "Write running configuration to memory, network, or terminal\n"
2535 "Write to configuration file\n")
2536{
hasso8c328f12004-10-05 21:01:23 +00002537 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002538 int fd;
2539 struct cmd_node *node;
2540 char *config_file;
2541 char *config_file_tmp = NULL;
2542 char *config_file_sav = NULL;
paul05865c92005-10-26 05:49:54 +00002543 int ret = CMD_WARNING;
paul718e3742002-12-13 20:15:29 +00002544 struct vty *file_vty;
2545
2546 /* Check and see if we are operating under vtysh configuration */
2547 if (host.config == NULL)
2548 {
2549 vty_out (vty, "Can't save to configuration file, using vtysh.%s",
2550 VTY_NEWLINE);
2551 return CMD_WARNING;
2552 }
2553
2554 /* Get filename. */
2555 config_file = host.config;
2556
paul05865c92005-10-26 05:49:54 +00002557 config_file_sav =
2558 XMALLOC (MTYPE_TMP, strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
paul718e3742002-12-13 20:15:29 +00002559 strcpy (config_file_sav, config_file);
2560 strcat (config_file_sav, CONF_BACKUP_EXT);
2561
2562
paul05865c92005-10-26 05:49:54 +00002563 config_file_tmp = XMALLOC (MTYPE_TMP, strlen (config_file) + 8);
paul718e3742002-12-13 20:15:29 +00002564 sprintf (config_file_tmp, "%s.XXXXXX", config_file);
2565
2566 /* Open file to configuration write. */
2567 fd = mkstemp (config_file_tmp);
2568 if (fd < 0)
2569 {
2570 vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
2571 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002572 goto finished;
paul718e3742002-12-13 20:15:29 +00002573 }
2574
2575 /* Make vty for configuration file. */
2576 file_vty = vty_new ();
2577 file_vty->fd = fd;
2578 file_vty->type = VTY_FILE;
2579
2580 /* Config file header print. */
2581 vty_out (file_vty, "!\n! Zebra configuration saved from vty\n! ");
2582 vty_time_print (file_vty, 1);
2583 vty_out (file_vty, "!\n");
2584
paul55468c82005-03-14 20:19:01 +00002585 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +00002586 if ((node = vector_slot (cmdvec, i)) && node->func)
2587 {
2588 if ((*node->func) (file_vty))
2589 vty_out (file_vty, "!\n");
2590 }
2591 vty_close (file_vty);
2592
2593 if (unlink (config_file_sav) != 0)
2594 if (errno != ENOENT)
2595 {
2596 vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
2597 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002598 goto finished;
paul718e3742002-12-13 20:15:29 +00002599 }
2600 if (link (config_file, config_file_sav) != 0)
2601 {
2602 vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
2603 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002604 goto finished;
paul718e3742002-12-13 20:15:29 +00002605 }
2606 sync ();
2607 if (unlink (config_file) != 0)
2608 {
2609 vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
2610 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002611 goto finished;
paul718e3742002-12-13 20:15:29 +00002612 }
2613 if (link (config_file_tmp, config_file) != 0)
2614 {
2615 vty_out (vty, "Can't save configuration file %s.%s", config_file,
2616 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002617 goto finished;
paul718e3742002-12-13 20:15:29 +00002618 }
paul718e3742002-12-13 20:15:29 +00002619 sync ();
2620
gdtaa593d52003-12-22 20:15:53 +00002621 if (chmod (config_file, CONFIGFILE_MASK) != 0)
2622 {
2623 vty_out (vty, "Can't chmod configuration file %s: %s (%d).%s",
ajs6099b3b2004-11-20 02:06:59 +00002624 config_file, safe_strerror(errno), errno, VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002625 goto finished;
gdtaa593d52003-12-22 20:15:53 +00002626 }
2627
paul718e3742002-12-13 20:15:29 +00002628 vty_out (vty, "Configuration saved to %s%s", config_file,
2629 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002630 ret = CMD_SUCCESS;
2631
2632finished:
2633 unlink (config_file_tmp);
2634 XFREE (MTYPE_TMP, config_file_tmp);
2635 XFREE (MTYPE_TMP, config_file_sav);
2636 return ret;
paul718e3742002-12-13 20:15:29 +00002637}
2638
2639ALIAS (config_write_file,
2640 config_write_cmd,
2641 "write",
2642 "Write running configuration to memory, network, or terminal\n")
2643
2644ALIAS (config_write_file,
2645 config_write_memory_cmd,
2646 "write memory",
2647 "Write running configuration to memory, network, or terminal\n"
2648 "Write configuration to the file (same as write file)\n")
2649
2650ALIAS (config_write_file,
2651 copy_runningconfig_startupconfig_cmd,
2652 "copy running-config startup-config",
2653 "Copy configuration\n"
2654 "Copy running config to... \n"
2655 "Copy running config to startup config (same as write file)\n")
2656
2657/* Write current configuration into the terminal. */
2658DEFUN (config_write_terminal,
2659 config_write_terminal_cmd,
2660 "write terminal",
2661 "Write running configuration to memory, network, or terminal\n"
2662 "Write to terminal\n")
2663{
hasso8c328f12004-10-05 21:01:23 +00002664 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002665 struct cmd_node *node;
2666
2667 if (vty->type == VTY_SHELL_SERV)
2668 {
paul55468c82005-03-14 20:19:01 +00002669 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +00002670 if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
2671 {
2672 if ((*node->func) (vty))
2673 vty_out (vty, "!%s", VTY_NEWLINE);
2674 }
2675 }
2676 else
2677 {
2678 vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
2679 VTY_NEWLINE);
2680 vty_out (vty, "!%s", VTY_NEWLINE);
2681
paul55468c82005-03-14 20:19:01 +00002682 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +00002683 if ((node = vector_slot (cmdvec, i)) && node->func)
2684 {
2685 if ((*node->func) (vty))
2686 vty_out (vty, "!%s", VTY_NEWLINE);
2687 }
2688 vty_out (vty, "end%s",VTY_NEWLINE);
2689 }
2690 return CMD_SUCCESS;
2691}
2692
2693/* Write current configuration into the terminal. */
2694ALIAS (config_write_terminal,
2695 show_running_config_cmd,
2696 "show running-config",
2697 SHOW_STR
2698 "running configuration\n")
2699
2700/* Write startup configuration into the terminal. */
2701DEFUN (show_startup_config,
2702 show_startup_config_cmd,
2703 "show startup-config",
2704 SHOW_STR
2705 "Contentes of startup configuration\n")
2706{
2707 char buf[BUFSIZ];
2708 FILE *confp;
2709
2710 confp = fopen (host.config, "r");
2711 if (confp == NULL)
2712 {
2713 vty_out (vty, "Can't open configuration file [%s]%s",
2714 host.config, VTY_NEWLINE);
2715 return CMD_WARNING;
2716 }
2717
2718 while (fgets (buf, BUFSIZ, confp))
2719 {
2720 char *cp = buf;
2721
2722 while (*cp != '\r' && *cp != '\n' && *cp != '\0')
2723 cp++;
2724 *cp = '\0';
2725
2726 vty_out (vty, "%s%s", buf, VTY_NEWLINE);
2727 }
2728
2729 fclose (confp);
2730
2731 return CMD_SUCCESS;
2732}
2733
2734/* Hostname configuration */
2735DEFUN (config_hostname,
2736 hostname_cmd,
2737 "hostname WORD",
2738 "Set system's network name\n"
2739 "This system's network name\n")
2740{
2741 if (!isalpha((int) *argv[0]))
2742 {
2743 vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
2744 return CMD_WARNING;
2745 }
2746
2747 if (host.name)
paul05865c92005-10-26 05:49:54 +00002748 XFREE (MTYPE_HOST, host.name);
paul718e3742002-12-13 20:15:29 +00002749
paul05865c92005-10-26 05:49:54 +00002750 host.name = XSTRDUP (MTYPE_HOST, argv[0]);
paul718e3742002-12-13 20:15:29 +00002751 return CMD_SUCCESS;
2752}
2753
2754DEFUN (config_no_hostname,
2755 no_hostname_cmd,
2756 "no hostname [HOSTNAME]",
2757 NO_STR
2758 "Reset system's network name\n"
2759 "Host name of this router\n")
2760{
2761 if (host.name)
paul05865c92005-10-26 05:49:54 +00002762 XFREE (MTYPE_HOST, host.name);
paul718e3742002-12-13 20:15:29 +00002763 host.name = NULL;
2764 return CMD_SUCCESS;
2765}
2766
2767/* VTY interface password set. */
2768DEFUN (config_password, password_cmd,
2769 "password (8|) WORD",
2770 "Assign the terminal connection password\n"
2771 "Specifies a HIDDEN password will follow\n"
2772 "dummy string \n"
2773 "The HIDDEN line password string\n")
2774{
2775 /* Argument check. */
2776 if (argc == 0)
2777 {
2778 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2779 return CMD_WARNING;
2780 }
2781
2782 if (argc == 2)
2783 {
2784 if (*argv[0] == '8')
2785 {
2786 if (host.password)
paul05865c92005-10-26 05:49:54 +00002787 XFREE (MTYPE_HOST, host.password);
paul718e3742002-12-13 20:15:29 +00002788 host.password = NULL;
2789 if (host.password_encrypt)
paul05865c92005-10-26 05:49:54 +00002790 XFREE (MTYPE_HOST, host.password_encrypt);
2791 host.password_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
paul718e3742002-12-13 20:15:29 +00002792 return CMD_SUCCESS;
2793 }
2794 else
2795 {
2796 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2797 return CMD_WARNING;
2798 }
2799 }
2800
2801 if (!isalnum ((int) *argv[0]))
2802 {
2803 vty_out (vty,
2804 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2805 return CMD_WARNING;
2806 }
2807
2808 if (host.password)
paul05865c92005-10-26 05:49:54 +00002809 XFREE (MTYPE_HOST, host.password);
paul718e3742002-12-13 20:15:29 +00002810 host.password = NULL;
2811
2812 if (host.encrypt)
2813 {
2814 if (host.password_encrypt)
paul05865c92005-10-26 05:49:54 +00002815 XFREE (MTYPE_HOST, host.password_encrypt);
2816 host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
paul718e3742002-12-13 20:15:29 +00002817 }
2818 else
paul05865c92005-10-26 05:49:54 +00002819 host.password = XSTRDUP (MTYPE_HOST, argv[0]);
paul718e3742002-12-13 20:15:29 +00002820
2821 return CMD_SUCCESS;
2822}
2823
2824ALIAS (config_password, password_text_cmd,
2825 "password LINE",
2826 "Assign the terminal connection password\n"
2827 "The UNENCRYPTED (cleartext) line password\n")
2828
2829/* VTY enable password set. */
2830DEFUN (config_enable_password, enable_password_cmd,
2831 "enable password (8|) WORD",
2832 "Modify enable password parameters\n"
2833 "Assign the privileged level password\n"
2834 "Specifies a HIDDEN password will follow\n"
2835 "dummy string \n"
2836 "The HIDDEN 'enable' password string\n")
2837{
2838 /* Argument check. */
2839 if (argc == 0)
2840 {
2841 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2842 return CMD_WARNING;
2843 }
2844
2845 /* Crypt type is specified. */
2846 if (argc == 2)
2847 {
2848 if (*argv[0] == '8')
2849 {
2850 if (host.enable)
paul05865c92005-10-26 05:49:54 +00002851 XFREE (MTYPE_HOST, host.enable);
paul718e3742002-12-13 20:15:29 +00002852 host.enable = NULL;
2853
2854 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002855 XFREE (MTYPE_HOST, host.enable_encrypt);
2856 host.enable_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
paul718e3742002-12-13 20:15:29 +00002857
2858 return CMD_SUCCESS;
2859 }
2860 else
2861 {
2862 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2863 return CMD_WARNING;
2864 }
2865 }
2866
2867 if (!isalnum ((int) *argv[0]))
2868 {
2869 vty_out (vty,
2870 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2871 return CMD_WARNING;
2872 }
2873
2874 if (host.enable)
paul05865c92005-10-26 05:49:54 +00002875 XFREE (MTYPE_HOST, host.enable);
paul718e3742002-12-13 20:15:29 +00002876 host.enable = NULL;
2877
2878 /* Plain password input. */
2879 if (host.encrypt)
2880 {
2881 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002882 XFREE (MTYPE_HOST, host.enable_encrypt);
2883 host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
paul718e3742002-12-13 20:15:29 +00002884 }
2885 else
paul05865c92005-10-26 05:49:54 +00002886 host.enable = XSTRDUP (MTYPE_HOST, argv[0]);
paul718e3742002-12-13 20:15:29 +00002887
2888 return CMD_SUCCESS;
2889}
2890
2891ALIAS (config_enable_password,
2892 enable_password_text_cmd,
2893 "enable password LINE",
2894 "Modify enable password parameters\n"
2895 "Assign the privileged level password\n"
2896 "The UNENCRYPTED (cleartext) 'enable' password\n")
2897
2898/* VTY enable password delete. */
2899DEFUN (no_config_enable_password, no_enable_password_cmd,
2900 "no enable password",
2901 NO_STR
2902 "Modify enable password parameters\n"
2903 "Assign the privileged level password\n")
2904{
2905 if (host.enable)
paul05865c92005-10-26 05:49:54 +00002906 XFREE (MTYPE_HOST, host.enable);
paul718e3742002-12-13 20:15:29 +00002907 host.enable = NULL;
2908
2909 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002910 XFREE (MTYPE_HOST, host.enable_encrypt);
paul718e3742002-12-13 20:15:29 +00002911 host.enable_encrypt = NULL;
2912
2913 return CMD_SUCCESS;
2914}
2915
2916DEFUN (service_password_encrypt,
2917 service_password_encrypt_cmd,
2918 "service password-encryption",
2919 "Set up miscellaneous service\n"
2920 "Enable encrypted passwords\n")
2921{
2922 if (host.encrypt)
2923 return CMD_SUCCESS;
2924
2925 host.encrypt = 1;
2926
2927 if (host.password)
2928 {
2929 if (host.password_encrypt)
paul05865c92005-10-26 05:49:54 +00002930 XFREE (MTYPE_HOST, host.password_encrypt);
2931 host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.password));
paul718e3742002-12-13 20:15:29 +00002932 }
2933 if (host.enable)
2934 {
2935 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002936 XFREE (MTYPE_HOST, host.enable_encrypt);
2937 host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.enable));
paul718e3742002-12-13 20:15:29 +00002938 }
2939
2940 return CMD_SUCCESS;
2941}
2942
2943DEFUN (no_service_password_encrypt,
2944 no_service_password_encrypt_cmd,
2945 "no service password-encryption",
2946 NO_STR
2947 "Set up miscellaneous service\n"
2948 "Enable encrypted passwords\n")
2949{
2950 if (! host.encrypt)
2951 return CMD_SUCCESS;
2952
2953 host.encrypt = 0;
2954
2955 if (host.password_encrypt)
paul05865c92005-10-26 05:49:54 +00002956 XFREE (MTYPE_HOST, host.password_encrypt);
paul718e3742002-12-13 20:15:29 +00002957 host.password_encrypt = NULL;
2958
2959 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002960 XFREE (MTYPE_HOST, host.enable_encrypt);
paul718e3742002-12-13 20:15:29 +00002961 host.enable_encrypt = NULL;
2962
2963 return CMD_SUCCESS;
2964}
2965
2966DEFUN (config_terminal_length, config_terminal_length_cmd,
2967 "terminal length <0-512>",
2968 "Set terminal line parameters\n"
2969 "Set number of lines on a screen\n"
2970 "Number of lines on screen (0 for no pausing)\n")
2971{
2972 int lines;
2973 char *endptr = NULL;
2974
2975 lines = strtol (argv[0], &endptr, 10);
2976 if (lines < 0 || lines > 512 || *endptr != '\0')
2977 {
2978 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2979 return CMD_WARNING;
2980 }
2981 vty->lines = lines;
2982
2983 return CMD_SUCCESS;
2984}
2985
2986DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
2987 "terminal no length",
2988 "Set terminal line parameters\n"
2989 NO_STR
2990 "Set number of lines on a screen\n")
2991{
2992 vty->lines = -1;
2993 return CMD_SUCCESS;
2994}
2995
2996DEFUN (service_terminal_length, service_terminal_length_cmd,
2997 "service terminal-length <0-512>",
2998 "Set up miscellaneous service\n"
2999 "System wide terminal length configuration\n"
3000 "Number of lines of VTY (0 means no line control)\n")
3001{
3002 int lines;
3003 char *endptr = NULL;
3004
3005 lines = strtol (argv[0], &endptr, 10);
3006 if (lines < 0 || lines > 512 || *endptr != '\0')
3007 {
3008 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
3009 return CMD_WARNING;
3010 }
3011 host.lines = lines;
3012
3013 return CMD_SUCCESS;
3014}
3015
3016DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
3017 "no service terminal-length [<0-512>]",
3018 NO_STR
3019 "Set up miscellaneous service\n"
3020 "System wide terminal length configuration\n"
3021 "Number of lines of VTY (0 means no line control)\n")
3022{
3023 host.lines = -1;
3024 return CMD_SUCCESS;
3025}
3026
ajs2885f722004-12-17 23:16:33 +00003027DEFUN_HIDDEN (do_echo,
3028 echo_cmd,
3029 "echo .MESSAGE",
3030 "Echo a message back to the vty\n"
3031 "The message to echo\n")
3032{
3033 char *message;
3034
ajsf6834d42005-01-28 20:28:35 +00003035 vty_out (vty, "%s%s", ((message = argv_concat(argv, argc, 0)) ? message : ""),
3036 VTY_NEWLINE);
3037 if (message)
3038 XFREE(MTYPE_TMP, message);
ajs2885f722004-12-17 23:16:33 +00003039 return CMD_SUCCESS;
3040}
3041
ajs274a4a42004-12-07 15:39:31 +00003042DEFUN (config_logmsg,
3043 config_logmsg_cmd,
3044 "logmsg "LOG_LEVELS" .MESSAGE",
3045 "Send a message to enabled logging destinations\n"
3046 LOG_LEVEL_DESC
3047 "The message to send\n")
3048{
3049 int level;
3050 char *message;
3051
3052 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3053 return CMD_ERR_NO_MATCH;
3054
ajsf6834d42005-01-28 20:28:35 +00003055 zlog(NULL, level, ((message = argv_concat(argv, argc, 1)) ? message : ""));
3056 if (message)
3057 XFREE(MTYPE_TMP, message);
ajs274a4a42004-12-07 15:39:31 +00003058 return CMD_SUCCESS;
3059}
3060
3061DEFUN (show_logging,
3062 show_logging_cmd,
3063 "show logging",
3064 SHOW_STR
3065 "Show current logging configuration\n")
3066{
3067 struct zlog *zl = zlog_default;
3068
3069 vty_out (vty, "Syslog logging: ");
3070 if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED)
3071 vty_out (vty, "disabled");
3072 else
3073 vty_out (vty, "level %s, facility %s, ident %s",
3074 zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]],
3075 facility_name(zl->facility), zl->ident);
3076 vty_out (vty, "%s", VTY_NEWLINE);
3077
3078 vty_out (vty, "Stdout logging: ");
3079 if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED)
3080 vty_out (vty, "disabled");
3081 else
3082 vty_out (vty, "level %s",
3083 zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
3084 vty_out (vty, "%s", VTY_NEWLINE);
3085
3086 vty_out (vty, "Monitor logging: ");
3087 if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
3088 vty_out (vty, "disabled");
3089 else
3090 vty_out (vty, "level %s",
3091 zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
3092 vty_out (vty, "%s", VTY_NEWLINE);
3093
3094 vty_out (vty, "File logging: ");
3095 if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) ||
3096 !zl->fp)
3097 vty_out (vty, "disabled");
3098 else
3099 vty_out (vty, "level %s, filename %s",
3100 zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
3101 zl->filename);
3102 vty_out (vty, "%s", VTY_NEWLINE);
3103
3104 vty_out (vty, "Protocol name: %s%s",
3105 zlog_proto_names[zl->protocol], VTY_NEWLINE);
3106 vty_out (vty, "Record priority: %s%s",
3107 (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE);
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +00003108 vty_out (vty, "Timestamp precision: %d%s",
3109 zl->timestamp_precision, VTY_NEWLINE);
ajs274a4a42004-12-07 15:39:31 +00003110
3111 return CMD_SUCCESS;
3112}
3113
paul718e3742002-12-13 20:15:29 +00003114DEFUN (config_log_stdout,
3115 config_log_stdout_cmd,
3116 "log stdout",
3117 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003118 "Set stdout logging level\n")
paul718e3742002-12-13 20:15:29 +00003119{
ajs274a4a42004-12-07 15:39:31 +00003120 zlog_set_level (NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl);
3121 return CMD_SUCCESS;
3122}
3123
3124DEFUN (config_log_stdout_level,
3125 config_log_stdout_level_cmd,
3126 "log stdout "LOG_LEVELS,
3127 "Logging control\n"
3128 "Set stdout logging level\n"
3129 LOG_LEVEL_DESC)
3130{
3131 int level;
3132
3133 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3134 return CMD_ERR_NO_MATCH;
3135 zlog_set_level (NULL, ZLOG_DEST_STDOUT, level);
paul718e3742002-12-13 20:15:29 +00003136 return CMD_SUCCESS;
3137}
3138
3139DEFUN (no_config_log_stdout,
3140 no_config_log_stdout_cmd,
ajs274a4a42004-12-07 15:39:31 +00003141 "no log stdout [LEVEL]",
paul718e3742002-12-13 20:15:29 +00003142 NO_STR
3143 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003144 "Cancel logging to stdout\n"
3145 "Logging level\n")
paul718e3742002-12-13 20:15:29 +00003146{
ajs274a4a42004-12-07 15:39:31 +00003147 zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED);
paul718e3742002-12-13 20:15:29 +00003148 return CMD_SUCCESS;
3149}
3150
ajs274a4a42004-12-07 15:39:31 +00003151DEFUN (config_log_monitor,
3152 config_log_monitor_cmd,
3153 "log monitor",
paul718e3742002-12-13 20:15:29 +00003154 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003155 "Set terminal line (monitor) logging level\n")
3156{
3157 zlog_set_level (NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl);
3158 return CMD_SUCCESS;
3159}
3160
3161DEFUN (config_log_monitor_level,
3162 config_log_monitor_level_cmd,
3163 "log monitor "LOG_LEVELS,
3164 "Logging control\n"
3165 "Set terminal line (monitor) logging level\n"
3166 LOG_LEVEL_DESC)
3167{
3168 int level;
3169
3170 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3171 return CMD_ERR_NO_MATCH;
3172 zlog_set_level (NULL, ZLOG_DEST_MONITOR, level);
3173 return CMD_SUCCESS;
3174}
3175
3176DEFUN (no_config_log_monitor,
3177 no_config_log_monitor_cmd,
3178 "no log monitor [LEVEL]",
3179 NO_STR
3180 "Logging control\n"
3181 "Disable terminal line (monitor) logging\n"
3182 "Logging level\n")
3183{
3184 zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
3185 return CMD_SUCCESS;
3186}
3187
3188static int
3189set_log_file(struct vty *vty, const char *fname, int loglevel)
paul718e3742002-12-13 20:15:29 +00003190{
3191 int ret;
paul9035efa2004-10-10 11:56:56 +00003192 char *p = NULL;
3193 const char *fullpath;
3194
paul718e3742002-12-13 20:15:29 +00003195 /* Path detection. */
ajs274a4a42004-12-07 15:39:31 +00003196 if (! IS_DIRECTORY_SEP (*fname))
paul718e3742002-12-13 20:15:29 +00003197 {
paul9035efa2004-10-10 11:56:56 +00003198 char cwd[MAXPATHLEN+1];
3199 cwd[MAXPATHLEN] = '\0';
3200
3201 if (getcwd (cwd, MAXPATHLEN) == NULL)
3202 {
3203 zlog_err ("config_log_file: Unable to alloc mem!");
3204 return CMD_WARNING;
3205 }
3206
ajs274a4a42004-12-07 15:39:31 +00003207 if ( (p = XMALLOC (MTYPE_TMP, strlen (cwd) + strlen (fname) + 2))
paul9035efa2004-10-10 11:56:56 +00003208 == NULL)
3209 {
3210 zlog_err ("config_log_file: Unable to alloc mem!");
3211 return CMD_WARNING;
3212 }
ajs274a4a42004-12-07 15:39:31 +00003213 sprintf (p, "%s/%s", cwd, fname);
paul9035efa2004-10-10 11:56:56 +00003214 fullpath = p;
paul718e3742002-12-13 20:15:29 +00003215 }
3216 else
ajs274a4a42004-12-07 15:39:31 +00003217 fullpath = fname;
paul718e3742002-12-13 20:15:29 +00003218
ajs274a4a42004-12-07 15:39:31 +00003219 ret = zlog_set_file (NULL, fullpath, loglevel);
paul718e3742002-12-13 20:15:29 +00003220
paul9035efa2004-10-10 11:56:56 +00003221 if (p)
3222 XFREE (MTYPE_TMP, p);
3223
paul718e3742002-12-13 20:15:29 +00003224 if (!ret)
3225 {
ajs274a4a42004-12-07 15:39:31 +00003226 vty_out (vty, "can't open logfile %s\n", fname);
paul718e3742002-12-13 20:15:29 +00003227 return CMD_WARNING;
3228 }
3229
3230 if (host.logfile)
paul05865c92005-10-26 05:49:54 +00003231 XFREE (MTYPE_HOST, host.logfile);
paul718e3742002-12-13 20:15:29 +00003232
paul05865c92005-10-26 05:49:54 +00003233 host.logfile = XSTRDUP (MTYPE_HOST, fname);
paul718e3742002-12-13 20:15:29 +00003234
3235 return CMD_SUCCESS;
3236}
3237
ajs274a4a42004-12-07 15:39:31 +00003238DEFUN (config_log_file,
3239 config_log_file_cmd,
3240 "log file FILENAME",
3241 "Logging control\n"
3242 "Logging to file\n"
3243 "Logging filename\n")
3244{
3245 return set_log_file(vty, argv[0], zlog_default->default_lvl);
3246}
3247
3248DEFUN (config_log_file_level,
3249 config_log_file_level_cmd,
3250 "log file FILENAME "LOG_LEVELS,
3251 "Logging control\n"
3252 "Logging to file\n"
3253 "Logging filename\n"
3254 LOG_LEVEL_DESC)
3255{
3256 int level;
3257
3258 if ((level = level_match(argv[1])) == ZLOG_DISABLED)
3259 return CMD_ERR_NO_MATCH;
3260 return set_log_file(vty, argv[0], level);
3261}
3262
paul718e3742002-12-13 20:15:29 +00003263DEFUN (no_config_log_file,
3264 no_config_log_file_cmd,
3265 "no log file [FILENAME]",
3266 NO_STR
3267 "Logging control\n"
3268 "Cancel logging to file\n"
3269 "Logging file name\n")
3270{
3271 zlog_reset_file (NULL);
3272
3273 if (host.logfile)
paul05865c92005-10-26 05:49:54 +00003274 XFREE (MTYPE_HOST, host.logfile);
paul718e3742002-12-13 20:15:29 +00003275
3276 host.logfile = NULL;
3277
3278 return CMD_SUCCESS;
3279}
3280
ajs274a4a42004-12-07 15:39:31 +00003281ALIAS (no_config_log_file,
3282 no_config_log_file_level_cmd,
3283 "no log file FILENAME LEVEL",
3284 NO_STR
3285 "Logging control\n"
3286 "Cancel logging to file\n"
3287 "Logging file name\n"
3288 "Logging level\n")
3289
paul718e3742002-12-13 20:15:29 +00003290DEFUN (config_log_syslog,
3291 config_log_syslog_cmd,
3292 "log syslog",
3293 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003294 "Set syslog logging level\n")
paul718e3742002-12-13 20:15:29 +00003295{
ajs274a4a42004-12-07 15:39:31 +00003296 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
paul12ab19f2003-07-26 06:14:55 +00003297 return CMD_SUCCESS;
3298}
3299
ajs274a4a42004-12-07 15:39:31 +00003300DEFUN (config_log_syslog_level,
3301 config_log_syslog_level_cmd,
3302 "log syslog "LOG_LEVELS,
paul12ab19f2003-07-26 06:14:55 +00003303 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003304 "Set syslog logging level\n"
3305 LOG_LEVEL_DESC)
paul12ab19f2003-07-26 06:14:55 +00003306{
ajs274a4a42004-12-07 15:39:31 +00003307 int level;
paul12ab19f2003-07-26 06:14:55 +00003308
ajs274a4a42004-12-07 15:39:31 +00003309 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3310 return CMD_ERR_NO_MATCH;
3311 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, level);
3312 return CMD_SUCCESS;
3313}
paul12ab19f2003-07-26 06:14:55 +00003314
ajs274a4a42004-12-07 15:39:31 +00003315DEFUN_DEPRECATED (config_log_syslog_facility,
3316 config_log_syslog_facility_cmd,
3317 "log syslog facility "LOG_FACILITIES,
3318 "Logging control\n"
3319 "Logging goes to syslog\n"
3320 "(Deprecated) Facility parameter for syslog messages\n"
3321 LOG_FACILITY_DESC)
3322{
3323 int facility;
paul12ab19f2003-07-26 06:14:55 +00003324
ajs274a4a42004-12-07 15:39:31 +00003325 if ((facility = facility_match(argv[0])) < 0)
3326 return CMD_ERR_NO_MATCH;
3327
3328 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
paul12ab19f2003-07-26 06:14:55 +00003329 zlog_default->facility = facility;
paul718e3742002-12-13 20:15:29 +00003330 return CMD_SUCCESS;
3331}
3332
3333DEFUN (no_config_log_syslog,
3334 no_config_log_syslog_cmd,
ajs274a4a42004-12-07 15:39:31 +00003335 "no log syslog [LEVEL]",
paul718e3742002-12-13 20:15:29 +00003336 NO_STR
3337 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003338 "Cancel logging to syslog\n"
3339 "Logging level\n")
paul718e3742002-12-13 20:15:29 +00003340{
ajs274a4a42004-12-07 15:39:31 +00003341 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
paul718e3742002-12-13 20:15:29 +00003342 return CMD_SUCCESS;
3343}
3344
paul12ab19f2003-07-26 06:14:55 +00003345ALIAS (no_config_log_syslog,
3346 no_config_log_syslog_facility_cmd,
ajs274a4a42004-12-07 15:39:31 +00003347 "no log syslog facility "LOG_FACILITIES,
paul12ab19f2003-07-26 06:14:55 +00003348 NO_STR
3349 "Logging control\n"
3350 "Logging goes to syslog\n"
3351 "Facility parameter for syslog messages\n"
ajs274a4a42004-12-07 15:39:31 +00003352 LOG_FACILITY_DESC)
paul12ab19f2003-07-26 06:14:55 +00003353
ajs274a4a42004-12-07 15:39:31 +00003354DEFUN (config_log_facility,
3355 config_log_facility_cmd,
3356 "log facility "LOG_FACILITIES,
paul718e3742002-12-13 20:15:29 +00003357 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003358 "Facility parameter for syslog messages\n"
3359 LOG_FACILITY_DESC)
paul718e3742002-12-13 20:15:29 +00003360{
ajs274a4a42004-12-07 15:39:31 +00003361 int facility;
3362
3363 if ((facility = facility_match(argv[0])) < 0)
3364 return CMD_ERR_NO_MATCH;
3365 zlog_default->facility = facility;
3366 return CMD_SUCCESS;
paul718e3742002-12-13 20:15:29 +00003367}
3368
ajs274a4a42004-12-07 15:39:31 +00003369DEFUN (no_config_log_facility,
3370 no_config_log_facility_cmd,
3371 "no log facility [FACILITY]",
paul718e3742002-12-13 20:15:29 +00003372 NO_STR
3373 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003374 "Reset syslog facility to default (daemon)\n"
3375 "Syslog facility\n")
paul718e3742002-12-13 20:15:29 +00003376{
ajs274a4a42004-12-07 15:39:31 +00003377 zlog_default->facility = LOG_DAEMON;
3378 return CMD_SUCCESS;
3379}
3380
3381DEFUN_DEPRECATED (config_log_trap,
3382 config_log_trap_cmd,
3383 "log trap "LOG_LEVELS,
3384 "Logging control\n"
3385 "(Deprecated) Set logging level and default for all destinations\n"
3386 LOG_LEVEL_DESC)
3387{
3388 int new_level ;
3389 int i;
3390
3391 if ((new_level = level_match(argv[0])) == ZLOG_DISABLED)
3392 return CMD_ERR_NO_MATCH;
3393
3394 zlog_default->default_lvl = new_level;
3395 for (i = 0; i < ZLOG_NUM_DESTS; i++)
3396 if (zlog_default->maxlvl[i] != ZLOG_DISABLED)
3397 zlog_default->maxlvl[i] = new_level;
3398 return CMD_SUCCESS;
3399}
3400
3401DEFUN_DEPRECATED (no_config_log_trap,
3402 no_config_log_trap_cmd,
3403 "no log trap [LEVEL]",
3404 NO_STR
3405 "Logging control\n"
3406 "Permit all logging information\n"
3407 "Logging level\n")
3408{
3409 zlog_default->default_lvl = LOG_DEBUG;
paul718e3742002-12-13 20:15:29 +00003410 return CMD_SUCCESS;
3411}
3412
3413DEFUN (config_log_record_priority,
3414 config_log_record_priority_cmd,
3415 "log record-priority",
3416 "Logging control\n"
3417 "Log the priority of the message within the message\n")
3418{
3419 zlog_default->record_priority = 1 ;
3420 return CMD_SUCCESS;
3421}
3422
3423DEFUN (no_config_log_record_priority,
3424 no_config_log_record_priority_cmd,
3425 "no log record-priority",
3426 NO_STR
3427 "Logging control\n"
3428 "Do not log the priority of the message within the message\n")
3429{
3430 zlog_default->record_priority = 0 ;
3431 return CMD_SUCCESS;
3432}
3433
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +00003434DEFUN (config_log_timestamp_precision,
3435 config_log_timestamp_precision_cmd,
3436 "log timestamp precision <0-6>",
3437 "Logging control\n"
3438 "Timestamp configuration\n"
3439 "Set the timestamp precision\n"
3440 "Number of subsecond digits\n")
3441{
3442 if (argc != 1)
3443 {
3444 vty_out (vty, "Insufficient arguments%s", VTY_NEWLINE);
3445 return CMD_WARNING;
3446 }
3447
3448 VTY_GET_INTEGER_RANGE("Timestamp Precision",
3449 zlog_default->timestamp_precision, argv[0], 0, 6);
3450 return CMD_SUCCESS;
3451}
3452
3453DEFUN (no_config_log_timestamp_precision,
3454 no_config_log_timestamp_precision_cmd,
3455 "no log timestamp precision",
3456 NO_STR
3457 "Logging control\n"
3458 "Timestamp configuration\n"
3459 "Reset the timestamp precision to the default value of 0\n")
3460{
3461 zlog_default->timestamp_precision = 0 ;
3462 return CMD_SUCCESS;
3463}
3464
paul3b0c5d92005-03-08 10:43:43 +00003465DEFUN (banner_motd_file,
3466 banner_motd_file_cmd,
3467 "banner motd file [FILE]",
3468 "Set banner\n"
3469 "Banner for motd\n"
3470 "Banner from a file\n"
3471 "Filename\n")
3472{
paulb45da6f2005-03-08 15:16:57 +00003473 if (host.motdfile)
paul05865c92005-10-26 05:49:54 +00003474 XFREE (MTYPE_HOST, host.motdfile);
3475 host.motdfile = XSTRDUP (MTYPE_HOST, argv[0]);
paulb45da6f2005-03-08 15:16:57 +00003476
paul3b0c5d92005-03-08 10:43:43 +00003477 return CMD_SUCCESS;
3478}
paul718e3742002-12-13 20:15:29 +00003479
3480DEFUN (banner_motd_default,
3481 banner_motd_default_cmd,
3482 "banner motd default",
3483 "Set banner string\n"
3484 "Strings for motd\n"
3485 "Default string\n")
3486{
3487 host.motd = default_motd;
3488 return CMD_SUCCESS;
3489}
3490
3491DEFUN (no_banner_motd,
3492 no_banner_motd_cmd,
3493 "no banner motd",
3494 NO_STR
3495 "Set banner string\n"
3496 "Strings for motd\n")
3497{
3498 host.motd = NULL;
paul22085182005-03-08 16:00:12 +00003499 if (host.motdfile)
paul05865c92005-10-26 05:49:54 +00003500 XFREE (MTYPE_HOST, host.motdfile);
paul3b0c5d92005-03-08 10:43:43 +00003501 host.motdfile = NULL;
paul718e3742002-12-13 20:15:29 +00003502 return CMD_SUCCESS;
3503}
3504
3505/* Set config filename. Called from vty.c */
3506void
3507host_config_set (char *filename)
3508{
paul05865c92005-10-26 05:49:54 +00003509 host.config = XSTRDUP (MTYPE_HOST, filename);
paul718e3742002-12-13 20:15:29 +00003510}
3511
3512void
3513install_default (enum node_type node)
3514{
3515 install_element (node, &config_exit_cmd);
3516 install_element (node, &config_quit_cmd);
3517 install_element (node, &config_end_cmd);
3518 install_element (node, &config_help_cmd);
3519 install_element (node, &config_list_cmd);
3520
3521 install_element (node, &config_write_terminal_cmd);
3522 install_element (node, &config_write_file_cmd);
3523 install_element (node, &config_write_memory_cmd);
3524 install_element (node, &config_write_cmd);
3525 install_element (node, &show_running_config_cmd);
3526}
3527
3528/* Initialize command interface. Install basic nodes and commands. */
3529void
3530cmd_init (int terminal)
3531{
3532 /* Allocate initial top vector of commands. */
3533 cmdvec = vector_init (VECTOR_MIN_SIZE);
3534
3535 /* Default host value settings. */
3536 host.name = NULL;
3537 host.password = NULL;
3538 host.enable = NULL;
3539 host.logfile = NULL;
3540 host.config = NULL;
3541 host.lines = -1;
3542 host.motd = default_motd;
paul3b0c5d92005-03-08 10:43:43 +00003543 host.motdfile = NULL;
paul718e3742002-12-13 20:15:29 +00003544
3545 /* Install top nodes. */
3546 install_node (&view_node, NULL);
3547 install_node (&enable_node, NULL);
3548 install_node (&auth_node, NULL);
3549 install_node (&auth_enable_node, NULL);
Paul Jakma62687ff2008-08-23 14:27:06 +01003550 install_node (&restricted_node, NULL);
paul718e3742002-12-13 20:15:29 +00003551 install_node (&config_node, config_write_host);
3552
3553 /* Each node's basic commands. */
3554 install_element (VIEW_NODE, &show_version_cmd);
3555 if (terminal)
3556 {
3557 install_element (VIEW_NODE, &config_list_cmd);
3558 install_element (VIEW_NODE, &config_exit_cmd);
3559 install_element (VIEW_NODE, &config_quit_cmd);
3560 install_element (VIEW_NODE, &config_help_cmd);
3561 install_element (VIEW_NODE, &config_enable_cmd);
3562 install_element (VIEW_NODE, &config_terminal_length_cmd);
3563 install_element (VIEW_NODE, &config_terminal_no_length_cmd);
ajs274a4a42004-12-07 15:39:31 +00003564 install_element (VIEW_NODE, &show_logging_cmd);
ajs2885f722004-12-17 23:16:33 +00003565 install_element (VIEW_NODE, &echo_cmd);
Paul Jakma62687ff2008-08-23 14:27:06 +01003566
3567 install_element (RESTRICTED_NODE, &config_list_cmd);
3568 install_element (RESTRICTED_NODE, &config_exit_cmd);
3569 install_element (RESTRICTED_NODE, &config_quit_cmd);
3570 install_element (RESTRICTED_NODE, &config_help_cmd);
3571 install_element (RESTRICTED_NODE, &config_enable_cmd);
3572 install_element (RESTRICTED_NODE, &config_terminal_length_cmd);
3573 install_element (RESTRICTED_NODE, &config_terminal_no_length_cmd);
3574 install_element (RESTRICTED_NODE, &echo_cmd);
paul718e3742002-12-13 20:15:29 +00003575 }
3576
3577 if (terminal)
3578 {
3579 install_default (ENABLE_NODE);
3580 install_element (ENABLE_NODE, &config_disable_cmd);
3581 install_element (ENABLE_NODE, &config_terminal_cmd);
3582 install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
3583 }
3584 install_element (ENABLE_NODE, &show_startup_config_cmd);
3585 install_element (ENABLE_NODE, &show_version_cmd);
paul718e3742002-12-13 20:15:29 +00003586
3587 if (terminal)
paul718e3742002-12-13 20:15:29 +00003588 {
hassoe7168df2004-10-03 20:11:32 +00003589 install_element (ENABLE_NODE, &config_terminal_length_cmd);
3590 install_element (ENABLE_NODE, &config_terminal_no_length_cmd);
ajs274a4a42004-12-07 15:39:31 +00003591 install_element (ENABLE_NODE, &show_logging_cmd);
ajs2885f722004-12-17 23:16:33 +00003592 install_element (ENABLE_NODE, &echo_cmd);
ajs274a4a42004-12-07 15:39:31 +00003593 install_element (ENABLE_NODE, &config_logmsg_cmd);
hassoe7168df2004-10-03 20:11:32 +00003594
3595 install_default (CONFIG_NODE);
hassoea8e9d92004-10-07 21:32:14 +00003596 }
3597
3598 install_element (CONFIG_NODE, &hostname_cmd);
3599 install_element (CONFIG_NODE, &no_hostname_cmd);
hassoe7168df2004-10-03 20:11:32 +00003600
hassoea8e9d92004-10-07 21:32:14 +00003601 if (terminal)
3602 {
hassoe7168df2004-10-03 20:11:32 +00003603 install_element (CONFIG_NODE, &password_cmd);
3604 install_element (CONFIG_NODE, &password_text_cmd);
3605 install_element (CONFIG_NODE, &enable_password_cmd);
3606 install_element (CONFIG_NODE, &enable_password_text_cmd);
3607 install_element (CONFIG_NODE, &no_enable_password_cmd);
3608
paul718e3742002-12-13 20:15:29 +00003609 install_element (CONFIG_NODE, &config_log_stdout_cmd);
ajs274a4a42004-12-07 15:39:31 +00003610 install_element (CONFIG_NODE, &config_log_stdout_level_cmd);
paul718e3742002-12-13 20:15:29 +00003611 install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
ajs274a4a42004-12-07 15:39:31 +00003612 install_element (CONFIG_NODE, &config_log_monitor_cmd);
3613 install_element (CONFIG_NODE, &config_log_monitor_level_cmd);
3614 install_element (CONFIG_NODE, &no_config_log_monitor_cmd);
paul718e3742002-12-13 20:15:29 +00003615 install_element (CONFIG_NODE, &config_log_file_cmd);
ajs274a4a42004-12-07 15:39:31 +00003616 install_element (CONFIG_NODE, &config_log_file_level_cmd);
paul718e3742002-12-13 20:15:29 +00003617 install_element (CONFIG_NODE, &no_config_log_file_cmd);
ajs274a4a42004-12-07 15:39:31 +00003618 install_element (CONFIG_NODE, &no_config_log_file_level_cmd);
paul718e3742002-12-13 20:15:29 +00003619 install_element (CONFIG_NODE, &config_log_syslog_cmd);
ajs274a4a42004-12-07 15:39:31 +00003620 install_element (CONFIG_NODE, &config_log_syslog_level_cmd);
paul12ab19f2003-07-26 06:14:55 +00003621 install_element (CONFIG_NODE, &config_log_syslog_facility_cmd);
paul718e3742002-12-13 20:15:29 +00003622 install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
paul12ab19f2003-07-26 06:14:55 +00003623 install_element (CONFIG_NODE, &no_config_log_syslog_facility_cmd);
ajs274a4a42004-12-07 15:39:31 +00003624 install_element (CONFIG_NODE, &config_log_facility_cmd);
3625 install_element (CONFIG_NODE, &no_config_log_facility_cmd);
paul718e3742002-12-13 20:15:29 +00003626 install_element (CONFIG_NODE, &config_log_trap_cmd);
3627 install_element (CONFIG_NODE, &no_config_log_trap_cmd);
3628 install_element (CONFIG_NODE, &config_log_record_priority_cmd);
3629 install_element (CONFIG_NODE, &no_config_log_record_priority_cmd);
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +00003630 install_element (CONFIG_NODE, &config_log_timestamp_precision_cmd);
3631 install_element (CONFIG_NODE, &no_config_log_timestamp_precision_cmd);
paul718e3742002-12-13 20:15:29 +00003632 install_element (CONFIG_NODE, &service_password_encrypt_cmd);
3633 install_element (CONFIG_NODE, &no_service_password_encrypt_cmd);
3634 install_element (CONFIG_NODE, &banner_motd_default_cmd);
paul3b0c5d92005-03-08 10:43:43 +00003635 install_element (CONFIG_NODE, &banner_motd_file_cmd);
paul718e3742002-12-13 20:15:29 +00003636 install_element (CONFIG_NODE, &no_banner_motd_cmd);
3637 install_element (CONFIG_NODE, &service_terminal_length_cmd);
3638 install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
paul718e3742002-12-13 20:15:29 +00003639
paul354d1192005-04-25 16:26:42 +00003640 install_element (VIEW_NODE, &show_thread_cpu_cmd);
3641 install_element (ENABLE_NODE, &show_thread_cpu_cmd);
Paul Jakma62687ff2008-08-23 14:27:06 +01003642 install_element (RESTRICTED_NODE, &show_thread_cpu_cmd);
paul354d1192005-04-25 16:26:42 +00003643 install_element (VIEW_NODE, &show_work_queues_cmd);
3644 install_element (ENABLE_NODE, &show_work_queues_cmd);
paul9ab68122003-01-18 01:16:20 +00003645 }
paul718e3742002-12-13 20:15:29 +00003646 srand(time(NULL));
3647}