blob: f3d96ede0134f26cd3a53cb356eb9ac02cf82408 [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
56struct cmd_node auth_enable_node =
57{
58 AUTH_ENABLE_NODE,
59 "Password: ",
60};
61
62struct cmd_node enable_node =
63{
64 ENABLE_NODE,
65 "%s# ",
66};
67
68struct cmd_node config_node =
69{
70 CONFIG_NODE,
71 "%s(config)# ",
72 1
73};
hasso6590f2c2004-10-19 20:40:08 +000074
75/* Default motd string. */
76const char *default_motd =
77"\r\n\
78Hello, this is " QUAGGA_PROGNAME " (version " QUAGGA_VERSION ").\r\n\
79" QUAGGA_COPYRIGHT "\r\n\
80\r\n";
81
ajs274a4a42004-12-07 15:39:31 +000082
83static struct facility_map {
84 int facility;
85 const char *name;
86 size_t match;
87} syslog_facilities[] =
88 {
89 { LOG_KERN, "kern", 1 },
90 { LOG_USER, "user", 2 },
91 { LOG_MAIL, "mail", 1 },
92 { LOG_DAEMON, "daemon", 1 },
93 { LOG_AUTH, "auth", 1 },
94 { LOG_SYSLOG, "syslog", 1 },
95 { LOG_LPR, "lpr", 2 },
96 { LOG_NEWS, "news", 1 },
97 { LOG_UUCP, "uucp", 2 },
98 { LOG_CRON, "cron", 1 },
99#ifdef LOG_FTP
100 { LOG_FTP, "ftp", 1 },
101#endif
102 { LOG_LOCAL0, "local0", 6 },
103 { LOG_LOCAL1, "local1", 6 },
104 { LOG_LOCAL2, "local2", 6 },
105 { LOG_LOCAL3, "local3", 6 },
106 { LOG_LOCAL4, "local4", 6 },
107 { LOG_LOCAL5, "local5", 6 },
108 { LOG_LOCAL6, "local6", 6 },
109 { LOG_LOCAL7, "local7", 6 },
110 { 0, NULL, 0 },
111 };
112
113static const char *
114facility_name(int facility)
115{
116 struct facility_map *fm;
117
118 for (fm = syslog_facilities; fm->name; fm++)
119 if (fm->facility == facility)
120 return fm->name;
121 return "";
122}
123
124static int
125facility_match(const char *str)
126{
127 struct facility_map *fm;
128
129 for (fm = syslog_facilities; fm->name; fm++)
130 if (!strncmp(str,fm->name,fm->match))
131 return fm->facility;
132 return -1;
133}
134
135static int
136level_match(const char *s)
137{
138 int level ;
139
140 for ( level = 0 ; zlog_priority [level] != NULL ; level ++ )
141 if (!strncmp (s, zlog_priority[level], 2))
142 return level;
143 return ZLOG_DISABLED;
144}
145
ajscb585b62005-01-14 17:09:38 +0000146/* This is called from main when a daemon is invoked with -v or --version. */
hasso6590f2c2004-10-19 20:40:08 +0000147void
148print_version (const char *progname)
149{
ajscb585b62005-01-14 17:09:38 +0000150 printf ("%s version %s\n", progname, QUAGGA_VERSION);
151 printf ("%s\n", QUAGGA_COPYRIGHT);
hasso6590f2c2004-10-19 20:40:08 +0000152}
153
paul718e3742002-12-13 20:15:29 +0000154
155/* Utility function to concatenate argv argument into a single string
156 with inserting ' ' character between each argument. */
157char *
paul42d49862004-10-13 05:22:18 +0000158argv_concat (const char **argv, int argc, int shift)
paul718e3742002-12-13 20:15:29 +0000159{
160 int i;
ajsf6834d42005-01-28 20:28:35 +0000161 size_t len;
paul718e3742002-12-13 20:15:29 +0000162 char *str;
ajsf6834d42005-01-28 20:28:35 +0000163 char *p;
paul718e3742002-12-13 20:15:29 +0000164
ajsf6834d42005-01-28 20:28:35 +0000165 len = 0;
166 for (i = shift; i < argc; i++)
167 len += strlen(argv[i])+1;
168 if (!len)
169 return NULL;
170 p = str = XMALLOC(MTYPE_TMP, len);
paul718e3742002-12-13 20:15:29 +0000171 for (i = shift; i < argc; i++)
172 {
ajsf6834d42005-01-28 20:28:35 +0000173 size_t arglen;
174 memcpy(p, argv[i], (arglen = strlen(argv[i])));
175 p += arglen;
176 *p++ = ' ';
paul718e3742002-12-13 20:15:29 +0000177 }
ajsf6834d42005-01-28 20:28:35 +0000178 *(p-1) = '\0';
paul718e3742002-12-13 20:15:29 +0000179 return str;
180}
181
182/* Install top node of command vector. */
183void
184install_node (struct cmd_node *node,
185 int (*func) (struct vty *))
186{
187 vector_set_index (cmdvec, node->node, node);
188 node->func = func;
189 node->cmd_vector = vector_init (VECTOR_MIN_SIZE);
190}
191
192/* Compare two command's string. Used in sort_node (). */
ajs274a4a42004-12-07 15:39:31 +0000193static int
paul718e3742002-12-13 20:15:29 +0000194cmp_node (const void *p, const void *q)
195{
paul8cc41982005-05-06 21:25:49 +0000196 const struct cmd_element *a = *(struct cmd_element **)p;
197 const struct cmd_element *b = *(struct cmd_element **)q;
paul718e3742002-12-13 20:15:29 +0000198
199 return strcmp (a->string, b->string);
200}
201
ajs274a4a42004-12-07 15:39:31 +0000202static int
paul718e3742002-12-13 20:15:29 +0000203cmp_desc (const void *p, const void *q)
204{
paul8cc41982005-05-06 21:25:49 +0000205 const struct desc *a = *(struct desc **)p;
206 const struct desc *b = *(struct desc **)q;
paul718e3742002-12-13 20:15:29 +0000207
208 return strcmp (a->cmd, b->cmd);
209}
210
211/* Sort each node's command element according to command string. */
212void
213sort_node ()
214{
hasso8c328f12004-10-05 21:01:23 +0000215 unsigned int i, j;
paul718e3742002-12-13 20:15:29 +0000216 struct cmd_node *cnode;
217 vector descvec;
218 struct cmd_element *cmd_element;
219
paul55468c82005-03-14 20:19:01 +0000220 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +0000221 if ((cnode = vector_slot (cmdvec, i)) != NULL)
222 {
223 vector cmd_vector = cnode->cmd_vector;
paul55468c82005-03-14 20:19:01 +0000224 qsort (cmd_vector->index, vector_active (cmd_vector),
paulb8961472005-03-14 17:35:52 +0000225 sizeof (void *), cmp_node);
paul718e3742002-12-13 20:15:29 +0000226
paul55468c82005-03-14 20:19:01 +0000227 for (j = 0; j < vector_active (cmd_vector); j++)
paulb8961472005-03-14 17:35:52 +0000228 if ((cmd_element = vector_slot (cmd_vector, j)) != NULL
paul55468c82005-03-14 20:19:01 +0000229 && vector_active (cmd_element->strvec))
paul718e3742002-12-13 20:15:29 +0000230 {
231 descvec = vector_slot (cmd_element->strvec,
paul55468c82005-03-14 20:19:01 +0000232 vector_active (cmd_element->strvec) - 1);
233 qsort (descvec->index, vector_active (descvec),
paulb8961472005-03-14 17:35:52 +0000234 sizeof (void *), cmp_desc);
paul718e3742002-12-13 20:15:29 +0000235 }
236 }
237}
238
239/* Breaking up string into each command piece. I assume given
240 character is separated by a space character. Return value is a
241 vector which includes char ** data element. */
242vector
hassoea8e9d92004-10-07 21:32:14 +0000243cmd_make_strvec (const char *string)
paul718e3742002-12-13 20:15:29 +0000244{
hassoea8e9d92004-10-07 21:32:14 +0000245 const char *cp, *start;
246 char *token;
paul718e3742002-12-13 20:15:29 +0000247 int strlen;
248 vector strvec;
249
250 if (string == NULL)
251 return NULL;
252
253 cp = string;
254
255 /* Skip white spaces. */
256 while (isspace ((int) *cp) && *cp != '\0')
257 cp++;
258
259 /* Return if there is only white spaces */
260 if (*cp == '\0')
261 return NULL;
262
263 if (*cp == '!' || *cp == '#')
264 return NULL;
265
266 /* Prepare return vector. */
267 strvec = vector_init (VECTOR_MIN_SIZE);
268
269 /* Copy each command piece and set into vector. */
270 while (1)
271 {
272 start = cp;
273 while (!(isspace ((int) *cp) || *cp == '\r' || *cp == '\n') &&
274 *cp != '\0')
275 cp++;
276 strlen = cp - start;
277 token = XMALLOC (MTYPE_STRVEC, strlen + 1);
278 memcpy (token, start, strlen);
279 *(token + strlen) = '\0';
280 vector_set (strvec, token);
281
282 while ((isspace ((int) *cp) || *cp == '\n' || *cp == '\r') &&
283 *cp != '\0')
284 cp++;
285
286 if (*cp == '\0')
287 return strvec;
288 }
289}
290
291/* Free allocated string vector. */
292void
293cmd_free_strvec (vector v)
294{
hasso8c328f12004-10-05 21:01:23 +0000295 unsigned int i;
paul718e3742002-12-13 20:15:29 +0000296 char *cp;
297
298 if (!v)
299 return;
300
paul55468c82005-03-14 20:19:01 +0000301 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +0000302 if ((cp = vector_slot (v, i)) != NULL)
303 XFREE (MTYPE_STRVEC, cp);
304
305 vector_free (v);
306}
307
308/* Fetch next description. Used in cmd_make_descvec(). */
ajs274a4a42004-12-07 15:39:31 +0000309static char *
hasso6ad96ea2004-10-07 19:33:46 +0000310cmd_desc_str (const char **string)
paul718e3742002-12-13 20:15:29 +0000311{
hasso6ad96ea2004-10-07 19:33:46 +0000312 const char *cp, *start;
313 char *token;
paul718e3742002-12-13 20:15:29 +0000314 int strlen;
315
316 cp = *string;
317
318 if (cp == NULL)
319 return NULL;
320
321 /* Skip white spaces. */
322 while (isspace ((int) *cp) && *cp != '\0')
323 cp++;
324
325 /* Return if there is only white spaces */
326 if (*cp == '\0')
327 return NULL;
328
329 start = cp;
330
331 while (!(*cp == '\r' || *cp == '\n') && *cp != '\0')
332 cp++;
333
334 strlen = cp - start;
335 token = XMALLOC (MTYPE_STRVEC, strlen + 1);
336 memcpy (token, start, strlen);
337 *(token + strlen) = '\0';
338
339 *string = cp;
340
341 return token;
342}
343
344/* New string vector. */
ajs274a4a42004-12-07 15:39:31 +0000345static vector
hasso8c328f12004-10-05 21:01:23 +0000346cmd_make_descvec (const char *string, const char *descstr)
paul718e3742002-12-13 20:15:29 +0000347{
348 int multiple = 0;
hasso8c328f12004-10-05 21:01:23 +0000349 const char *sp;
paul718e3742002-12-13 20:15:29 +0000350 char *token;
351 int len;
hasso8c328f12004-10-05 21:01:23 +0000352 const char *cp;
353 const char *dp;
paul718e3742002-12-13 20:15:29 +0000354 vector allvec;
355 vector strvec = NULL;
356 struct desc *desc;
357
358 cp = string;
359 dp = descstr;
360
361 if (cp == NULL)
362 return NULL;
363
364 allvec = vector_init (VECTOR_MIN_SIZE);
365
366 while (1)
367 {
368 while (isspace ((int) *cp) && *cp != '\0')
369 cp++;
370
371 if (*cp == '(')
372 {
373 multiple = 1;
374 cp++;
375 }
376 if (*cp == ')')
377 {
378 multiple = 0;
379 cp++;
380 }
381 if (*cp == '|')
382 {
383 if (! multiple)
384 {
385 fprintf (stderr, "Command parse error!: %s\n", string);
386 exit (1);
387 }
388 cp++;
389 }
390
391 while (isspace ((int) *cp) && *cp != '\0')
392 cp++;
393
394 if (*cp == '(')
395 {
396 multiple = 1;
397 cp++;
398 }
399
400 if (*cp == '\0')
401 return allvec;
402
403 sp = cp;
404
405 while (! (isspace ((int) *cp) || *cp == '\r' || *cp == '\n' || *cp == ')' || *cp == '|') && *cp != '\0')
406 cp++;
407
408 len = cp - sp;
409
410 token = XMALLOC (MTYPE_STRVEC, len + 1);
411 memcpy (token, sp, len);
412 *(token + len) = '\0';
413
414 desc = XCALLOC (MTYPE_DESC, sizeof (struct desc));
415 desc->cmd = token;
416 desc->str = cmd_desc_str (&dp);
417
418 if (multiple)
419 {
420 if (multiple == 1)
421 {
422 strvec = vector_init (VECTOR_MIN_SIZE);
423 vector_set (allvec, strvec);
424 }
425 multiple++;
426 }
427 else
428 {
429 strvec = vector_init (VECTOR_MIN_SIZE);
430 vector_set (allvec, strvec);
431 }
432 vector_set (strvec, desc);
433 }
434}
435
436/* Count mandantory string vector size. This is to determine inputed
437 command has enough command length. */
ajs274a4a42004-12-07 15:39:31 +0000438static int
paul718e3742002-12-13 20:15:29 +0000439cmd_cmdsize (vector strvec)
440{
hasso8c328f12004-10-05 21:01:23 +0000441 unsigned int i;
paul718e3742002-12-13 20:15:29 +0000442 int size = 0;
443 vector descvec;
paulb8961472005-03-14 17:35:52 +0000444 struct desc *desc;
paul718e3742002-12-13 20:15:29 +0000445
paul55468c82005-03-14 20:19:01 +0000446 for (i = 0; i < vector_active (strvec); i++)
paulb8961472005-03-14 17:35:52 +0000447 if ((descvec = vector_slot (strvec, i)) != NULL)
paul718e3742002-12-13 20:15:29 +0000448 {
paul55468c82005-03-14 20:19:01 +0000449 if ((vector_active (descvec)) == 1
paulb8961472005-03-14 17:35:52 +0000450 && (desc = vector_slot (descvec, 0)) != NULL)
paul718e3742002-12-13 20:15:29 +0000451 {
hasso8c328f12004-10-05 21:01:23 +0000452 if (desc->cmd == NULL || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +0000453 return size;
454 else
455 size++;
456 }
457 else
458 size++;
459 }
460 return size;
461}
462
463/* Return prompt character of specified node. */
hasso8c328f12004-10-05 21:01:23 +0000464const char *
paul718e3742002-12-13 20:15:29 +0000465cmd_prompt (enum node_type node)
466{
467 struct cmd_node *cnode;
468
469 cnode = vector_slot (cmdvec, node);
470 return cnode->prompt;
471}
472
473/* Install a command into a node. */
474void
475install_element (enum node_type ntype, struct cmd_element *cmd)
476{
477 struct cmd_node *cnode;
pauleb820af2005-09-05 11:54:13 +0000478
479 /* cmd_init hasn't been called */
480 if (!cmdvec)
481 return;
482
paul718e3742002-12-13 20:15:29 +0000483 cnode = vector_slot (cmdvec, ntype);
484
485 if (cnode == NULL)
486 {
487 fprintf (stderr, "Command node %d doesn't exist, please check it\n",
488 ntype);
489 exit (1);
490 }
491
492 vector_set (cnode->cmd_vector, cmd);
493
494 cmd->strvec = cmd_make_descvec (cmd->string, cmd->doc);
495 cmd->cmdsize = cmd_cmdsize (cmd->strvec);
496}
497
498static unsigned char itoa64[] =
499"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
500
ajs274a4a42004-12-07 15:39:31 +0000501static void
paul718e3742002-12-13 20:15:29 +0000502to64(char *s, long v, int n)
503{
504 while (--n >= 0)
505 {
506 *s++ = itoa64[v&0x3f];
507 v >>= 6;
508 }
509}
510
ajs274a4a42004-12-07 15:39:31 +0000511static char *
512zencrypt (const char *passwd)
paul718e3742002-12-13 20:15:29 +0000513{
514 char salt[6];
515 struct timeval tv;
516 char *crypt (const char *, const char *);
517
518 gettimeofday(&tv,0);
519
520 to64(&salt[0], random(), 3);
521 to64(&salt[3], tv.tv_usec, 3);
522 salt[5] = '\0';
523
524 return crypt (passwd, salt);
525}
526
527/* This function write configuration of this host. */
ajs274a4a42004-12-07 15:39:31 +0000528static int
paul718e3742002-12-13 20:15:29 +0000529config_write_host (struct vty *vty)
530{
531 if (host.name)
532 vty_out (vty, "hostname %s%s", host.name, VTY_NEWLINE);
533
534 if (host.encrypt)
535 {
536 if (host.password_encrypt)
537 vty_out (vty, "password 8 %s%s", host.password_encrypt, VTY_NEWLINE);
538 if (host.enable_encrypt)
539 vty_out (vty, "enable password 8 %s%s", host.enable_encrypt, VTY_NEWLINE);
540 }
541 else
542 {
543 if (host.password)
544 vty_out (vty, "password %s%s", host.password, VTY_NEWLINE);
545 if (host.enable)
546 vty_out (vty, "enable password %s%s", host.enable, VTY_NEWLINE);
547 }
548
ajs274a4a42004-12-07 15:39:31 +0000549 if (zlog_default->default_lvl != LOG_DEBUG)
ajs82146b82004-12-07 17:15:55 +0000550 {
551 vty_out (vty, "! N.B. The 'log trap' command is deprecated.%s",
552 VTY_NEWLINE);
553 vty_out (vty, "log trap %s%s",
554 zlog_priority[zlog_default->default_lvl], VTY_NEWLINE);
555 }
paul718e3742002-12-13 20:15:29 +0000556
ajs274a4a42004-12-07 15:39:31 +0000557 if (host.logfile && (zlog_default->maxlvl[ZLOG_DEST_FILE] != ZLOG_DISABLED))
paul12ab19f2003-07-26 06:14:55 +0000558 {
ajs274a4a42004-12-07 15:39:31 +0000559 vty_out (vty, "log file %s", host.logfile);
560 if (zlog_default->maxlvl[ZLOG_DEST_FILE] != zlog_default->default_lvl)
561 vty_out (vty, " %s",
562 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_FILE]]);
paul12ab19f2003-07-26 06:14:55 +0000563 vty_out (vty, "%s", VTY_NEWLINE);
564 }
ajs274a4a42004-12-07 15:39:31 +0000565
566 if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != ZLOG_DISABLED)
567 {
568 vty_out (vty, "log stdout");
569 if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != zlog_default->default_lvl)
570 vty_out (vty, " %s",
571 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_STDOUT]]);
572 vty_out (vty, "%s", VTY_NEWLINE);
573 }
574
575 if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
576 vty_out(vty,"no log monitor%s",VTY_NEWLINE);
577 else if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] != zlog_default->default_lvl)
578 vty_out(vty,"log monitor %s%s",
579 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_MONITOR]],VTY_NEWLINE);
580
581 if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED)
582 {
583 vty_out (vty, "log syslog");
584 if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != zlog_default->default_lvl)
585 vty_out (vty, " %s",
586 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_SYSLOG]]);
587 vty_out (vty, "%s", VTY_NEWLINE);
588 }
589
590 if (zlog_default->facility != LOG_DAEMON)
591 vty_out (vty, "log facility %s%s",
592 facility_name(zlog_default->facility), VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +0000593
594 if (zlog_default->record_priority == 1)
595 vty_out (vty, "log record-priority%s", VTY_NEWLINE);
596
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +0000597 if (zlog_default->timestamp_precision > 0)
598 vty_out (vty, "log timestamp precision %d%s",
599 zlog_default->timestamp_precision, VTY_NEWLINE);
600
paul718e3742002-12-13 20:15:29 +0000601 if (host.advanced)
602 vty_out (vty, "service advanced-vty%s", VTY_NEWLINE);
603
604 if (host.encrypt)
605 vty_out (vty, "service password-encryption%s", VTY_NEWLINE);
606
607 if (host.lines >= 0)
608 vty_out (vty, "service terminal-length %d%s", host.lines,
609 VTY_NEWLINE);
610
paul3b0c5d92005-03-08 10:43:43 +0000611 if (host.motdfile)
612 vty_out (vty, "banner motd file %s%s", host.motdfile, VTY_NEWLINE);
613 else if (! host.motd)
paul718e3742002-12-13 20:15:29 +0000614 vty_out (vty, "no banner motd%s", VTY_NEWLINE);
615
616 return 1;
617}
618
619/* Utility function for getting command vector. */
ajs274a4a42004-12-07 15:39:31 +0000620static vector
paul718e3742002-12-13 20:15:29 +0000621cmd_node_vector (vector v, enum node_type ntype)
622{
623 struct cmd_node *cnode = vector_slot (v, ntype);
624 return cnode->cmd_vector;
625}
626
ajs274a4a42004-12-07 15:39:31 +0000627#if 0
628/* Filter command vector by symbol. This function is not actually used;
629 * should it be deleted? */
630static int
paul718e3742002-12-13 20:15:29 +0000631cmd_filter_by_symbol (char *command, char *symbol)
632{
633 int i, lim;
634
635 if (strcmp (symbol, "IPV4_ADDRESS") == 0)
636 {
637 i = 0;
638 lim = strlen (command);
639 while (i < lim)
640 {
641 if (! (isdigit ((int) command[i]) || command[i] == '.' || command[i] == '/'))
642 return 1;
643 i++;
644 }
645 return 0;
646 }
647 if (strcmp (symbol, "STRING") == 0)
648 {
649 i = 0;
650 lim = strlen (command);
651 while (i < lim)
652 {
653 if (! (isalpha ((int) command[i]) || command[i] == '_' || command[i] == '-'))
654 return 1;
655 i++;
656 }
657 return 0;
658 }
659 if (strcmp (symbol, "IFNAME") == 0)
660 {
661 i = 0;
662 lim = strlen (command);
663 while (i < lim)
664 {
665 if (! isalnum ((int) command[i]))
666 return 1;
667 i++;
668 }
669 return 0;
670 }
671 return 0;
672}
ajs274a4a42004-12-07 15:39:31 +0000673#endif
paul718e3742002-12-13 20:15:29 +0000674
675/* Completion match types. */
676enum match_type
677{
678 no_match,
679 extend_match,
680 ipv4_prefix_match,
681 ipv4_match,
682 ipv6_prefix_match,
683 ipv6_match,
684 range_match,
685 vararg_match,
686 partly_match,
687 exact_match
688};
689
ajs274a4a42004-12-07 15:39:31 +0000690static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000691cmd_ipv4_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000692{
hasso8c328f12004-10-05 21:01:23 +0000693 const char *sp;
paul718e3742002-12-13 20:15:29 +0000694 int dots = 0, nums = 0;
695 char buf[4];
696
697 if (str == NULL)
698 return partly_match;
699
700 for (;;)
701 {
702 memset (buf, 0, sizeof (buf));
703 sp = str;
704 while (*str != '\0')
705 {
706 if (*str == '.')
707 {
708 if (dots >= 3)
709 return no_match;
710
711 if (*(str + 1) == '.')
712 return no_match;
713
714 if (*(str + 1) == '\0')
715 return partly_match;
716
717 dots++;
718 break;
719 }
720 if (!isdigit ((int) *str))
721 return no_match;
722
723 str++;
724 }
725
726 if (str - sp > 3)
727 return no_match;
728
729 strncpy (buf, sp, str - sp);
730 if (atoi (buf) > 255)
731 return no_match;
732
733 nums++;
734
735 if (*str == '\0')
736 break;
737
738 str++;
739 }
740
741 if (nums < 4)
742 return partly_match;
743
744 return exact_match;
745}
746
ajs274a4a42004-12-07 15:39:31 +0000747static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000748cmd_ipv4_prefix_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000749{
hasso8c328f12004-10-05 21:01:23 +0000750 const char *sp;
paul718e3742002-12-13 20:15:29 +0000751 int dots = 0;
752 char buf[4];
753
754 if (str == NULL)
755 return partly_match;
756
757 for (;;)
758 {
759 memset (buf, 0, sizeof (buf));
760 sp = str;
761 while (*str != '\0' && *str != '/')
762 {
763 if (*str == '.')
764 {
765 if (dots == 3)
766 return no_match;
767
768 if (*(str + 1) == '.' || *(str + 1) == '/')
769 return no_match;
770
771 if (*(str + 1) == '\0')
772 return partly_match;
773
774 dots++;
775 break;
776 }
777
778 if (!isdigit ((int) *str))
779 return no_match;
780
781 str++;
782 }
783
784 if (str - sp > 3)
785 return no_match;
786
787 strncpy (buf, sp, str - sp);
788 if (atoi (buf) > 255)
789 return no_match;
790
791 if (dots == 3)
792 {
793 if (*str == '/')
794 {
795 if (*(str + 1) == '\0')
796 return partly_match;
797
798 str++;
799 break;
800 }
801 else if (*str == '\0')
802 return partly_match;
803 }
804
805 if (*str == '\0')
806 return partly_match;
807
808 str++;
809 }
810
811 sp = str;
812 while (*str != '\0')
813 {
814 if (!isdigit ((int) *str))
815 return no_match;
816
817 str++;
818 }
819
820 if (atoi (sp) > 32)
821 return no_match;
822
823 return exact_match;
824}
825
826#define IPV6_ADDR_STR "0123456789abcdefABCDEF:.%"
827#define IPV6_PREFIX_STR "0123456789abcdefABCDEF:.%/"
828#define STATE_START 1
829#define STATE_COLON 2
830#define STATE_DOUBLE 3
831#define STATE_ADDR 4
832#define STATE_DOT 5
833#define STATE_SLASH 6
834#define STATE_MASK 7
835
paul22e0a9e2003-07-11 17:55:46 +0000836#ifdef HAVE_IPV6
837
ajs274a4a42004-12-07 15:39:31 +0000838static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000839cmd_ipv6_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000840{
841 int state = STATE_START;
842 int colons = 0, nums = 0, double_colon = 0;
hasso8c328f12004-10-05 21:01:23 +0000843 const char *sp = NULL;
hasso726f9b22003-05-25 21:04:54 +0000844 struct sockaddr_in6 sin6_dummy;
845 int ret;
paul718e3742002-12-13 20:15:29 +0000846
847 if (str == NULL)
848 return partly_match;
849
850 if (strspn (str, IPV6_ADDR_STR) != strlen (str))
851 return no_match;
852
hasso726f9b22003-05-25 21:04:54 +0000853 /* use inet_pton that has a better support,
854 * for example inet_pton can support the automatic addresses:
855 * ::1.2.3.4
856 */
857 ret = inet_pton(AF_INET6, str, &sin6_dummy.sin6_addr);
858
859 if (ret == 1)
860 return exact_match;
861
paul718e3742002-12-13 20:15:29 +0000862 while (*str != '\0')
863 {
864 switch (state)
865 {
866 case STATE_START:
867 if (*str == ':')
868 {
869 if (*(str + 1) != ':' && *(str + 1) != '\0')
870 return no_match;
871 colons--;
872 state = STATE_COLON;
873 }
874 else
875 {
876 sp = str;
877 state = STATE_ADDR;
878 }
879
880 continue;
881 case STATE_COLON:
882 colons++;
883 if (*(str + 1) == ':')
884 state = STATE_DOUBLE;
885 else
886 {
887 sp = str + 1;
888 state = STATE_ADDR;
889 }
890 break;
891 case STATE_DOUBLE:
892 if (double_colon)
893 return no_match;
894
895 if (*(str + 1) == ':')
896 return no_match;
897 else
898 {
899 if (*(str + 1) != '\0')
900 colons++;
901 sp = str + 1;
902 state = STATE_ADDR;
903 }
904
905 double_colon++;
906 nums++;
907 break;
908 case STATE_ADDR:
909 if (*(str + 1) == ':' || *(str + 1) == '\0')
910 {
911 if (str - sp > 3)
912 return no_match;
913
914 nums++;
915 state = STATE_COLON;
916 }
917 if (*(str + 1) == '.')
918 state = STATE_DOT;
919 break;
920 case STATE_DOT:
921 state = STATE_ADDR;
922 break;
923 default:
924 break;
925 }
926
927 if (nums > 8)
928 return no_match;
929
930 if (colons > 7)
931 return no_match;
932
933 str++;
934 }
935
936#if 0
937 if (nums < 11)
938 return partly_match;
939#endif /* 0 */
940
941 return exact_match;
942}
943
ajs274a4a42004-12-07 15:39:31 +0000944static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000945cmd_ipv6_prefix_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000946{
947 int state = STATE_START;
948 int colons = 0, nums = 0, double_colon = 0;
949 int mask;
hasso8c328f12004-10-05 21:01:23 +0000950 const char *sp = NULL;
paul718e3742002-12-13 20:15:29 +0000951 char *endptr = NULL;
952
953 if (str == NULL)
954 return partly_match;
955
956 if (strspn (str, IPV6_PREFIX_STR) != strlen (str))
957 return no_match;
958
959 while (*str != '\0' && state != STATE_MASK)
960 {
961 switch (state)
962 {
963 case STATE_START:
964 if (*str == ':')
965 {
966 if (*(str + 1) != ':' && *(str + 1) != '\0')
967 return no_match;
968 colons--;
969 state = STATE_COLON;
970 }
971 else
972 {
973 sp = str;
974 state = STATE_ADDR;
975 }
976
977 continue;
978 case STATE_COLON:
979 colons++;
980 if (*(str + 1) == '/')
981 return no_match;
982 else if (*(str + 1) == ':')
983 state = STATE_DOUBLE;
984 else
985 {
986 sp = str + 1;
987 state = STATE_ADDR;
988 }
989 break;
990 case STATE_DOUBLE:
991 if (double_colon)
992 return no_match;
993
994 if (*(str + 1) == ':')
995 return no_match;
996 else
997 {
998 if (*(str + 1) != '\0' && *(str + 1) != '/')
999 colons++;
1000 sp = str + 1;
1001
1002 if (*(str + 1) == '/')
1003 state = STATE_SLASH;
1004 else
1005 state = STATE_ADDR;
1006 }
1007
1008 double_colon++;
1009 nums += 1;
1010 break;
1011 case STATE_ADDR:
1012 if (*(str + 1) == ':' || *(str + 1) == '.'
1013 || *(str + 1) == '\0' || *(str + 1) == '/')
1014 {
1015 if (str - sp > 3)
1016 return no_match;
1017
1018 for (; sp <= str; sp++)
1019 if (*sp == '/')
1020 return no_match;
1021
1022 nums++;
1023
1024 if (*(str + 1) == ':')
1025 state = STATE_COLON;
1026 else if (*(str + 1) == '.')
1027 state = STATE_DOT;
1028 else if (*(str + 1) == '/')
1029 state = STATE_SLASH;
1030 }
1031 break;
1032 case STATE_DOT:
1033 state = STATE_ADDR;
1034 break;
1035 case STATE_SLASH:
1036 if (*(str + 1) == '\0')
1037 return partly_match;
1038
1039 state = STATE_MASK;
1040 break;
1041 default:
1042 break;
1043 }
1044
1045 if (nums > 11)
1046 return no_match;
1047
1048 if (colons > 7)
1049 return no_match;
1050
1051 str++;
1052 }
1053
1054 if (state < STATE_MASK)
1055 return partly_match;
1056
1057 mask = strtol (str, &endptr, 10);
1058 if (*endptr != '\0')
1059 return no_match;
1060
1061 if (mask < 0 || mask > 128)
1062 return no_match;
1063
1064/* I don't know why mask < 13 makes command match partly.
1065 Forgive me to make this comments. I Want to set static default route
1066 because of lack of function to originate default in ospf6d; sorry
1067 yasu
1068 if (mask < 13)
1069 return partly_match;
1070*/
1071
1072 return exact_match;
1073}
1074
paul22e0a9e2003-07-11 17:55:46 +00001075#endif /* HAVE_IPV6 */
1076
paul718e3742002-12-13 20:15:29 +00001077#define DECIMAL_STRLEN_MAX 10
1078
ajs274a4a42004-12-07 15:39:31 +00001079static int
hasso8c328f12004-10-05 21:01:23 +00001080cmd_range_match (const char *range, const char *str)
paul718e3742002-12-13 20:15:29 +00001081{
1082 char *p;
1083 char buf[DECIMAL_STRLEN_MAX + 1];
1084 char *endptr = NULL;
1085 unsigned long min, max, val;
1086
1087 if (str == NULL)
1088 return 1;
1089
1090 val = strtoul (str, &endptr, 10);
1091 if (*endptr != '\0')
1092 return 0;
1093
1094 range++;
1095 p = strchr (range, '-');
1096 if (p == NULL)
1097 return 0;
1098 if (p - range > DECIMAL_STRLEN_MAX)
1099 return 0;
1100 strncpy (buf, range, p - range);
1101 buf[p - range] = '\0';
1102 min = strtoul (buf, &endptr, 10);
1103 if (*endptr != '\0')
1104 return 0;
1105
1106 range = p + 1;
1107 p = strchr (range, '>');
1108 if (p == NULL)
1109 return 0;
1110 if (p - range > DECIMAL_STRLEN_MAX)
1111 return 0;
1112 strncpy (buf, range, p - range);
1113 buf[p - range] = '\0';
1114 max = strtoul (buf, &endptr, 10);
1115 if (*endptr != '\0')
1116 return 0;
1117
1118 if (val < min || val > max)
1119 return 0;
1120
1121 return 1;
1122}
1123
1124/* Make completion match and return match type flag. */
ajs274a4a42004-12-07 15:39:31 +00001125static enum match_type
hasso8c328f12004-10-05 21:01:23 +00001126cmd_filter_by_completion (char *command, vector v, unsigned int index)
paul718e3742002-12-13 20:15:29 +00001127{
hasso8c328f12004-10-05 21:01:23 +00001128 unsigned int i;
1129 const char *str;
paul718e3742002-12-13 20:15:29 +00001130 struct cmd_element *cmd_element;
1131 enum match_type match_type;
1132 vector descvec;
1133 struct desc *desc;
paul909a2152005-03-14 17:41:45 +00001134
paul718e3742002-12-13 20:15:29 +00001135 match_type = no_match;
1136
1137 /* If command and cmd_element string does not match set NULL to vector */
paul55468c82005-03-14 20:19:01 +00001138 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001139 if ((cmd_element = vector_slot (v, i)) != NULL)
1140 {
paul55468c82005-03-14 20:19:01 +00001141 if (index >= vector_active (cmd_element->strvec))
paul718e3742002-12-13 20:15:29 +00001142 vector_slot (v, i) = NULL;
1143 else
1144 {
hasso8c328f12004-10-05 21:01:23 +00001145 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001146 int matched = 0;
1147
1148 descvec = vector_slot (cmd_element->strvec, index);
paul909a2152005-03-14 17:41:45 +00001149
paul55468c82005-03-14 20:19:01 +00001150 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001151 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001152 {
1153 str = desc->cmd;
1154
1155 if (CMD_VARARG (str))
1156 {
1157 if (match_type < vararg_match)
1158 match_type = vararg_match;
1159 matched++;
1160 }
1161 else if (CMD_RANGE (str))
1162 {
1163 if (cmd_range_match (str, command))
1164 {
1165 if (match_type < range_match)
1166 match_type = range_match;
paul718e3742002-12-13 20:15:29 +00001167
paul909a2152005-03-14 17:41:45 +00001168 matched++;
1169 }
1170 }
paul22e0a9e2003-07-11 17:55:46 +00001171#ifdef HAVE_IPV6
paul909a2152005-03-14 17:41:45 +00001172 else if (CMD_IPV6 (str))
1173 {
1174 if (cmd_ipv6_match (command))
1175 {
1176 if (match_type < ipv6_match)
1177 match_type = ipv6_match;
paul718e3742002-12-13 20:15:29 +00001178
paul909a2152005-03-14 17:41:45 +00001179 matched++;
1180 }
1181 }
1182 else if (CMD_IPV6_PREFIX (str))
1183 {
1184 if (cmd_ipv6_prefix_match (command))
1185 {
1186 if (match_type < ipv6_prefix_match)
1187 match_type = ipv6_prefix_match;
paul718e3742002-12-13 20:15:29 +00001188
paul909a2152005-03-14 17:41:45 +00001189 matched++;
1190 }
1191 }
1192#endif /* HAVE_IPV6 */
1193 else if (CMD_IPV4 (str))
1194 {
1195 if (cmd_ipv4_match (command))
1196 {
1197 if (match_type < ipv4_match)
1198 match_type = ipv4_match;
paul718e3742002-12-13 20:15:29 +00001199
paul909a2152005-03-14 17:41:45 +00001200 matched++;
1201 }
1202 }
1203 else if (CMD_IPV4_PREFIX (str))
1204 {
1205 if (cmd_ipv4_prefix_match (command))
1206 {
1207 if (match_type < ipv4_prefix_match)
1208 match_type = ipv4_prefix_match;
1209 matched++;
1210 }
1211 }
1212 else
1213 /* Check is this point's argument optional ? */
1214 if (CMD_OPTION (str) || CMD_VARIABLE (str))
1215 {
1216 if (match_type < extend_match)
1217 match_type = extend_match;
1218 matched++;
1219 }
1220 else if (strncmp (command, str, strlen (command)) == 0)
1221 {
1222 if (strcmp (command, str) == 0)
1223 match_type = exact_match;
1224 else
1225 {
1226 if (match_type < partly_match)
1227 match_type = partly_match;
1228 }
1229 matched++;
1230 }
1231 }
1232 if (!matched)
paul718e3742002-12-13 20:15:29 +00001233 vector_slot (v, i) = NULL;
1234 }
1235 }
1236 return match_type;
1237}
1238
1239/* Filter vector by command character with index. */
ajs274a4a42004-12-07 15:39:31 +00001240static enum match_type
hasso8c328f12004-10-05 21:01:23 +00001241cmd_filter_by_string (char *command, vector v, unsigned int index)
paul718e3742002-12-13 20:15:29 +00001242{
hasso8c328f12004-10-05 21:01:23 +00001243 unsigned int i;
1244 const char *str;
paul718e3742002-12-13 20:15:29 +00001245 struct cmd_element *cmd_element;
1246 enum match_type match_type;
1247 vector descvec;
1248 struct desc *desc;
paul909a2152005-03-14 17:41:45 +00001249
paul718e3742002-12-13 20:15:29 +00001250 match_type = no_match;
1251
1252 /* If command and cmd_element string does not match set NULL to vector */
paul55468c82005-03-14 20:19:01 +00001253 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001254 if ((cmd_element = vector_slot (v, i)) != NULL)
1255 {
1256 /* If given index is bigger than max string vector of command,
paul909a2152005-03-14 17:41:45 +00001257 set NULL */
paul55468c82005-03-14 20:19:01 +00001258 if (index >= vector_active (cmd_element->strvec))
paul718e3742002-12-13 20:15:29 +00001259 vector_slot (v, i) = NULL;
paul909a2152005-03-14 17:41:45 +00001260 else
paul718e3742002-12-13 20:15:29 +00001261 {
hasso8c328f12004-10-05 21:01:23 +00001262 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001263 int matched = 0;
1264
1265 descvec = vector_slot (cmd_element->strvec, index);
1266
paul55468c82005-03-14 20:19:01 +00001267 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001268 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001269 {
1270 str = desc->cmd;
paul718e3742002-12-13 20:15:29 +00001271
paul909a2152005-03-14 17:41:45 +00001272 if (CMD_VARARG (str))
1273 {
1274 if (match_type < vararg_match)
1275 match_type = vararg_match;
1276 matched++;
1277 }
1278 else if (CMD_RANGE (str))
1279 {
1280 if (cmd_range_match (str, command))
1281 {
1282 if (match_type < range_match)
1283 match_type = range_match;
1284 matched++;
1285 }
1286 }
paul22e0a9e2003-07-11 17:55:46 +00001287#ifdef HAVE_IPV6
paul909a2152005-03-14 17:41:45 +00001288 else if (CMD_IPV6 (str))
1289 {
1290 if (cmd_ipv6_match (command) == exact_match)
1291 {
1292 if (match_type < ipv6_match)
1293 match_type = ipv6_match;
1294 matched++;
1295 }
1296 }
1297 else if (CMD_IPV6_PREFIX (str))
1298 {
1299 if (cmd_ipv6_prefix_match (command) == exact_match)
1300 {
1301 if (match_type < ipv6_prefix_match)
1302 match_type = ipv6_prefix_match;
1303 matched++;
1304 }
1305 }
paul22e0a9e2003-07-11 17:55:46 +00001306#endif /* HAVE_IPV6 */
paul909a2152005-03-14 17:41:45 +00001307 else if (CMD_IPV4 (str))
1308 {
1309 if (cmd_ipv4_match (command) == exact_match)
1310 {
1311 if (match_type < ipv4_match)
1312 match_type = ipv4_match;
1313 matched++;
1314 }
1315 }
1316 else if (CMD_IPV4_PREFIX (str))
1317 {
1318 if (cmd_ipv4_prefix_match (command) == exact_match)
1319 {
1320 if (match_type < ipv4_prefix_match)
1321 match_type = ipv4_prefix_match;
1322 matched++;
1323 }
1324 }
1325 else if (CMD_OPTION (str) || CMD_VARIABLE (str))
1326 {
1327 if (match_type < extend_match)
1328 match_type = extend_match;
1329 matched++;
1330 }
1331 else
1332 {
1333 if (strcmp (command, str) == 0)
1334 {
1335 match_type = exact_match;
1336 matched++;
1337 }
1338 }
1339 }
1340 if (!matched)
paul718e3742002-12-13 20:15:29 +00001341 vector_slot (v, i) = NULL;
1342 }
1343 }
1344 return match_type;
1345}
1346
1347/* Check ambiguous match */
ajs274a4a42004-12-07 15:39:31 +00001348static int
paul718e3742002-12-13 20:15:29 +00001349is_cmd_ambiguous (char *command, vector v, int index, enum match_type type)
1350{
hasso8c328f12004-10-05 21:01:23 +00001351 unsigned int i;
1352 unsigned int j;
1353 const char *str = NULL;
paul718e3742002-12-13 20:15:29 +00001354 struct cmd_element *cmd_element;
hasso8c328f12004-10-05 21:01:23 +00001355 const char *matched = NULL;
paul718e3742002-12-13 20:15:29 +00001356 vector descvec;
1357 struct desc *desc;
paul909a2152005-03-14 17:41:45 +00001358
paul55468c82005-03-14 20:19:01 +00001359 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001360 if ((cmd_element = vector_slot (v, i)) != NULL)
1361 {
1362 int match = 0;
1363
1364 descvec = vector_slot (cmd_element->strvec, index);
1365
paul55468c82005-03-14 20:19:01 +00001366 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001367 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001368 {
1369 enum match_type ret;
1370
1371 str = desc->cmd;
paul718e3742002-12-13 20:15:29 +00001372
paul909a2152005-03-14 17:41:45 +00001373 switch (type)
1374 {
1375 case exact_match:
1376 if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
1377 && strcmp (command, str) == 0)
1378 match++;
1379 break;
1380 case partly_match:
1381 if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
1382 && strncmp (command, str, strlen (command)) == 0)
1383 {
1384 if (matched && strcmp (matched, str) != 0)
1385 return 1; /* There is ambiguous match. */
1386 else
1387 matched = str;
1388 match++;
1389 }
1390 break;
1391 case range_match:
1392 if (cmd_range_match (str, command))
1393 {
1394 if (matched && strcmp (matched, str) != 0)
1395 return 1;
1396 else
1397 matched = str;
1398 match++;
1399 }
1400 break;
1401#ifdef HAVE_IPV6
1402 case ipv6_match:
1403 if (CMD_IPV6 (str))
1404 match++;
1405 break;
1406 case ipv6_prefix_match:
1407 if ((ret = cmd_ipv6_prefix_match (command)) != no_match)
1408 {
1409 if (ret == partly_match)
1410 return 2; /* There is incomplete match. */
paul718e3742002-12-13 20:15:29 +00001411
paul909a2152005-03-14 17:41:45 +00001412 match++;
1413 }
1414 break;
1415#endif /* HAVE_IPV6 */
1416 case ipv4_match:
1417 if (CMD_IPV4 (str))
paul718e3742002-12-13 20:15:29 +00001418 match++;
paul909a2152005-03-14 17:41:45 +00001419 break;
1420 case ipv4_prefix_match:
1421 if ((ret = cmd_ipv4_prefix_match (command)) != no_match)
1422 {
1423 if (ret == partly_match)
1424 return 2; /* There is incomplete match. */
paul718e3742002-12-13 20:15:29 +00001425
paul909a2152005-03-14 17:41:45 +00001426 match++;
1427 }
1428 break;
1429 case extend_match:
1430 if (CMD_OPTION (str) || CMD_VARIABLE (str))
paul718e3742002-12-13 20:15:29 +00001431 match++;
paul909a2152005-03-14 17:41:45 +00001432 break;
1433 case no_match:
1434 default:
1435 break;
1436 }
1437 }
1438 if (!match)
paul718e3742002-12-13 20:15:29 +00001439 vector_slot (v, i) = NULL;
1440 }
1441 return 0;
1442}
1443
1444/* If src matches dst return dst string, otherwise return NULL */
ajs274a4a42004-12-07 15:39:31 +00001445static const char *
hasso8c328f12004-10-05 21:01:23 +00001446cmd_entry_function (const char *src, const char *dst)
paul718e3742002-12-13 20:15:29 +00001447{
1448 /* Skip variable arguments. */
1449 if (CMD_OPTION (dst) || CMD_VARIABLE (dst) || CMD_VARARG (dst) ||
1450 CMD_IPV4 (dst) || CMD_IPV4_PREFIX (dst) || CMD_RANGE (dst))
1451 return NULL;
1452
1453 /* In case of 'command \t', given src is NULL string. */
1454 if (src == NULL)
1455 return dst;
1456
1457 /* Matched with input string. */
1458 if (strncmp (src, dst, strlen (src)) == 0)
1459 return dst;
1460
1461 return NULL;
1462}
1463
1464/* If src matches dst return dst string, otherwise return NULL */
1465/* This version will return the dst string always if it is
1466 CMD_VARIABLE for '?' key processing */
ajs274a4a42004-12-07 15:39:31 +00001467static const char *
hasso8c328f12004-10-05 21:01:23 +00001468cmd_entry_function_desc (const char *src, const char *dst)
paul718e3742002-12-13 20:15:29 +00001469{
1470 if (CMD_VARARG (dst))
1471 return dst;
1472
1473 if (CMD_RANGE (dst))
1474 {
1475 if (cmd_range_match (dst, src))
1476 return dst;
1477 else
1478 return NULL;
1479 }
1480
paul22e0a9e2003-07-11 17:55:46 +00001481#ifdef HAVE_IPV6
paul718e3742002-12-13 20:15:29 +00001482 if (CMD_IPV6 (dst))
1483 {
1484 if (cmd_ipv6_match (src))
1485 return dst;
1486 else
1487 return NULL;
1488 }
1489
1490 if (CMD_IPV6_PREFIX (dst))
1491 {
1492 if (cmd_ipv6_prefix_match (src))
1493 return dst;
1494 else
1495 return NULL;
1496 }
paul22e0a9e2003-07-11 17:55:46 +00001497#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +00001498
1499 if (CMD_IPV4 (dst))
1500 {
1501 if (cmd_ipv4_match (src))
1502 return dst;
1503 else
1504 return NULL;
1505 }
1506
1507 if (CMD_IPV4_PREFIX (dst))
1508 {
1509 if (cmd_ipv4_prefix_match (src))
1510 return dst;
1511 else
1512 return NULL;
1513 }
1514
1515 /* Optional or variable commands always match on '?' */
1516 if (CMD_OPTION (dst) || CMD_VARIABLE (dst))
1517 return dst;
1518
1519 /* In case of 'command \t', given src is NULL string. */
1520 if (src == NULL)
1521 return dst;
1522
1523 if (strncmp (src, dst, strlen (src)) == 0)
1524 return dst;
1525 else
1526 return NULL;
1527}
1528
1529/* Check same string element existence. If it isn't there return
1530 1. */
ajs274a4a42004-12-07 15:39:31 +00001531static int
hasso8c328f12004-10-05 21:01:23 +00001532cmd_unique_string (vector v, const char *str)
paul718e3742002-12-13 20:15:29 +00001533{
hasso8c328f12004-10-05 21:01:23 +00001534 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001535 char *match;
1536
paul55468c82005-03-14 20:19:01 +00001537 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001538 if ((match = vector_slot (v, i)) != NULL)
1539 if (strcmp (match, str) == 0)
1540 return 0;
1541 return 1;
1542}
1543
1544/* Compare string to description vector. If there is same string
1545 return 1 else return 0. */
ajs274a4a42004-12-07 15:39:31 +00001546static int
hasso8c328f12004-10-05 21:01:23 +00001547desc_unique_string (vector v, const char *str)
paul718e3742002-12-13 20:15:29 +00001548{
hasso8c328f12004-10-05 21:01:23 +00001549 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001550 struct desc *desc;
1551
paul55468c82005-03-14 20:19:01 +00001552 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001553 if ((desc = vector_slot (v, i)) != NULL)
1554 if (strcmp (desc->cmd, str) == 0)
1555 return 1;
1556 return 0;
1557}
1558
ajs274a4a42004-12-07 15:39:31 +00001559static int
paulb92938a2002-12-13 21:20:42 +00001560cmd_try_do_shortcut (enum node_type node, char* first_word) {
1561 if ( first_word != NULL &&
1562 node != AUTH_NODE &&
1563 node != VIEW_NODE &&
1564 node != AUTH_ENABLE_NODE &&
1565 node != ENABLE_NODE &&
1566 0 == strcmp( "do", first_word ) )
1567 return 1;
1568 return 0;
1569}
1570
paul718e3742002-12-13 20:15:29 +00001571/* '?' describe command support. */
ajs274a4a42004-12-07 15:39:31 +00001572static vector
paulb92938a2002-12-13 21:20:42 +00001573cmd_describe_command_real (vector vline, struct vty *vty, int *status)
paul718e3742002-12-13 20:15:29 +00001574{
paulb8961472005-03-14 17:35:52 +00001575 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001576 vector cmd_vector;
1577#define INIT_MATCHVEC_SIZE 10
1578 vector matchvec;
1579 struct cmd_element *cmd_element;
paulb8961472005-03-14 17:35:52 +00001580 unsigned int index;
paul54aba542003-08-21 20:28:24 +00001581 int ret;
1582 enum match_type match;
1583 char *command;
paul718e3742002-12-13 20:15:29 +00001584 static struct desc desc_cr = { "<cr>", "" };
1585
1586 /* Set index. */
paul55468c82005-03-14 20:19:01 +00001587 if (vector_active (vline) == 0)
paulb8961472005-03-14 17:35:52 +00001588 {
1589 *status = CMD_ERR_NO_MATCH;
1590 return NULL;
1591 }
1592 else
paul55468c82005-03-14 20:19:01 +00001593 index = vector_active (vline) - 1;
paul909a2152005-03-14 17:41:45 +00001594
paul718e3742002-12-13 20:15:29 +00001595 /* Make copy vector of current node's command vector. */
1596 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1597
1598 /* Prepare match vector */
1599 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1600
1601 /* Filter commands. */
paul54aba542003-08-21 20:28:24 +00001602 /* Only words precedes current word will be checked in this loop. */
paul718e3742002-12-13 20:15:29 +00001603 for (i = 0; i < index; i++)
paulb8961472005-03-14 17:35:52 +00001604 if ((command = vector_slot (vline, i)))
paul909a2152005-03-14 17:41:45 +00001605 {
1606 match = cmd_filter_by_completion (command, cmd_vector, i);
1607
1608 if (match == vararg_match)
1609 {
1610 struct cmd_element *cmd_element;
1611 vector descvec;
1612 unsigned int j, k;
paul718e3742002-12-13 20:15:29 +00001613
paul55468c82005-03-14 20:19:01 +00001614 for (j = 0; j < vector_active (cmd_vector); j++)
paulb8961472005-03-14 17:35:52 +00001615 if ((cmd_element = vector_slot (cmd_vector, j)) != NULL
paul55468c82005-03-14 20:19:01 +00001616 && (vector_active (cmd_element->strvec)))
paul909a2152005-03-14 17:41:45 +00001617 {
1618 descvec = vector_slot (cmd_element->strvec,
paul55468c82005-03-14 20:19:01 +00001619 vector_active (cmd_element->strvec) - 1);
1620 for (k = 0; k < vector_active (descvec); k++)
paul909a2152005-03-14 17:41:45 +00001621 {
1622 struct desc *desc = vector_slot (descvec, k);
1623 vector_set (matchvec, desc);
1624 }
1625 }
1626
1627 vector_set (matchvec, &desc_cr);
1628 vector_free (cmd_vector);
paul718e3742002-12-13 20:15:29 +00001629
paul909a2152005-03-14 17:41:45 +00001630 return matchvec;
1631 }
paul718e3742002-12-13 20:15:29 +00001632
paul909a2152005-03-14 17:41:45 +00001633 if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
1634 {
1635 vector_free (cmd_vector);
Paul Jakmae5cd7062006-06-15 12:25:55 +00001636 vector_free (matchvec);
paul909a2152005-03-14 17:41:45 +00001637 *status = CMD_ERR_AMBIGUOUS;
1638 return NULL;
1639 }
1640 else if (ret == 2)
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_NO_MATCH;
1645 return NULL;
1646 }
1647 }
paul718e3742002-12-13 20:15:29 +00001648
1649 /* Prepare match vector */
1650 /* matchvec = vector_init (INIT_MATCHVEC_SIZE); */
1651
paul54aba542003-08-21 20:28:24 +00001652 /* Make sure that cmd_vector is filtered based on current word */
1653 command = vector_slot (vline, index);
1654 if (command)
1655 match = cmd_filter_by_completion (command, cmd_vector, index);
1656
paul718e3742002-12-13 20:15:29 +00001657 /* Make description vector. */
paul55468c82005-03-14 20:19:01 +00001658 for (i = 0; i < vector_active (cmd_vector); i++)
paul718e3742002-12-13 20:15:29 +00001659 if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
1660 {
hasso8c328f12004-10-05 21:01:23 +00001661 const char *string = NULL;
paul718e3742002-12-13 20:15:29 +00001662 vector strvec = cmd_element->strvec;
1663
paul55468c82005-03-14 20:19:01 +00001664 /* if command is NULL, index may be equal to vector_active */
1665 if (command && index >= vector_active (strvec))
paul718e3742002-12-13 20:15:29 +00001666 vector_slot (cmd_vector, i) = NULL;
1667 else
1668 {
paul54aba542003-08-21 20:28:24 +00001669 /* Check if command is completed. */
paul55468c82005-03-14 20:19:01 +00001670 if (command == NULL && index == vector_active (strvec))
paul718e3742002-12-13 20:15:29 +00001671 {
1672 string = "<cr>";
paul909a2152005-03-14 17:41:45 +00001673 if (!desc_unique_string (matchvec, string))
paul718e3742002-12-13 20:15:29 +00001674 vector_set (matchvec, &desc_cr);
1675 }
1676 else
1677 {
hasso8c328f12004-10-05 21:01:23 +00001678 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001679 vector descvec = vector_slot (strvec, index);
1680 struct desc *desc;
1681
paul55468c82005-03-14 20:19:01 +00001682 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001683 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001684 {
1685 string = cmd_entry_function_desc (command, desc->cmd);
1686 if (string)
1687 {
1688 /* Uniqueness check */
1689 if (!desc_unique_string (matchvec, string))
1690 vector_set (matchvec, desc);
1691 }
1692 }
paul718e3742002-12-13 20:15:29 +00001693 }
1694 }
1695 }
1696 vector_free (cmd_vector);
1697
1698 if (vector_slot (matchvec, 0) == NULL)
1699 {
1700 vector_free (matchvec);
paul909a2152005-03-14 17:41:45 +00001701 *status = CMD_ERR_NO_MATCH;
Paul Jakma5fc60512006-05-12 23:24:09 +00001702 return NULL;
paul718e3742002-12-13 20:15:29 +00001703 }
paul718e3742002-12-13 20:15:29 +00001704
Paul Jakma5fc60512006-05-12 23:24:09 +00001705 *status = CMD_SUCCESS;
paul718e3742002-12-13 20:15:29 +00001706 return matchvec;
1707}
1708
paulb92938a2002-12-13 21:20:42 +00001709vector
1710cmd_describe_command (vector vline, struct vty *vty, int *status)
1711{
1712 vector ret;
1713
1714 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1715 {
1716 enum node_type onode;
1717 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00001718 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00001719
1720 onode = vty->node;
1721 vty->node = ENABLE_NODE;
1722 /* We can try it on enable node, cos' the vty is authenticated */
1723
1724 shifted_vline = vector_init (vector_count(vline));
1725 /* use memcpy? */
paul55468c82005-03-14 20:19:01 +00001726 for (index = 1; index < vector_active (vline); index++)
paulb92938a2002-12-13 21:20:42 +00001727 {
1728 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1729 }
1730
1731 ret = cmd_describe_command_real (shifted_vline, vty, status);
1732
1733 vector_free(shifted_vline);
1734 vty->node = onode;
1735 return ret;
1736 }
1737
1738
1739 return cmd_describe_command_real (vline, vty, status);
1740}
1741
1742
paul718e3742002-12-13 20:15:29 +00001743/* Check LCD of matched command. */
ajs274a4a42004-12-07 15:39:31 +00001744static int
paul718e3742002-12-13 20:15:29 +00001745cmd_lcd (char **matched)
1746{
1747 int i;
1748 int j;
1749 int lcd = -1;
1750 char *s1, *s2;
1751 char c1, c2;
1752
1753 if (matched[0] == NULL || matched[1] == NULL)
1754 return 0;
1755
1756 for (i = 1; matched[i] != NULL; i++)
1757 {
1758 s1 = matched[i - 1];
1759 s2 = matched[i];
1760
1761 for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
1762 if (c1 != c2)
1763 break;
1764
1765 if (lcd < 0)
1766 lcd = j;
1767 else
1768 {
1769 if (lcd > j)
1770 lcd = j;
1771 }
1772 }
1773 return lcd;
1774}
1775
1776/* Command line completion support. */
ajs274a4a42004-12-07 15:39:31 +00001777static char **
paulb92938a2002-12-13 21:20:42 +00001778cmd_complete_command_real (vector vline, struct vty *vty, int *status)
paul718e3742002-12-13 20:15:29 +00001779{
paulb8961472005-03-14 17:35:52 +00001780 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001781 vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1782#define INIT_MATCHVEC_SIZE 10
1783 vector matchvec;
1784 struct cmd_element *cmd_element;
paulb8961472005-03-14 17:35:52 +00001785 unsigned int index;
paul718e3742002-12-13 20:15:29 +00001786 char **match_str;
1787 struct desc *desc;
1788 vector descvec;
1789 char *command;
1790 int lcd;
1791
paul55468c82005-03-14 20:19:01 +00001792 if (vector_active (vline) == 0)
paulb8961472005-03-14 17:35:52 +00001793 {
Paul Jakmad2519962006-05-12 23:19:37 +00001794 vector_free (cmd_vector);
paulb8961472005-03-14 17:35:52 +00001795 *status = CMD_ERR_NO_MATCH;
1796 return NULL;
1797 }
1798 else
paul55468c82005-03-14 20:19:01 +00001799 index = vector_active (vline) - 1;
paulb8961472005-03-14 17:35:52 +00001800
paul718e3742002-12-13 20:15:29 +00001801 /* First, filter by preceeding command string */
1802 for (i = 0; i < index; i++)
paulb8961472005-03-14 17:35:52 +00001803 if ((command = vector_slot (vline, i)))
paul909a2152005-03-14 17:41:45 +00001804 {
1805 enum match_type match;
1806 int ret;
paul718e3742002-12-13 20:15:29 +00001807
paul909a2152005-03-14 17:41:45 +00001808 /* First try completion match, if there is exactly match return 1 */
1809 match = cmd_filter_by_completion (command, cmd_vector, i);
paul718e3742002-12-13 20:15:29 +00001810
paul909a2152005-03-14 17:41:45 +00001811 /* If there is exact match then filter ambiguous match else check
1812 ambiguousness. */
1813 if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
1814 {
1815 vector_free (cmd_vector);
1816 *status = CMD_ERR_AMBIGUOUS;
1817 return NULL;
1818 }
1819 /*
1820 else if (ret == 2)
1821 {
1822 vector_free (cmd_vector);
1823 *status = CMD_ERR_NO_MATCH;
1824 return NULL;
1825 }
1826 */
1827 }
1828
paul718e3742002-12-13 20:15:29 +00001829 /* Prepare match vector. */
1830 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1831
1832 /* Now we got into completion */
paul55468c82005-03-14 20:19:01 +00001833 for (i = 0; i < vector_active (cmd_vector); i++)
paulb8961472005-03-14 17:35:52 +00001834 if ((cmd_element = vector_slot (cmd_vector, i)))
paul718e3742002-12-13 20:15:29 +00001835 {
hasso8c328f12004-10-05 21:01:23 +00001836 const char *string;
paul718e3742002-12-13 20:15:29 +00001837 vector strvec = cmd_element->strvec;
paul909a2152005-03-14 17:41:45 +00001838
paul718e3742002-12-13 20:15:29 +00001839 /* Check field length */
paul55468c82005-03-14 20:19:01 +00001840 if (index >= vector_active (strvec))
paul718e3742002-12-13 20:15:29 +00001841 vector_slot (cmd_vector, i) = NULL;
paul909a2152005-03-14 17:41:45 +00001842 else
paul718e3742002-12-13 20:15:29 +00001843 {
hasso8c328f12004-10-05 21:01:23 +00001844 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001845
1846 descvec = vector_slot (strvec, index);
paul55468c82005-03-14 20:19:01 +00001847 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001848 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001849 {
paulb8961472005-03-14 17:35:52 +00001850 if ((string =
1851 cmd_entry_function (vector_slot (vline, index),
paul909a2152005-03-14 17:41:45 +00001852 desc->cmd)))
1853 if (cmd_unique_string (matchvec, string))
1854 vector_set (matchvec, XSTRDUP (MTYPE_TMP, string));
1855 }
paul718e3742002-12-13 20:15:29 +00001856 }
1857 }
1858
1859 /* We don't need cmd_vector any more. */
1860 vector_free (cmd_vector);
1861
1862 /* No matched command */
1863 if (vector_slot (matchvec, 0) == NULL)
1864 {
1865 vector_free (matchvec);
1866
1867 /* In case of 'command \t' pattern. Do you need '?' command at
1868 the end of the line. */
1869 if (vector_slot (vline, index) == '\0')
1870 *status = CMD_ERR_NOTHING_TODO;
1871 else
1872 *status = CMD_ERR_NO_MATCH;
1873 return NULL;
1874 }
1875
1876 /* Only one matched */
1877 if (vector_slot (matchvec, 1) == NULL)
1878 {
1879 match_str = (char **) matchvec->index;
1880 vector_only_wrapper_free (matchvec);
1881 *status = CMD_COMPLETE_FULL_MATCH;
1882 return match_str;
1883 }
1884 /* Make it sure last element is NULL. */
1885 vector_set (matchvec, NULL);
1886
1887 /* Check LCD of matched strings. */
1888 if (vector_slot (vline, index) != NULL)
1889 {
1890 lcd = cmd_lcd ((char **) matchvec->index);
1891
1892 if (lcd)
1893 {
1894 int len = strlen (vector_slot (vline, index));
paul909a2152005-03-14 17:41:45 +00001895
paul718e3742002-12-13 20:15:29 +00001896 if (len < lcd)
1897 {
1898 char *lcdstr;
paul909a2152005-03-14 17:41:45 +00001899
paul05865c92005-10-26 05:49:54 +00001900 lcdstr = XMALLOC (MTYPE_STRVEC, lcd + 1);
paul718e3742002-12-13 20:15:29 +00001901 memcpy (lcdstr, matchvec->index[0], lcd);
1902 lcdstr[lcd] = '\0';
1903
1904 /* match_str = (char **) &lcdstr; */
1905
1906 /* Free matchvec. */
paul55468c82005-03-14 20:19:01 +00001907 for (i = 0; i < vector_active (matchvec); i++)
paul718e3742002-12-13 20:15:29 +00001908 {
1909 if (vector_slot (matchvec, i))
paul05865c92005-10-26 05:49:54 +00001910 XFREE (MTYPE_STRVEC, vector_slot (matchvec, i));
paul718e3742002-12-13 20:15:29 +00001911 }
1912 vector_free (matchvec);
1913
paul909a2152005-03-14 17:41:45 +00001914 /* Make new matchvec. */
paul718e3742002-12-13 20:15:29 +00001915 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1916 vector_set (matchvec, lcdstr);
1917 match_str = (char **) matchvec->index;
1918 vector_only_wrapper_free (matchvec);
1919
1920 *status = CMD_COMPLETE_MATCH;
1921 return match_str;
1922 }
1923 }
1924 }
1925
1926 match_str = (char **) matchvec->index;
1927 vector_only_wrapper_free (matchvec);
1928 *status = CMD_COMPLETE_LIST_MATCH;
1929 return match_str;
1930}
1931
paulb92938a2002-12-13 21:20:42 +00001932char **
paul9ab68122003-01-18 01:16:20 +00001933cmd_complete_command (vector vline, struct vty *vty, int *status)
paulb92938a2002-12-13 21:20:42 +00001934{
1935 char **ret;
1936
1937 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1938 {
1939 enum node_type onode;
1940 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00001941 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00001942
1943 onode = vty->node;
1944 vty->node = ENABLE_NODE;
1945 /* We can try it on enable node, cos' the vty is authenticated */
1946
1947 shifted_vline = vector_init (vector_count(vline));
1948 /* use memcpy? */
paul55468c82005-03-14 20:19:01 +00001949 for (index = 1; index < vector_active (vline); index++)
paulb92938a2002-12-13 21:20:42 +00001950 {
1951 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1952 }
1953
1954 ret = cmd_complete_command_real (shifted_vline, vty, status);
1955
1956 vector_free(shifted_vline);
1957 vty->node = onode;
1958 return ret;
1959 }
1960
1961
1962 return cmd_complete_command_real (vline, vty, status);
1963}
1964
1965/* return parent node */
1966/* MUST eventually converge on CONFIG_NODE */
hasso13bfca72005-01-23 21:42:25 +00001967enum node_type
ajs274a4a42004-12-07 15:39:31 +00001968node_parent ( enum node_type node )
paulb92938a2002-12-13 21:20:42 +00001969{
1970 enum node_type ret;
1971
paul9ab68122003-01-18 01:16:20 +00001972 assert (node > CONFIG_NODE);
1973
1974 switch (node)
1975 {
1976 case BGP_VPNV4_NODE:
1977 case BGP_IPV4_NODE:
1978 case BGP_IPV4M_NODE:
1979 case BGP_IPV6_NODE:
paul1e836592005-08-22 22:39:56 +00001980 case BGP_IPV6M_NODE:
paul9ab68122003-01-18 01:16:20 +00001981 ret = BGP_NODE;
1982 break;
1983 case KEYCHAIN_KEY_NODE:
1984 ret = KEYCHAIN_NODE;
1985 break;
1986 default:
1987 ret = CONFIG_NODE;
paulb92938a2002-12-13 21:20:42 +00001988 }
1989
1990 return ret;
1991}
1992
paul718e3742002-12-13 20:15:29 +00001993/* Execute command by argument vline vector. */
ajs274a4a42004-12-07 15:39:31 +00001994static int
paulb8961472005-03-14 17:35:52 +00001995cmd_execute_command_real (vector vline, struct vty *vty,
1996 struct cmd_element **cmd)
paul718e3742002-12-13 20:15:29 +00001997{
hasso8c328f12004-10-05 21:01:23 +00001998 unsigned int i;
1999 unsigned int index;
paul718e3742002-12-13 20:15:29 +00002000 vector cmd_vector;
2001 struct cmd_element *cmd_element;
2002 struct cmd_element *matched_element;
2003 unsigned int matched_count, incomplete_count;
2004 int argc;
paul9035efa2004-10-10 11:56:56 +00002005 const char *argv[CMD_ARGC_MAX];
paul718e3742002-12-13 20:15:29 +00002006 enum match_type match = 0;
2007 int varflag;
2008 char *command;
2009
2010 /* Make copy of command elements. */
2011 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2012
paul55468c82005-03-14 20:19:01 +00002013 for (index = 0; index < vector_active (vline); index++)
paulb8961472005-03-14 17:35:52 +00002014 if ((command = vector_slot (vline, index)))
paul909a2152005-03-14 17:41:45 +00002015 {
2016 int ret;
paul718e3742002-12-13 20:15:29 +00002017
paul909a2152005-03-14 17:41:45 +00002018 match = cmd_filter_by_completion (command, cmd_vector, index);
paul718e3742002-12-13 20:15:29 +00002019
paul909a2152005-03-14 17:41:45 +00002020 if (match == vararg_match)
2021 break;
2022
2023 ret = is_cmd_ambiguous (command, cmd_vector, index, match);
paul718e3742002-12-13 20:15:29 +00002024
paul909a2152005-03-14 17:41:45 +00002025 if (ret == 1)
2026 {
2027 vector_free (cmd_vector);
2028 return CMD_ERR_AMBIGUOUS;
2029 }
2030 else if (ret == 2)
2031 {
2032 vector_free (cmd_vector);
2033 return CMD_ERR_NO_MATCH;
2034 }
2035 }
paul718e3742002-12-13 20:15:29 +00002036
2037 /* Check matched count. */
2038 matched_element = NULL;
2039 matched_count = 0;
2040 incomplete_count = 0;
2041
paul55468c82005-03-14 20:19:01 +00002042 for (i = 0; i < vector_active (cmd_vector); i++)
paulb8961472005-03-14 17:35:52 +00002043 if ((cmd_element = vector_slot (cmd_vector, i)))
paul718e3742002-12-13 20:15:29 +00002044 {
paul718e3742002-12-13 20:15:29 +00002045 if (match == vararg_match || index >= cmd_element->cmdsize)
2046 {
2047 matched_element = cmd_element;
2048#if 0
2049 printf ("DEBUG: %s\n", cmd_element->string);
2050#endif
2051 matched_count++;
2052 }
2053 else
2054 {
2055 incomplete_count++;
2056 }
2057 }
paul909a2152005-03-14 17:41:45 +00002058
paul718e3742002-12-13 20:15:29 +00002059 /* Finish of using cmd_vector. */
2060 vector_free (cmd_vector);
2061
paul909a2152005-03-14 17:41:45 +00002062 /* To execute command, matched_count must be 1. */
2063 if (matched_count == 0)
paul718e3742002-12-13 20:15:29 +00002064 {
2065 if (incomplete_count)
2066 return CMD_ERR_INCOMPLETE;
2067 else
2068 return CMD_ERR_NO_MATCH;
2069 }
2070
paul909a2152005-03-14 17:41:45 +00002071 if (matched_count > 1)
paul718e3742002-12-13 20:15:29 +00002072 return CMD_ERR_AMBIGUOUS;
2073
2074 /* Argument treatment */
2075 varflag = 0;
2076 argc = 0;
2077
paul55468c82005-03-14 20:19:01 +00002078 for (i = 0; i < vector_active (vline); i++)
paul718e3742002-12-13 20:15:29 +00002079 {
2080 if (varflag)
2081 argv[argc++] = vector_slot (vline, i);
2082 else
paul909a2152005-03-14 17:41:45 +00002083 {
paul718e3742002-12-13 20:15:29 +00002084 vector descvec = vector_slot (matched_element->strvec, i);
2085
paul55468c82005-03-14 20:19:01 +00002086 if (vector_active (descvec) == 1)
paul718e3742002-12-13 20:15:29 +00002087 {
2088 struct desc *desc = vector_slot (descvec, 0);
paul718e3742002-12-13 20:15:29 +00002089
hasso8c328f12004-10-05 21:01:23 +00002090 if (CMD_VARARG (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002091 varflag = 1;
2092
hasso8c328f12004-10-05 21:01:23 +00002093 if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002094 argv[argc++] = vector_slot (vline, i);
2095 }
2096 else
2097 argv[argc++] = vector_slot (vline, i);
2098 }
2099
2100 if (argc >= CMD_ARGC_MAX)
2101 return CMD_ERR_EXEED_ARGC_MAX;
2102 }
2103
2104 /* For vtysh execution. */
2105 if (cmd)
2106 *cmd = matched_element;
2107
2108 if (matched_element->daemon)
2109 return CMD_SUCCESS_DAEMON;
2110
2111 /* Execute matched command. */
2112 return (*matched_element->func) (matched_element, vty, argc, argv);
2113}
2114
paulb92938a2002-12-13 21:20:42 +00002115int
hasso87d683b2005-01-16 23:31:54 +00002116cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,
2117 int vtysh) {
paul9ab68122003-01-18 01:16:20 +00002118 int ret, saved_ret, tried = 0;
2119 enum node_type onode, try_node;
2120
2121 onode = try_node = vty->node;
paulb92938a2002-12-13 21:20:42 +00002122
2123 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
2124 {
2125 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00002126 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00002127
2128 vty->node = ENABLE_NODE;
2129 /* We can try it on enable node, cos' the vty is authenticated */
2130
2131 shifted_vline = vector_init (vector_count(vline));
2132 /* use memcpy? */
paul55468c82005-03-14 20:19:01 +00002133 for (index = 1; index < vector_active (vline); index++)
paulb92938a2002-12-13 21:20:42 +00002134 {
2135 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
2136 }
2137
2138 ret = cmd_execute_command_real (shifted_vline, vty, cmd);
2139
2140 vector_free(shifted_vline);
2141 vty->node = onode;
2142 return ret;
2143 }
2144
2145
paul9ab68122003-01-18 01:16:20 +00002146 saved_ret = ret = cmd_execute_command_real (vline, vty, cmd);
paulb92938a2002-12-13 21:20:42 +00002147
hasso87d683b2005-01-16 23:31:54 +00002148 if (vtysh)
2149 return saved_ret;
2150
paulb92938a2002-12-13 21:20:42 +00002151 /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
paul9ab68122003-01-18 01:16:20 +00002152 while ( ret != CMD_SUCCESS && ret != CMD_WARNING
paulb92938a2002-12-13 21:20:42 +00002153 && vty->node > CONFIG_NODE )
2154 {
paul9ab68122003-01-18 01:16:20 +00002155 try_node = node_parent(try_node);
2156 vty->node = try_node;
paulb92938a2002-12-13 21:20:42 +00002157 ret = cmd_execute_command_real (vline, vty, cmd);
paul9ab68122003-01-18 01:16:20 +00002158 tried = 1;
2159 if (ret == CMD_SUCCESS || ret == CMD_WARNING)
paulb92938a2002-12-13 21:20:42 +00002160 {
paul9ab68122003-01-18 01:16:20 +00002161 /* succesfull command, leave the node as is */
paulb92938a2002-12-13 21:20:42 +00002162 return ret;
2163 }
paulb92938a2002-12-13 21:20:42 +00002164 }
paul9ab68122003-01-18 01:16:20 +00002165 /* no command succeeded, reset the vty to the original node and
2166 return the error for this node */
2167 if ( tried )
2168 vty->node = onode;
2169 return saved_ret;
pauleda031f2003-01-18 00:39:19 +00002170}
2171
paul718e3742002-12-13 20:15:29 +00002172/* Execute command by argument readline. */
2173int
paul909a2152005-03-14 17:41:45 +00002174cmd_execute_command_strict (vector vline, struct vty *vty,
paul718e3742002-12-13 20:15:29 +00002175 struct cmd_element **cmd)
2176{
hasso8c328f12004-10-05 21:01:23 +00002177 unsigned int i;
2178 unsigned int index;
paul718e3742002-12-13 20:15:29 +00002179 vector cmd_vector;
2180 struct cmd_element *cmd_element;
2181 struct cmd_element *matched_element;
2182 unsigned int matched_count, incomplete_count;
2183 int argc;
paul9035efa2004-10-10 11:56:56 +00002184 const char *argv[CMD_ARGC_MAX];
paul718e3742002-12-13 20:15:29 +00002185 int varflag;
2186 enum match_type match = 0;
2187 char *command;
2188
2189 /* Make copy of command element */
2190 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2191
paul55468c82005-03-14 20:19:01 +00002192 for (index = 0; index < vector_active (vline); index++)
paulb8961472005-03-14 17:35:52 +00002193 if ((command = vector_slot (vline, index)))
paul909a2152005-03-14 17:41:45 +00002194 {
2195 int ret;
2196
2197 match = cmd_filter_by_string (vector_slot (vline, index),
2198 cmd_vector, index);
paul718e3742002-12-13 20:15:29 +00002199
paul909a2152005-03-14 17:41:45 +00002200 /* If command meets '.VARARG' then finish matching. */
2201 if (match == vararg_match)
2202 break;
2203
2204 ret = is_cmd_ambiguous (command, cmd_vector, index, match);
2205 if (ret == 1)
2206 {
2207 vector_free (cmd_vector);
2208 return CMD_ERR_AMBIGUOUS;
2209 }
2210 if (ret == 2)
2211 {
2212 vector_free (cmd_vector);
2213 return CMD_ERR_NO_MATCH;
2214 }
2215 }
paul718e3742002-12-13 20:15:29 +00002216
2217 /* Check matched count. */
2218 matched_element = NULL;
2219 matched_count = 0;
2220 incomplete_count = 0;
paul55468c82005-03-14 20:19:01 +00002221 for (i = 0; i < vector_active (cmd_vector); i++)
paul909a2152005-03-14 17:41:45 +00002222 if (vector_slot (cmd_vector, i) != NULL)
paul718e3742002-12-13 20:15:29 +00002223 {
paul909a2152005-03-14 17:41:45 +00002224 cmd_element = vector_slot (cmd_vector, i);
paul718e3742002-12-13 20:15:29 +00002225
2226 if (match == vararg_match || index >= cmd_element->cmdsize)
2227 {
2228 matched_element = cmd_element;
2229 matched_count++;
2230 }
2231 else
2232 incomplete_count++;
2233 }
paul909a2152005-03-14 17:41:45 +00002234
paul718e3742002-12-13 20:15:29 +00002235 /* Finish of using cmd_vector. */
2236 vector_free (cmd_vector);
2237
paul909a2152005-03-14 17:41:45 +00002238 /* To execute command, matched_count must be 1. */
2239 if (matched_count == 0)
paul718e3742002-12-13 20:15:29 +00002240 {
2241 if (incomplete_count)
2242 return CMD_ERR_INCOMPLETE;
2243 else
2244 return CMD_ERR_NO_MATCH;
2245 }
2246
paul909a2152005-03-14 17:41:45 +00002247 if (matched_count > 1)
paul718e3742002-12-13 20:15:29 +00002248 return CMD_ERR_AMBIGUOUS;
2249
2250 /* Argument treatment */
2251 varflag = 0;
2252 argc = 0;
2253
paul55468c82005-03-14 20:19:01 +00002254 for (i = 0; i < vector_active (vline); i++)
paul718e3742002-12-13 20:15:29 +00002255 {
2256 if (varflag)
2257 argv[argc++] = vector_slot (vline, i);
2258 else
paul909a2152005-03-14 17:41:45 +00002259 {
paul718e3742002-12-13 20:15:29 +00002260 vector descvec = vector_slot (matched_element->strvec, i);
2261
paul55468c82005-03-14 20:19:01 +00002262 if (vector_active (descvec) == 1)
paul718e3742002-12-13 20:15:29 +00002263 {
2264 struct desc *desc = vector_slot (descvec, 0);
paul718e3742002-12-13 20:15:29 +00002265
hasso8c328f12004-10-05 21:01:23 +00002266 if (CMD_VARARG (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002267 varflag = 1;
paul909a2152005-03-14 17:41:45 +00002268
hasso8c328f12004-10-05 21:01:23 +00002269 if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002270 argv[argc++] = vector_slot (vline, i);
2271 }
2272 else
2273 argv[argc++] = vector_slot (vline, i);
2274 }
2275
2276 if (argc >= CMD_ARGC_MAX)
2277 return CMD_ERR_EXEED_ARGC_MAX;
2278 }
2279
2280 /* For vtysh execution. */
2281 if (cmd)
2282 *cmd = matched_element;
2283
2284 if (matched_element->daemon)
2285 return CMD_SUCCESS_DAEMON;
2286
2287 /* Now execute matched command */
2288 return (*matched_element->func) (matched_element, vty, argc, argv);
2289}
2290
2291/* Configration make from file. */
2292int
2293config_from_file (struct vty *vty, FILE *fp)
2294{
2295 int ret;
2296 vector vline;
2297
2298 while (fgets (vty->buf, VTY_BUFSIZ, fp))
2299 {
2300 vline = cmd_make_strvec (vty->buf);
2301
2302 /* In case of comment line */
2303 if (vline == NULL)
2304 continue;
2305 /* Execute configuration command : this is strict match */
2306 ret = cmd_execute_command_strict (vline, vty, NULL);
2307
2308 /* Try again with setting node to CONFIG_NODE */
paulb92938a2002-12-13 21:20:42 +00002309 while (ret != CMD_SUCCESS && ret != CMD_WARNING
hassoddd85ed2004-10-13 08:18:07 +00002310 && ret != CMD_ERR_NOTHING_TODO && vty->node != CONFIG_NODE)
2311 {
paulb92938a2002-12-13 21:20:42 +00002312 vty->node = node_parent(vty->node);
hassoddd85ed2004-10-13 08:18:07 +00002313 ret = cmd_execute_command_strict (vline, vty, NULL);
2314 }
paul9ab68122003-01-18 01:16:20 +00002315
paul718e3742002-12-13 20:15:29 +00002316 cmd_free_strvec (vline);
2317
hassoddd85ed2004-10-13 08:18:07 +00002318 if (ret != CMD_SUCCESS && ret != CMD_WARNING
2319 && ret != CMD_ERR_NOTHING_TODO)
paul718e3742002-12-13 20:15:29 +00002320 return ret;
2321 }
2322 return CMD_SUCCESS;
2323}
2324
2325/* Configration from terminal */
2326DEFUN (config_terminal,
2327 config_terminal_cmd,
2328 "configure terminal",
2329 "Configuration from vty interface\n"
2330 "Configuration terminal\n")
2331{
2332 if (vty_config_lock (vty))
2333 vty->node = CONFIG_NODE;
2334 else
2335 {
2336 vty_out (vty, "VTY configuration is locked by other VTY%s", VTY_NEWLINE);
2337 return CMD_WARNING;
2338 }
2339 return CMD_SUCCESS;
2340}
2341
2342/* Enable command */
2343DEFUN (enable,
2344 config_enable_cmd,
2345 "enable",
2346 "Turn on privileged mode command\n")
2347{
2348 /* If enable password is NULL, change to ENABLE_NODE */
2349 if ((host.enable == NULL && host.enable_encrypt == NULL) ||
2350 vty->type == VTY_SHELL_SERV)
2351 vty->node = ENABLE_NODE;
2352 else
2353 vty->node = AUTH_ENABLE_NODE;
2354
2355 return CMD_SUCCESS;
2356}
2357
2358/* Disable command */
2359DEFUN (disable,
2360 config_disable_cmd,
2361 "disable",
2362 "Turn off privileged mode command\n")
2363{
2364 if (vty->node == ENABLE_NODE)
2365 vty->node = VIEW_NODE;
2366 return CMD_SUCCESS;
2367}
2368
2369/* Down vty node level. */
2370DEFUN (config_exit,
2371 config_exit_cmd,
2372 "exit",
2373 "Exit current mode and down to previous mode\n")
2374{
2375 switch (vty->node)
2376 {
2377 case VIEW_NODE:
2378 case ENABLE_NODE:
2379 if (vty_shell (vty))
2380 exit (0);
2381 else
2382 vty->status = VTY_CLOSE;
2383 break;
2384 case CONFIG_NODE:
2385 vty->node = ENABLE_NODE;
2386 vty_config_unlock (vty);
2387 break;
2388 case INTERFACE_NODE:
2389 case ZEBRA_NODE:
2390 case BGP_NODE:
2391 case RIP_NODE:
2392 case RIPNG_NODE:
2393 case OSPF_NODE:
2394 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00002395 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00002396 case KEYCHAIN_NODE:
2397 case MASC_NODE:
2398 case RMAP_NODE:
2399 case VTY_NODE:
2400 vty->node = CONFIG_NODE;
2401 break;
2402 case BGP_VPNV4_NODE:
2403 case BGP_IPV4_NODE:
2404 case BGP_IPV4M_NODE:
2405 case BGP_IPV6_NODE:
paul1e836592005-08-22 22:39:56 +00002406 case BGP_IPV6M_NODE:
paul718e3742002-12-13 20:15:29 +00002407 vty->node = BGP_NODE;
2408 break;
2409 case KEYCHAIN_KEY_NODE:
2410 vty->node = KEYCHAIN_NODE;
2411 break;
2412 default:
2413 break;
2414 }
2415 return CMD_SUCCESS;
2416}
2417
2418/* quit is alias of exit. */
2419ALIAS (config_exit,
2420 config_quit_cmd,
2421 "quit",
2422 "Exit current mode and down to previous mode\n")
2423
2424/* End of configuration. */
2425DEFUN (config_end,
2426 config_end_cmd,
2427 "end",
2428 "End current mode and change to enable mode.")
2429{
2430 switch (vty->node)
2431 {
2432 case VIEW_NODE:
2433 case ENABLE_NODE:
2434 /* Nothing to do. */
2435 break;
2436 case CONFIG_NODE:
2437 case INTERFACE_NODE:
2438 case ZEBRA_NODE:
2439 case RIP_NODE:
2440 case RIPNG_NODE:
2441 case BGP_NODE:
2442 case BGP_VPNV4_NODE:
2443 case BGP_IPV4_NODE:
2444 case BGP_IPV4M_NODE:
2445 case BGP_IPV6_NODE:
paul1e836592005-08-22 22:39:56 +00002446 case BGP_IPV6M_NODE:
paul718e3742002-12-13 20:15:29 +00002447 case RMAP_NODE:
2448 case OSPF_NODE:
2449 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00002450 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00002451 case KEYCHAIN_NODE:
2452 case KEYCHAIN_KEY_NODE:
2453 case MASC_NODE:
2454 case VTY_NODE:
2455 vty_config_unlock (vty);
2456 vty->node = ENABLE_NODE;
2457 break;
2458 default:
2459 break;
2460 }
2461 return CMD_SUCCESS;
2462}
2463
2464/* Show version. */
2465DEFUN (show_version,
2466 show_version_cmd,
2467 "show version",
2468 SHOW_STR
2469 "Displays zebra version\n")
2470{
hasso12f6ea22005-03-07 08:35:39 +00002471 vty_out (vty, "Quagga %s (%s).%s", QUAGGA_VERSION, host.name?host.name:"",
2472 VTY_NEWLINE);
hasso6590f2c2004-10-19 20:40:08 +00002473 vty_out (vty, "%s%s", QUAGGA_COPYRIGHT, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00002474
2475 return CMD_SUCCESS;
2476}
2477
2478/* Help display function for all node. */
2479DEFUN (config_help,
2480 config_help_cmd,
2481 "help",
2482 "Description of the interactive help system\n")
2483{
2484 vty_out (vty,
hasso6590f2c2004-10-19 20:40:08 +00002485 "Quagga VTY provides advanced help feature. When you need help,%s\
paul718e3742002-12-13 20:15:29 +00002486anytime at the command line please press '?'.%s\
2487%s\
2488If nothing matches, the help list will be empty and you must backup%s\
2489 until entering a '?' shows the available options.%s\
2490Two styles of help are provided:%s\
24911. Full help is available when you are ready to enter a%s\
2492command argument (e.g. 'show ?') and describes each possible%s\
2493argument.%s\
24942. Partial help is provided when an abbreviated argument is entered%s\
2495 and you want to know what arguments match the input%s\
2496 (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2497 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2498 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
2499 return CMD_SUCCESS;
2500}
2501
2502/* Help display function for all node. */
2503DEFUN (config_list,
2504 config_list_cmd,
2505 "list",
2506 "Print command list\n")
2507{
hasso8c328f12004-10-05 21:01:23 +00002508 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002509 struct cmd_node *cnode = vector_slot (cmdvec, vty->node);
2510 struct cmd_element *cmd;
2511
paul55468c82005-03-14 20:19:01 +00002512 for (i = 0; i < vector_active (cnode->cmd_vector); i++)
paul4275b1d2005-03-09 13:42:23 +00002513 if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL
2514 && !(cmd->attr == CMD_ATTR_DEPRECATED
2515 || cmd->attr == CMD_ATTR_HIDDEN))
paul718e3742002-12-13 20:15:29 +00002516 vty_out (vty, " %s%s", cmd->string,
2517 VTY_NEWLINE);
2518 return CMD_SUCCESS;
2519}
2520
2521/* Write current configuration into file. */
2522DEFUN (config_write_file,
2523 config_write_file_cmd,
2524 "write file",
2525 "Write running configuration to memory, network, or terminal\n"
2526 "Write to configuration file\n")
2527{
hasso8c328f12004-10-05 21:01:23 +00002528 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002529 int fd;
2530 struct cmd_node *node;
2531 char *config_file;
2532 char *config_file_tmp = NULL;
2533 char *config_file_sav = NULL;
paul05865c92005-10-26 05:49:54 +00002534 int ret = CMD_WARNING;
paul718e3742002-12-13 20:15:29 +00002535 struct vty *file_vty;
2536
2537 /* Check and see if we are operating under vtysh configuration */
2538 if (host.config == NULL)
2539 {
2540 vty_out (vty, "Can't save to configuration file, using vtysh.%s",
2541 VTY_NEWLINE);
2542 return CMD_WARNING;
2543 }
2544
2545 /* Get filename. */
2546 config_file = host.config;
2547
paul05865c92005-10-26 05:49:54 +00002548 config_file_sav =
2549 XMALLOC (MTYPE_TMP, strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
paul718e3742002-12-13 20:15:29 +00002550 strcpy (config_file_sav, config_file);
2551 strcat (config_file_sav, CONF_BACKUP_EXT);
2552
2553
paul05865c92005-10-26 05:49:54 +00002554 config_file_tmp = XMALLOC (MTYPE_TMP, strlen (config_file) + 8);
paul718e3742002-12-13 20:15:29 +00002555 sprintf (config_file_tmp, "%s.XXXXXX", config_file);
2556
2557 /* Open file to configuration write. */
2558 fd = mkstemp (config_file_tmp);
2559 if (fd < 0)
2560 {
2561 vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
2562 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002563 goto finished;
paul718e3742002-12-13 20:15:29 +00002564 }
2565
2566 /* Make vty for configuration file. */
2567 file_vty = vty_new ();
2568 file_vty->fd = fd;
2569 file_vty->type = VTY_FILE;
2570
2571 /* Config file header print. */
2572 vty_out (file_vty, "!\n! Zebra configuration saved from vty\n! ");
2573 vty_time_print (file_vty, 1);
2574 vty_out (file_vty, "!\n");
2575
paul55468c82005-03-14 20:19:01 +00002576 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +00002577 if ((node = vector_slot (cmdvec, i)) && node->func)
2578 {
2579 if ((*node->func) (file_vty))
2580 vty_out (file_vty, "!\n");
2581 }
2582 vty_close (file_vty);
2583
2584 if (unlink (config_file_sav) != 0)
2585 if (errno != ENOENT)
2586 {
2587 vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
2588 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002589 goto finished;
paul718e3742002-12-13 20:15:29 +00002590 }
2591 if (link (config_file, config_file_sav) != 0)
2592 {
2593 vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
2594 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002595 goto finished;
paul718e3742002-12-13 20:15:29 +00002596 }
2597 sync ();
2598 if (unlink (config_file) != 0)
2599 {
2600 vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
2601 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002602 goto finished;
paul718e3742002-12-13 20:15:29 +00002603 }
2604 if (link (config_file_tmp, config_file) != 0)
2605 {
2606 vty_out (vty, "Can't save configuration file %s.%s", config_file,
2607 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002608 goto finished;
paul718e3742002-12-13 20:15:29 +00002609 }
paul718e3742002-12-13 20:15:29 +00002610 sync ();
2611
gdtaa593d52003-12-22 20:15:53 +00002612 if (chmod (config_file, CONFIGFILE_MASK) != 0)
2613 {
2614 vty_out (vty, "Can't chmod configuration file %s: %s (%d).%s",
ajs6099b3b2004-11-20 02:06:59 +00002615 config_file, safe_strerror(errno), errno, VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002616 goto finished;
gdtaa593d52003-12-22 20:15:53 +00002617 }
2618
paul718e3742002-12-13 20:15:29 +00002619 vty_out (vty, "Configuration saved to %s%s", config_file,
2620 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002621 ret = CMD_SUCCESS;
2622
2623finished:
2624 unlink (config_file_tmp);
2625 XFREE (MTYPE_TMP, config_file_tmp);
2626 XFREE (MTYPE_TMP, config_file_sav);
2627 return ret;
paul718e3742002-12-13 20:15:29 +00002628}
2629
2630ALIAS (config_write_file,
2631 config_write_cmd,
2632 "write",
2633 "Write running configuration to memory, network, or terminal\n")
2634
2635ALIAS (config_write_file,
2636 config_write_memory_cmd,
2637 "write memory",
2638 "Write running configuration to memory, network, or terminal\n"
2639 "Write configuration to the file (same as write file)\n")
2640
2641ALIAS (config_write_file,
2642 copy_runningconfig_startupconfig_cmd,
2643 "copy running-config startup-config",
2644 "Copy configuration\n"
2645 "Copy running config to... \n"
2646 "Copy running config to startup config (same as write file)\n")
2647
2648/* Write current configuration into the terminal. */
2649DEFUN (config_write_terminal,
2650 config_write_terminal_cmd,
2651 "write terminal",
2652 "Write running configuration to memory, network, or terminal\n"
2653 "Write to terminal\n")
2654{
hasso8c328f12004-10-05 21:01:23 +00002655 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002656 struct cmd_node *node;
2657
2658 if (vty->type == VTY_SHELL_SERV)
2659 {
paul55468c82005-03-14 20:19:01 +00002660 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +00002661 if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
2662 {
2663 if ((*node->func) (vty))
2664 vty_out (vty, "!%s", VTY_NEWLINE);
2665 }
2666 }
2667 else
2668 {
2669 vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
2670 VTY_NEWLINE);
2671 vty_out (vty, "!%s", VTY_NEWLINE);
2672
paul55468c82005-03-14 20:19:01 +00002673 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +00002674 if ((node = vector_slot (cmdvec, i)) && node->func)
2675 {
2676 if ((*node->func) (vty))
2677 vty_out (vty, "!%s", VTY_NEWLINE);
2678 }
2679 vty_out (vty, "end%s",VTY_NEWLINE);
2680 }
2681 return CMD_SUCCESS;
2682}
2683
2684/* Write current configuration into the terminal. */
2685ALIAS (config_write_terminal,
2686 show_running_config_cmd,
2687 "show running-config",
2688 SHOW_STR
2689 "running configuration\n")
2690
2691/* Write startup configuration into the terminal. */
2692DEFUN (show_startup_config,
2693 show_startup_config_cmd,
2694 "show startup-config",
2695 SHOW_STR
2696 "Contentes of startup configuration\n")
2697{
2698 char buf[BUFSIZ];
2699 FILE *confp;
2700
2701 confp = fopen (host.config, "r");
2702 if (confp == NULL)
2703 {
2704 vty_out (vty, "Can't open configuration file [%s]%s",
2705 host.config, VTY_NEWLINE);
2706 return CMD_WARNING;
2707 }
2708
2709 while (fgets (buf, BUFSIZ, confp))
2710 {
2711 char *cp = buf;
2712
2713 while (*cp != '\r' && *cp != '\n' && *cp != '\0')
2714 cp++;
2715 *cp = '\0';
2716
2717 vty_out (vty, "%s%s", buf, VTY_NEWLINE);
2718 }
2719
2720 fclose (confp);
2721
2722 return CMD_SUCCESS;
2723}
2724
2725/* Hostname configuration */
2726DEFUN (config_hostname,
2727 hostname_cmd,
2728 "hostname WORD",
2729 "Set system's network name\n"
2730 "This system's network name\n")
2731{
2732 if (!isalpha((int) *argv[0]))
2733 {
2734 vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
2735 return CMD_WARNING;
2736 }
2737
2738 if (host.name)
paul05865c92005-10-26 05:49:54 +00002739 XFREE (MTYPE_HOST, host.name);
paul718e3742002-12-13 20:15:29 +00002740
paul05865c92005-10-26 05:49:54 +00002741 host.name = XSTRDUP (MTYPE_HOST, argv[0]);
paul718e3742002-12-13 20:15:29 +00002742 return CMD_SUCCESS;
2743}
2744
2745DEFUN (config_no_hostname,
2746 no_hostname_cmd,
2747 "no hostname [HOSTNAME]",
2748 NO_STR
2749 "Reset system's network name\n"
2750 "Host name of this router\n")
2751{
2752 if (host.name)
paul05865c92005-10-26 05:49:54 +00002753 XFREE (MTYPE_HOST, host.name);
paul718e3742002-12-13 20:15:29 +00002754 host.name = NULL;
2755 return CMD_SUCCESS;
2756}
2757
2758/* VTY interface password set. */
2759DEFUN (config_password, password_cmd,
2760 "password (8|) WORD",
2761 "Assign the terminal connection password\n"
2762 "Specifies a HIDDEN password will follow\n"
2763 "dummy string \n"
2764 "The HIDDEN line password string\n")
2765{
2766 /* Argument check. */
2767 if (argc == 0)
2768 {
2769 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2770 return CMD_WARNING;
2771 }
2772
2773 if (argc == 2)
2774 {
2775 if (*argv[0] == '8')
2776 {
2777 if (host.password)
paul05865c92005-10-26 05:49:54 +00002778 XFREE (MTYPE_HOST, host.password);
paul718e3742002-12-13 20:15:29 +00002779 host.password = NULL;
2780 if (host.password_encrypt)
paul05865c92005-10-26 05:49:54 +00002781 XFREE (MTYPE_HOST, host.password_encrypt);
2782 host.password_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
paul718e3742002-12-13 20:15:29 +00002783 return CMD_SUCCESS;
2784 }
2785 else
2786 {
2787 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2788 return CMD_WARNING;
2789 }
2790 }
2791
2792 if (!isalnum ((int) *argv[0]))
2793 {
2794 vty_out (vty,
2795 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2796 return CMD_WARNING;
2797 }
2798
2799 if (host.password)
paul05865c92005-10-26 05:49:54 +00002800 XFREE (MTYPE_HOST, host.password);
paul718e3742002-12-13 20:15:29 +00002801 host.password = NULL;
2802
2803 if (host.encrypt)
2804 {
2805 if (host.password_encrypt)
paul05865c92005-10-26 05:49:54 +00002806 XFREE (MTYPE_HOST, host.password_encrypt);
2807 host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
paul718e3742002-12-13 20:15:29 +00002808 }
2809 else
paul05865c92005-10-26 05:49:54 +00002810 host.password = XSTRDUP (MTYPE_HOST, argv[0]);
paul718e3742002-12-13 20:15:29 +00002811
2812 return CMD_SUCCESS;
2813}
2814
2815ALIAS (config_password, password_text_cmd,
2816 "password LINE",
2817 "Assign the terminal connection password\n"
2818 "The UNENCRYPTED (cleartext) line password\n")
2819
2820/* VTY enable password set. */
2821DEFUN (config_enable_password, enable_password_cmd,
2822 "enable password (8|) WORD",
2823 "Modify enable password parameters\n"
2824 "Assign the privileged level password\n"
2825 "Specifies a HIDDEN password will follow\n"
2826 "dummy string \n"
2827 "The HIDDEN 'enable' password string\n")
2828{
2829 /* Argument check. */
2830 if (argc == 0)
2831 {
2832 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2833 return CMD_WARNING;
2834 }
2835
2836 /* Crypt type is specified. */
2837 if (argc == 2)
2838 {
2839 if (*argv[0] == '8')
2840 {
2841 if (host.enable)
paul05865c92005-10-26 05:49:54 +00002842 XFREE (MTYPE_HOST, host.enable);
paul718e3742002-12-13 20:15:29 +00002843 host.enable = NULL;
2844
2845 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002846 XFREE (MTYPE_HOST, host.enable_encrypt);
2847 host.enable_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
paul718e3742002-12-13 20:15:29 +00002848
2849 return CMD_SUCCESS;
2850 }
2851 else
2852 {
2853 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2854 return CMD_WARNING;
2855 }
2856 }
2857
2858 if (!isalnum ((int) *argv[0]))
2859 {
2860 vty_out (vty,
2861 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2862 return CMD_WARNING;
2863 }
2864
2865 if (host.enable)
paul05865c92005-10-26 05:49:54 +00002866 XFREE (MTYPE_HOST, host.enable);
paul718e3742002-12-13 20:15:29 +00002867 host.enable = NULL;
2868
2869 /* Plain password input. */
2870 if (host.encrypt)
2871 {
2872 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002873 XFREE (MTYPE_HOST, host.enable_encrypt);
2874 host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
paul718e3742002-12-13 20:15:29 +00002875 }
2876 else
paul05865c92005-10-26 05:49:54 +00002877 host.enable = XSTRDUP (MTYPE_HOST, argv[0]);
paul718e3742002-12-13 20:15:29 +00002878
2879 return CMD_SUCCESS;
2880}
2881
2882ALIAS (config_enable_password,
2883 enable_password_text_cmd,
2884 "enable password LINE",
2885 "Modify enable password parameters\n"
2886 "Assign the privileged level password\n"
2887 "The UNENCRYPTED (cleartext) 'enable' password\n")
2888
2889/* VTY enable password delete. */
2890DEFUN (no_config_enable_password, no_enable_password_cmd,
2891 "no enable password",
2892 NO_STR
2893 "Modify enable password parameters\n"
2894 "Assign the privileged level password\n")
2895{
2896 if (host.enable)
paul05865c92005-10-26 05:49:54 +00002897 XFREE (MTYPE_HOST, host.enable);
paul718e3742002-12-13 20:15:29 +00002898 host.enable = NULL;
2899
2900 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002901 XFREE (MTYPE_HOST, host.enable_encrypt);
paul718e3742002-12-13 20:15:29 +00002902 host.enable_encrypt = NULL;
2903
2904 return CMD_SUCCESS;
2905}
2906
2907DEFUN (service_password_encrypt,
2908 service_password_encrypt_cmd,
2909 "service password-encryption",
2910 "Set up miscellaneous service\n"
2911 "Enable encrypted passwords\n")
2912{
2913 if (host.encrypt)
2914 return CMD_SUCCESS;
2915
2916 host.encrypt = 1;
2917
2918 if (host.password)
2919 {
2920 if (host.password_encrypt)
paul05865c92005-10-26 05:49:54 +00002921 XFREE (MTYPE_HOST, host.password_encrypt);
2922 host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.password));
paul718e3742002-12-13 20:15:29 +00002923 }
2924 if (host.enable)
2925 {
2926 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002927 XFREE (MTYPE_HOST, host.enable_encrypt);
2928 host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.enable));
paul718e3742002-12-13 20:15:29 +00002929 }
2930
2931 return CMD_SUCCESS;
2932}
2933
2934DEFUN (no_service_password_encrypt,
2935 no_service_password_encrypt_cmd,
2936 "no service password-encryption",
2937 NO_STR
2938 "Set up miscellaneous service\n"
2939 "Enable encrypted passwords\n")
2940{
2941 if (! host.encrypt)
2942 return CMD_SUCCESS;
2943
2944 host.encrypt = 0;
2945
2946 if (host.password_encrypt)
paul05865c92005-10-26 05:49:54 +00002947 XFREE (MTYPE_HOST, host.password_encrypt);
paul718e3742002-12-13 20:15:29 +00002948 host.password_encrypt = NULL;
2949
2950 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002951 XFREE (MTYPE_HOST, host.enable_encrypt);
paul718e3742002-12-13 20:15:29 +00002952 host.enable_encrypt = NULL;
2953
2954 return CMD_SUCCESS;
2955}
2956
2957DEFUN (config_terminal_length, config_terminal_length_cmd,
2958 "terminal length <0-512>",
2959 "Set terminal line parameters\n"
2960 "Set number of lines on a screen\n"
2961 "Number of lines on screen (0 for no pausing)\n")
2962{
2963 int lines;
2964 char *endptr = NULL;
2965
2966 lines = strtol (argv[0], &endptr, 10);
2967 if (lines < 0 || lines > 512 || *endptr != '\0')
2968 {
2969 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2970 return CMD_WARNING;
2971 }
2972 vty->lines = lines;
2973
2974 return CMD_SUCCESS;
2975}
2976
2977DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
2978 "terminal no length",
2979 "Set terminal line parameters\n"
2980 NO_STR
2981 "Set number of lines on a screen\n")
2982{
2983 vty->lines = -1;
2984 return CMD_SUCCESS;
2985}
2986
2987DEFUN (service_terminal_length, service_terminal_length_cmd,
2988 "service terminal-length <0-512>",
2989 "Set up miscellaneous service\n"
2990 "System wide terminal length configuration\n"
2991 "Number of lines of VTY (0 means no line control)\n")
2992{
2993 int lines;
2994 char *endptr = NULL;
2995
2996 lines = strtol (argv[0], &endptr, 10);
2997 if (lines < 0 || lines > 512 || *endptr != '\0')
2998 {
2999 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
3000 return CMD_WARNING;
3001 }
3002 host.lines = lines;
3003
3004 return CMD_SUCCESS;
3005}
3006
3007DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
3008 "no service terminal-length [<0-512>]",
3009 NO_STR
3010 "Set up miscellaneous service\n"
3011 "System wide terminal length configuration\n"
3012 "Number of lines of VTY (0 means no line control)\n")
3013{
3014 host.lines = -1;
3015 return CMD_SUCCESS;
3016}
3017
ajs2885f722004-12-17 23:16:33 +00003018DEFUN_HIDDEN (do_echo,
3019 echo_cmd,
3020 "echo .MESSAGE",
3021 "Echo a message back to the vty\n"
3022 "The message to echo\n")
3023{
3024 char *message;
3025
ajsf6834d42005-01-28 20:28:35 +00003026 vty_out (vty, "%s%s", ((message = argv_concat(argv, argc, 0)) ? message : ""),
3027 VTY_NEWLINE);
3028 if (message)
3029 XFREE(MTYPE_TMP, message);
ajs2885f722004-12-17 23:16:33 +00003030 return CMD_SUCCESS;
3031}
3032
ajs274a4a42004-12-07 15:39:31 +00003033DEFUN (config_logmsg,
3034 config_logmsg_cmd,
3035 "logmsg "LOG_LEVELS" .MESSAGE",
3036 "Send a message to enabled logging destinations\n"
3037 LOG_LEVEL_DESC
3038 "The message to send\n")
3039{
3040 int level;
3041 char *message;
3042
3043 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3044 return CMD_ERR_NO_MATCH;
3045
ajsf6834d42005-01-28 20:28:35 +00003046 zlog(NULL, level, ((message = argv_concat(argv, argc, 1)) ? message : ""));
3047 if (message)
3048 XFREE(MTYPE_TMP, message);
ajs274a4a42004-12-07 15:39:31 +00003049 return CMD_SUCCESS;
3050}
3051
3052DEFUN (show_logging,
3053 show_logging_cmd,
3054 "show logging",
3055 SHOW_STR
3056 "Show current logging configuration\n")
3057{
3058 struct zlog *zl = zlog_default;
3059
3060 vty_out (vty, "Syslog logging: ");
3061 if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED)
3062 vty_out (vty, "disabled");
3063 else
3064 vty_out (vty, "level %s, facility %s, ident %s",
3065 zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]],
3066 facility_name(zl->facility), zl->ident);
3067 vty_out (vty, "%s", VTY_NEWLINE);
3068
3069 vty_out (vty, "Stdout logging: ");
3070 if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED)
3071 vty_out (vty, "disabled");
3072 else
3073 vty_out (vty, "level %s",
3074 zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
3075 vty_out (vty, "%s", VTY_NEWLINE);
3076
3077 vty_out (vty, "Monitor logging: ");
3078 if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
3079 vty_out (vty, "disabled");
3080 else
3081 vty_out (vty, "level %s",
3082 zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
3083 vty_out (vty, "%s", VTY_NEWLINE);
3084
3085 vty_out (vty, "File logging: ");
3086 if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) ||
3087 !zl->fp)
3088 vty_out (vty, "disabled");
3089 else
3090 vty_out (vty, "level %s, filename %s",
3091 zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
3092 zl->filename);
3093 vty_out (vty, "%s", VTY_NEWLINE);
3094
3095 vty_out (vty, "Protocol name: %s%s",
3096 zlog_proto_names[zl->protocol], VTY_NEWLINE);
3097 vty_out (vty, "Record priority: %s%s",
3098 (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE);
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +00003099 vty_out (vty, "Timestamp precision: %d%s",
3100 zl->timestamp_precision, VTY_NEWLINE);
ajs274a4a42004-12-07 15:39:31 +00003101
3102 return CMD_SUCCESS;
3103}
3104
paul718e3742002-12-13 20:15:29 +00003105DEFUN (config_log_stdout,
3106 config_log_stdout_cmd,
3107 "log stdout",
3108 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003109 "Set stdout logging level\n")
paul718e3742002-12-13 20:15:29 +00003110{
ajs274a4a42004-12-07 15:39:31 +00003111 zlog_set_level (NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl);
3112 return CMD_SUCCESS;
3113}
3114
3115DEFUN (config_log_stdout_level,
3116 config_log_stdout_level_cmd,
3117 "log stdout "LOG_LEVELS,
3118 "Logging control\n"
3119 "Set stdout logging level\n"
3120 LOG_LEVEL_DESC)
3121{
3122 int level;
3123
3124 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3125 return CMD_ERR_NO_MATCH;
3126 zlog_set_level (NULL, ZLOG_DEST_STDOUT, level);
paul718e3742002-12-13 20:15:29 +00003127 return CMD_SUCCESS;
3128}
3129
3130DEFUN (no_config_log_stdout,
3131 no_config_log_stdout_cmd,
ajs274a4a42004-12-07 15:39:31 +00003132 "no log stdout [LEVEL]",
paul718e3742002-12-13 20:15:29 +00003133 NO_STR
3134 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003135 "Cancel logging to stdout\n"
3136 "Logging level\n")
paul718e3742002-12-13 20:15:29 +00003137{
ajs274a4a42004-12-07 15:39:31 +00003138 zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED);
paul718e3742002-12-13 20:15:29 +00003139 return CMD_SUCCESS;
3140}
3141
ajs274a4a42004-12-07 15:39:31 +00003142DEFUN (config_log_monitor,
3143 config_log_monitor_cmd,
3144 "log monitor",
paul718e3742002-12-13 20:15:29 +00003145 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003146 "Set terminal line (monitor) logging level\n")
3147{
3148 zlog_set_level (NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl);
3149 return CMD_SUCCESS;
3150}
3151
3152DEFUN (config_log_monitor_level,
3153 config_log_monitor_level_cmd,
3154 "log monitor "LOG_LEVELS,
3155 "Logging control\n"
3156 "Set terminal line (monitor) logging level\n"
3157 LOG_LEVEL_DESC)
3158{
3159 int level;
3160
3161 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3162 return CMD_ERR_NO_MATCH;
3163 zlog_set_level (NULL, ZLOG_DEST_MONITOR, level);
3164 return CMD_SUCCESS;
3165}
3166
3167DEFUN (no_config_log_monitor,
3168 no_config_log_monitor_cmd,
3169 "no log monitor [LEVEL]",
3170 NO_STR
3171 "Logging control\n"
3172 "Disable terminal line (monitor) logging\n"
3173 "Logging level\n")
3174{
3175 zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
3176 return CMD_SUCCESS;
3177}
3178
3179static int
3180set_log_file(struct vty *vty, const char *fname, int loglevel)
paul718e3742002-12-13 20:15:29 +00003181{
3182 int ret;
paul9035efa2004-10-10 11:56:56 +00003183 char *p = NULL;
3184 const char *fullpath;
3185
paul718e3742002-12-13 20:15:29 +00003186 /* Path detection. */
ajs274a4a42004-12-07 15:39:31 +00003187 if (! IS_DIRECTORY_SEP (*fname))
paul718e3742002-12-13 20:15:29 +00003188 {
paul9035efa2004-10-10 11:56:56 +00003189 char cwd[MAXPATHLEN+1];
3190 cwd[MAXPATHLEN] = '\0';
3191
3192 if (getcwd (cwd, MAXPATHLEN) == NULL)
3193 {
3194 zlog_err ("config_log_file: Unable to alloc mem!");
3195 return CMD_WARNING;
3196 }
3197
ajs274a4a42004-12-07 15:39:31 +00003198 if ( (p = XMALLOC (MTYPE_TMP, strlen (cwd) + strlen (fname) + 2))
paul9035efa2004-10-10 11:56:56 +00003199 == NULL)
3200 {
3201 zlog_err ("config_log_file: Unable to alloc mem!");
3202 return CMD_WARNING;
3203 }
ajs274a4a42004-12-07 15:39:31 +00003204 sprintf (p, "%s/%s", cwd, fname);
paul9035efa2004-10-10 11:56:56 +00003205 fullpath = p;
paul718e3742002-12-13 20:15:29 +00003206 }
3207 else
ajs274a4a42004-12-07 15:39:31 +00003208 fullpath = fname;
paul718e3742002-12-13 20:15:29 +00003209
ajs274a4a42004-12-07 15:39:31 +00003210 ret = zlog_set_file (NULL, fullpath, loglevel);
paul718e3742002-12-13 20:15:29 +00003211
paul9035efa2004-10-10 11:56:56 +00003212 if (p)
3213 XFREE (MTYPE_TMP, p);
3214
paul718e3742002-12-13 20:15:29 +00003215 if (!ret)
3216 {
ajs274a4a42004-12-07 15:39:31 +00003217 vty_out (vty, "can't open logfile %s\n", fname);
paul718e3742002-12-13 20:15:29 +00003218 return CMD_WARNING;
3219 }
3220
3221 if (host.logfile)
paul05865c92005-10-26 05:49:54 +00003222 XFREE (MTYPE_HOST, host.logfile);
paul718e3742002-12-13 20:15:29 +00003223
paul05865c92005-10-26 05:49:54 +00003224 host.logfile = XSTRDUP (MTYPE_HOST, fname);
paul718e3742002-12-13 20:15:29 +00003225
3226 return CMD_SUCCESS;
3227}
3228
ajs274a4a42004-12-07 15:39:31 +00003229DEFUN (config_log_file,
3230 config_log_file_cmd,
3231 "log file FILENAME",
3232 "Logging control\n"
3233 "Logging to file\n"
3234 "Logging filename\n")
3235{
3236 return set_log_file(vty, argv[0], zlog_default->default_lvl);
3237}
3238
3239DEFUN (config_log_file_level,
3240 config_log_file_level_cmd,
3241 "log file FILENAME "LOG_LEVELS,
3242 "Logging control\n"
3243 "Logging to file\n"
3244 "Logging filename\n"
3245 LOG_LEVEL_DESC)
3246{
3247 int level;
3248
3249 if ((level = level_match(argv[1])) == ZLOG_DISABLED)
3250 return CMD_ERR_NO_MATCH;
3251 return set_log_file(vty, argv[0], level);
3252}
3253
paul718e3742002-12-13 20:15:29 +00003254DEFUN (no_config_log_file,
3255 no_config_log_file_cmd,
3256 "no log file [FILENAME]",
3257 NO_STR
3258 "Logging control\n"
3259 "Cancel logging to file\n"
3260 "Logging file name\n")
3261{
3262 zlog_reset_file (NULL);
3263
3264 if (host.logfile)
paul05865c92005-10-26 05:49:54 +00003265 XFREE (MTYPE_HOST, host.logfile);
paul718e3742002-12-13 20:15:29 +00003266
3267 host.logfile = NULL;
3268
3269 return CMD_SUCCESS;
3270}
3271
ajs274a4a42004-12-07 15:39:31 +00003272ALIAS (no_config_log_file,
3273 no_config_log_file_level_cmd,
3274 "no log file FILENAME LEVEL",
3275 NO_STR
3276 "Logging control\n"
3277 "Cancel logging to file\n"
3278 "Logging file name\n"
3279 "Logging level\n")
3280
paul718e3742002-12-13 20:15:29 +00003281DEFUN (config_log_syslog,
3282 config_log_syslog_cmd,
3283 "log syslog",
3284 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003285 "Set syslog logging level\n")
paul718e3742002-12-13 20:15:29 +00003286{
ajs274a4a42004-12-07 15:39:31 +00003287 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
paul12ab19f2003-07-26 06:14:55 +00003288 return CMD_SUCCESS;
3289}
3290
ajs274a4a42004-12-07 15:39:31 +00003291DEFUN (config_log_syslog_level,
3292 config_log_syslog_level_cmd,
3293 "log syslog "LOG_LEVELS,
paul12ab19f2003-07-26 06:14:55 +00003294 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003295 "Set syslog logging level\n"
3296 LOG_LEVEL_DESC)
paul12ab19f2003-07-26 06:14:55 +00003297{
ajs274a4a42004-12-07 15:39:31 +00003298 int level;
paul12ab19f2003-07-26 06:14:55 +00003299
ajs274a4a42004-12-07 15:39:31 +00003300 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3301 return CMD_ERR_NO_MATCH;
3302 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, level);
3303 return CMD_SUCCESS;
3304}
paul12ab19f2003-07-26 06:14:55 +00003305
ajs274a4a42004-12-07 15:39:31 +00003306DEFUN_DEPRECATED (config_log_syslog_facility,
3307 config_log_syslog_facility_cmd,
3308 "log syslog facility "LOG_FACILITIES,
3309 "Logging control\n"
3310 "Logging goes to syslog\n"
3311 "(Deprecated) Facility parameter for syslog messages\n"
3312 LOG_FACILITY_DESC)
3313{
3314 int facility;
paul12ab19f2003-07-26 06:14:55 +00003315
ajs274a4a42004-12-07 15:39:31 +00003316 if ((facility = facility_match(argv[0])) < 0)
3317 return CMD_ERR_NO_MATCH;
3318
3319 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
paul12ab19f2003-07-26 06:14:55 +00003320 zlog_default->facility = facility;
paul718e3742002-12-13 20:15:29 +00003321 return CMD_SUCCESS;
3322}
3323
3324DEFUN (no_config_log_syslog,
3325 no_config_log_syslog_cmd,
ajs274a4a42004-12-07 15:39:31 +00003326 "no log syslog [LEVEL]",
paul718e3742002-12-13 20:15:29 +00003327 NO_STR
3328 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003329 "Cancel logging to syslog\n"
3330 "Logging level\n")
paul718e3742002-12-13 20:15:29 +00003331{
ajs274a4a42004-12-07 15:39:31 +00003332 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
paul718e3742002-12-13 20:15:29 +00003333 return CMD_SUCCESS;
3334}
3335
paul12ab19f2003-07-26 06:14:55 +00003336ALIAS (no_config_log_syslog,
3337 no_config_log_syslog_facility_cmd,
ajs274a4a42004-12-07 15:39:31 +00003338 "no log syslog facility "LOG_FACILITIES,
paul12ab19f2003-07-26 06:14:55 +00003339 NO_STR
3340 "Logging control\n"
3341 "Logging goes to syslog\n"
3342 "Facility parameter for syslog messages\n"
ajs274a4a42004-12-07 15:39:31 +00003343 LOG_FACILITY_DESC)
paul12ab19f2003-07-26 06:14:55 +00003344
ajs274a4a42004-12-07 15:39:31 +00003345DEFUN (config_log_facility,
3346 config_log_facility_cmd,
3347 "log facility "LOG_FACILITIES,
paul718e3742002-12-13 20:15:29 +00003348 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003349 "Facility parameter for syslog messages\n"
3350 LOG_FACILITY_DESC)
paul718e3742002-12-13 20:15:29 +00003351{
ajs274a4a42004-12-07 15:39:31 +00003352 int facility;
3353
3354 if ((facility = facility_match(argv[0])) < 0)
3355 return CMD_ERR_NO_MATCH;
3356 zlog_default->facility = facility;
3357 return CMD_SUCCESS;
paul718e3742002-12-13 20:15:29 +00003358}
3359
ajs274a4a42004-12-07 15:39:31 +00003360DEFUN (no_config_log_facility,
3361 no_config_log_facility_cmd,
3362 "no log facility [FACILITY]",
paul718e3742002-12-13 20:15:29 +00003363 NO_STR
3364 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003365 "Reset syslog facility to default (daemon)\n"
3366 "Syslog facility\n")
paul718e3742002-12-13 20:15:29 +00003367{
ajs274a4a42004-12-07 15:39:31 +00003368 zlog_default->facility = LOG_DAEMON;
3369 return CMD_SUCCESS;
3370}
3371
3372DEFUN_DEPRECATED (config_log_trap,
3373 config_log_trap_cmd,
3374 "log trap "LOG_LEVELS,
3375 "Logging control\n"
3376 "(Deprecated) Set logging level and default for all destinations\n"
3377 LOG_LEVEL_DESC)
3378{
3379 int new_level ;
3380 int i;
3381
3382 if ((new_level = level_match(argv[0])) == ZLOG_DISABLED)
3383 return CMD_ERR_NO_MATCH;
3384
3385 zlog_default->default_lvl = new_level;
3386 for (i = 0; i < ZLOG_NUM_DESTS; i++)
3387 if (zlog_default->maxlvl[i] != ZLOG_DISABLED)
3388 zlog_default->maxlvl[i] = new_level;
3389 return CMD_SUCCESS;
3390}
3391
3392DEFUN_DEPRECATED (no_config_log_trap,
3393 no_config_log_trap_cmd,
3394 "no log trap [LEVEL]",
3395 NO_STR
3396 "Logging control\n"
3397 "Permit all logging information\n"
3398 "Logging level\n")
3399{
3400 zlog_default->default_lvl = LOG_DEBUG;
paul718e3742002-12-13 20:15:29 +00003401 return CMD_SUCCESS;
3402}
3403
3404DEFUN (config_log_record_priority,
3405 config_log_record_priority_cmd,
3406 "log record-priority",
3407 "Logging control\n"
3408 "Log the priority of the message within the message\n")
3409{
3410 zlog_default->record_priority = 1 ;
3411 return CMD_SUCCESS;
3412}
3413
3414DEFUN (no_config_log_record_priority,
3415 no_config_log_record_priority_cmd,
3416 "no log record-priority",
3417 NO_STR
3418 "Logging control\n"
3419 "Do not log the priority of the message within the message\n")
3420{
3421 zlog_default->record_priority = 0 ;
3422 return CMD_SUCCESS;
3423}
3424
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +00003425DEFUN (config_log_timestamp_precision,
3426 config_log_timestamp_precision_cmd,
3427 "log timestamp precision <0-6>",
3428 "Logging control\n"
3429 "Timestamp configuration\n"
3430 "Set the timestamp precision\n"
3431 "Number of subsecond digits\n")
3432{
3433 if (argc != 1)
3434 {
3435 vty_out (vty, "Insufficient arguments%s", VTY_NEWLINE);
3436 return CMD_WARNING;
3437 }
3438
3439 VTY_GET_INTEGER_RANGE("Timestamp Precision",
3440 zlog_default->timestamp_precision, argv[0], 0, 6);
3441 return CMD_SUCCESS;
3442}
3443
3444DEFUN (no_config_log_timestamp_precision,
3445 no_config_log_timestamp_precision_cmd,
3446 "no log timestamp precision",
3447 NO_STR
3448 "Logging control\n"
3449 "Timestamp configuration\n"
3450 "Reset the timestamp precision to the default value of 0\n")
3451{
3452 zlog_default->timestamp_precision = 0 ;
3453 return CMD_SUCCESS;
3454}
3455
paul3b0c5d92005-03-08 10:43:43 +00003456DEFUN (banner_motd_file,
3457 banner_motd_file_cmd,
3458 "banner motd file [FILE]",
3459 "Set banner\n"
3460 "Banner for motd\n"
3461 "Banner from a file\n"
3462 "Filename\n")
3463{
paulb45da6f2005-03-08 15:16:57 +00003464 if (host.motdfile)
paul05865c92005-10-26 05:49:54 +00003465 XFREE (MTYPE_HOST, host.motdfile);
3466 host.motdfile = XSTRDUP (MTYPE_HOST, argv[0]);
paulb45da6f2005-03-08 15:16:57 +00003467
paul3b0c5d92005-03-08 10:43:43 +00003468 return CMD_SUCCESS;
3469}
paul718e3742002-12-13 20:15:29 +00003470
3471DEFUN (banner_motd_default,
3472 banner_motd_default_cmd,
3473 "banner motd default",
3474 "Set banner string\n"
3475 "Strings for motd\n"
3476 "Default string\n")
3477{
3478 host.motd = default_motd;
3479 return CMD_SUCCESS;
3480}
3481
3482DEFUN (no_banner_motd,
3483 no_banner_motd_cmd,
3484 "no banner motd",
3485 NO_STR
3486 "Set banner string\n"
3487 "Strings for motd\n")
3488{
3489 host.motd = NULL;
paul22085182005-03-08 16:00:12 +00003490 if (host.motdfile)
paul05865c92005-10-26 05:49:54 +00003491 XFREE (MTYPE_HOST, host.motdfile);
paul3b0c5d92005-03-08 10:43:43 +00003492 host.motdfile = NULL;
paul718e3742002-12-13 20:15:29 +00003493 return CMD_SUCCESS;
3494}
3495
3496/* Set config filename. Called from vty.c */
3497void
3498host_config_set (char *filename)
3499{
paul05865c92005-10-26 05:49:54 +00003500 host.config = XSTRDUP (MTYPE_HOST, filename);
paul718e3742002-12-13 20:15:29 +00003501}
3502
3503void
3504install_default (enum node_type node)
3505{
3506 install_element (node, &config_exit_cmd);
3507 install_element (node, &config_quit_cmd);
3508 install_element (node, &config_end_cmd);
3509 install_element (node, &config_help_cmd);
3510 install_element (node, &config_list_cmd);
3511
3512 install_element (node, &config_write_terminal_cmd);
3513 install_element (node, &config_write_file_cmd);
3514 install_element (node, &config_write_memory_cmd);
3515 install_element (node, &config_write_cmd);
3516 install_element (node, &show_running_config_cmd);
3517}
3518
3519/* Initialize command interface. Install basic nodes and commands. */
3520void
3521cmd_init (int terminal)
3522{
3523 /* Allocate initial top vector of commands. */
3524 cmdvec = vector_init (VECTOR_MIN_SIZE);
3525
3526 /* Default host value settings. */
3527 host.name = NULL;
3528 host.password = NULL;
3529 host.enable = NULL;
3530 host.logfile = NULL;
3531 host.config = NULL;
3532 host.lines = -1;
3533 host.motd = default_motd;
paul3b0c5d92005-03-08 10:43:43 +00003534 host.motdfile = NULL;
paul718e3742002-12-13 20:15:29 +00003535
3536 /* Install top nodes. */
3537 install_node (&view_node, NULL);
3538 install_node (&enable_node, NULL);
3539 install_node (&auth_node, NULL);
3540 install_node (&auth_enable_node, NULL);
3541 install_node (&config_node, config_write_host);
3542
3543 /* Each node's basic commands. */
3544 install_element (VIEW_NODE, &show_version_cmd);
3545 if (terminal)
3546 {
3547 install_element (VIEW_NODE, &config_list_cmd);
3548 install_element (VIEW_NODE, &config_exit_cmd);
3549 install_element (VIEW_NODE, &config_quit_cmd);
3550 install_element (VIEW_NODE, &config_help_cmd);
3551 install_element (VIEW_NODE, &config_enable_cmd);
3552 install_element (VIEW_NODE, &config_terminal_length_cmd);
3553 install_element (VIEW_NODE, &config_terminal_no_length_cmd);
ajs274a4a42004-12-07 15:39:31 +00003554 install_element (VIEW_NODE, &show_logging_cmd);
ajs2885f722004-12-17 23:16:33 +00003555 install_element (VIEW_NODE, &echo_cmd);
paul718e3742002-12-13 20:15:29 +00003556 }
3557
3558 if (terminal)
3559 {
3560 install_default (ENABLE_NODE);
3561 install_element (ENABLE_NODE, &config_disable_cmd);
3562 install_element (ENABLE_NODE, &config_terminal_cmd);
3563 install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
3564 }
3565 install_element (ENABLE_NODE, &show_startup_config_cmd);
3566 install_element (ENABLE_NODE, &show_version_cmd);
paul718e3742002-12-13 20:15:29 +00003567
3568 if (terminal)
paul718e3742002-12-13 20:15:29 +00003569 {
hassoe7168df2004-10-03 20:11:32 +00003570 install_element (ENABLE_NODE, &config_terminal_length_cmd);
3571 install_element (ENABLE_NODE, &config_terminal_no_length_cmd);
ajs274a4a42004-12-07 15:39:31 +00003572 install_element (ENABLE_NODE, &show_logging_cmd);
ajs2885f722004-12-17 23:16:33 +00003573 install_element (ENABLE_NODE, &echo_cmd);
ajs274a4a42004-12-07 15:39:31 +00003574 install_element (ENABLE_NODE, &config_logmsg_cmd);
hassoe7168df2004-10-03 20:11:32 +00003575
3576 install_default (CONFIG_NODE);
hassoea8e9d92004-10-07 21:32:14 +00003577 }
3578
3579 install_element (CONFIG_NODE, &hostname_cmd);
3580 install_element (CONFIG_NODE, &no_hostname_cmd);
hassoe7168df2004-10-03 20:11:32 +00003581
hassoea8e9d92004-10-07 21:32:14 +00003582 if (terminal)
3583 {
hassoe7168df2004-10-03 20:11:32 +00003584 install_element (CONFIG_NODE, &password_cmd);
3585 install_element (CONFIG_NODE, &password_text_cmd);
3586 install_element (CONFIG_NODE, &enable_password_cmd);
3587 install_element (CONFIG_NODE, &enable_password_text_cmd);
3588 install_element (CONFIG_NODE, &no_enable_password_cmd);
3589
paul718e3742002-12-13 20:15:29 +00003590 install_element (CONFIG_NODE, &config_log_stdout_cmd);
ajs274a4a42004-12-07 15:39:31 +00003591 install_element (CONFIG_NODE, &config_log_stdout_level_cmd);
paul718e3742002-12-13 20:15:29 +00003592 install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
ajs274a4a42004-12-07 15:39:31 +00003593 install_element (CONFIG_NODE, &config_log_monitor_cmd);
3594 install_element (CONFIG_NODE, &config_log_monitor_level_cmd);
3595 install_element (CONFIG_NODE, &no_config_log_monitor_cmd);
paul718e3742002-12-13 20:15:29 +00003596 install_element (CONFIG_NODE, &config_log_file_cmd);
ajs274a4a42004-12-07 15:39:31 +00003597 install_element (CONFIG_NODE, &config_log_file_level_cmd);
paul718e3742002-12-13 20:15:29 +00003598 install_element (CONFIG_NODE, &no_config_log_file_cmd);
ajs274a4a42004-12-07 15:39:31 +00003599 install_element (CONFIG_NODE, &no_config_log_file_level_cmd);
paul718e3742002-12-13 20:15:29 +00003600 install_element (CONFIG_NODE, &config_log_syslog_cmd);
ajs274a4a42004-12-07 15:39:31 +00003601 install_element (CONFIG_NODE, &config_log_syslog_level_cmd);
paul12ab19f2003-07-26 06:14:55 +00003602 install_element (CONFIG_NODE, &config_log_syslog_facility_cmd);
paul718e3742002-12-13 20:15:29 +00003603 install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
paul12ab19f2003-07-26 06:14:55 +00003604 install_element (CONFIG_NODE, &no_config_log_syslog_facility_cmd);
ajs274a4a42004-12-07 15:39:31 +00003605 install_element (CONFIG_NODE, &config_log_facility_cmd);
3606 install_element (CONFIG_NODE, &no_config_log_facility_cmd);
paul718e3742002-12-13 20:15:29 +00003607 install_element (CONFIG_NODE, &config_log_trap_cmd);
3608 install_element (CONFIG_NODE, &no_config_log_trap_cmd);
3609 install_element (CONFIG_NODE, &config_log_record_priority_cmd);
3610 install_element (CONFIG_NODE, &no_config_log_record_priority_cmd);
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +00003611 install_element (CONFIG_NODE, &config_log_timestamp_precision_cmd);
3612 install_element (CONFIG_NODE, &no_config_log_timestamp_precision_cmd);
paul718e3742002-12-13 20:15:29 +00003613 install_element (CONFIG_NODE, &service_password_encrypt_cmd);
3614 install_element (CONFIG_NODE, &no_service_password_encrypt_cmd);
3615 install_element (CONFIG_NODE, &banner_motd_default_cmd);
paul3b0c5d92005-03-08 10:43:43 +00003616 install_element (CONFIG_NODE, &banner_motd_file_cmd);
paul718e3742002-12-13 20:15:29 +00003617 install_element (CONFIG_NODE, &no_banner_motd_cmd);
3618 install_element (CONFIG_NODE, &service_terminal_length_cmd);
3619 install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
paul718e3742002-12-13 20:15:29 +00003620
paul354d1192005-04-25 16:26:42 +00003621 install_element (VIEW_NODE, &show_thread_cpu_cmd);
3622 install_element (ENABLE_NODE, &show_thread_cpu_cmd);
3623 install_element (VIEW_NODE, &show_work_queues_cmd);
3624 install_element (ENABLE_NODE, &show_work_queues_cmd);
paul9ab68122003-01-18 01:16:20 +00003625 }
paul718e3742002-12-13 20:15:29 +00003626 srand(time(NULL));
3627}