blob: ac3516c344308040f616b81627b7b2371b948052 [file] [log] [blame]
ajs274a4a42004-12-07 15:39:31 +00001/*
paul05865c92005-10-26 05:49:54 +00002 $Id: command.c,v 1.51 2005/10/26 05:49:54 paul Exp $
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
597 if (host.advanced)
598 vty_out (vty, "service advanced-vty%s", VTY_NEWLINE);
599
600 if (host.encrypt)
601 vty_out (vty, "service password-encryption%s", VTY_NEWLINE);
602
603 if (host.lines >= 0)
604 vty_out (vty, "service terminal-length %d%s", host.lines,
605 VTY_NEWLINE);
606
paul3b0c5d92005-03-08 10:43:43 +0000607 if (host.motdfile)
608 vty_out (vty, "banner motd file %s%s", host.motdfile, VTY_NEWLINE);
609 else if (! host.motd)
paul718e3742002-12-13 20:15:29 +0000610 vty_out (vty, "no banner motd%s", VTY_NEWLINE);
611
612 return 1;
613}
614
615/* Utility function for getting command vector. */
ajs274a4a42004-12-07 15:39:31 +0000616static vector
paul718e3742002-12-13 20:15:29 +0000617cmd_node_vector (vector v, enum node_type ntype)
618{
619 struct cmd_node *cnode = vector_slot (v, ntype);
620 return cnode->cmd_vector;
621}
622
ajs274a4a42004-12-07 15:39:31 +0000623#if 0
624/* Filter command vector by symbol. This function is not actually used;
625 * should it be deleted? */
626static int
paul718e3742002-12-13 20:15:29 +0000627cmd_filter_by_symbol (char *command, char *symbol)
628{
629 int i, lim;
630
631 if (strcmp (symbol, "IPV4_ADDRESS") == 0)
632 {
633 i = 0;
634 lim = strlen (command);
635 while (i < lim)
636 {
637 if (! (isdigit ((int) command[i]) || command[i] == '.' || command[i] == '/'))
638 return 1;
639 i++;
640 }
641 return 0;
642 }
643 if (strcmp (symbol, "STRING") == 0)
644 {
645 i = 0;
646 lim = strlen (command);
647 while (i < lim)
648 {
649 if (! (isalpha ((int) command[i]) || command[i] == '_' || command[i] == '-'))
650 return 1;
651 i++;
652 }
653 return 0;
654 }
655 if (strcmp (symbol, "IFNAME") == 0)
656 {
657 i = 0;
658 lim = strlen (command);
659 while (i < lim)
660 {
661 if (! isalnum ((int) command[i]))
662 return 1;
663 i++;
664 }
665 return 0;
666 }
667 return 0;
668}
ajs274a4a42004-12-07 15:39:31 +0000669#endif
paul718e3742002-12-13 20:15:29 +0000670
671/* Completion match types. */
672enum match_type
673{
674 no_match,
675 extend_match,
676 ipv4_prefix_match,
677 ipv4_match,
678 ipv6_prefix_match,
679 ipv6_match,
680 range_match,
681 vararg_match,
682 partly_match,
683 exact_match
684};
685
ajs274a4a42004-12-07 15:39:31 +0000686static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000687cmd_ipv4_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000688{
hasso8c328f12004-10-05 21:01:23 +0000689 const char *sp;
paul718e3742002-12-13 20:15:29 +0000690 int dots = 0, nums = 0;
691 char buf[4];
692
693 if (str == NULL)
694 return partly_match;
695
696 for (;;)
697 {
698 memset (buf, 0, sizeof (buf));
699 sp = str;
700 while (*str != '\0')
701 {
702 if (*str == '.')
703 {
704 if (dots >= 3)
705 return no_match;
706
707 if (*(str + 1) == '.')
708 return no_match;
709
710 if (*(str + 1) == '\0')
711 return partly_match;
712
713 dots++;
714 break;
715 }
716 if (!isdigit ((int) *str))
717 return no_match;
718
719 str++;
720 }
721
722 if (str - sp > 3)
723 return no_match;
724
725 strncpy (buf, sp, str - sp);
726 if (atoi (buf) > 255)
727 return no_match;
728
729 nums++;
730
731 if (*str == '\0')
732 break;
733
734 str++;
735 }
736
737 if (nums < 4)
738 return partly_match;
739
740 return exact_match;
741}
742
ajs274a4a42004-12-07 15:39:31 +0000743static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000744cmd_ipv4_prefix_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000745{
hasso8c328f12004-10-05 21:01:23 +0000746 const char *sp;
paul718e3742002-12-13 20:15:29 +0000747 int dots = 0;
748 char buf[4];
749
750 if (str == NULL)
751 return partly_match;
752
753 for (;;)
754 {
755 memset (buf, 0, sizeof (buf));
756 sp = str;
757 while (*str != '\0' && *str != '/')
758 {
759 if (*str == '.')
760 {
761 if (dots == 3)
762 return no_match;
763
764 if (*(str + 1) == '.' || *(str + 1) == '/')
765 return no_match;
766
767 if (*(str + 1) == '\0')
768 return partly_match;
769
770 dots++;
771 break;
772 }
773
774 if (!isdigit ((int) *str))
775 return no_match;
776
777 str++;
778 }
779
780 if (str - sp > 3)
781 return no_match;
782
783 strncpy (buf, sp, str - sp);
784 if (atoi (buf) > 255)
785 return no_match;
786
787 if (dots == 3)
788 {
789 if (*str == '/')
790 {
791 if (*(str + 1) == '\0')
792 return partly_match;
793
794 str++;
795 break;
796 }
797 else if (*str == '\0')
798 return partly_match;
799 }
800
801 if (*str == '\0')
802 return partly_match;
803
804 str++;
805 }
806
807 sp = str;
808 while (*str != '\0')
809 {
810 if (!isdigit ((int) *str))
811 return no_match;
812
813 str++;
814 }
815
816 if (atoi (sp) > 32)
817 return no_match;
818
819 return exact_match;
820}
821
822#define IPV6_ADDR_STR "0123456789abcdefABCDEF:.%"
823#define IPV6_PREFIX_STR "0123456789abcdefABCDEF:.%/"
824#define STATE_START 1
825#define STATE_COLON 2
826#define STATE_DOUBLE 3
827#define STATE_ADDR 4
828#define STATE_DOT 5
829#define STATE_SLASH 6
830#define STATE_MASK 7
831
paul22e0a9e2003-07-11 17:55:46 +0000832#ifdef HAVE_IPV6
833
ajs274a4a42004-12-07 15:39:31 +0000834static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000835cmd_ipv6_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000836{
837 int state = STATE_START;
838 int colons = 0, nums = 0, double_colon = 0;
hasso8c328f12004-10-05 21:01:23 +0000839 const char *sp = NULL;
hasso726f9b22003-05-25 21:04:54 +0000840 struct sockaddr_in6 sin6_dummy;
841 int ret;
paul718e3742002-12-13 20:15:29 +0000842
843 if (str == NULL)
844 return partly_match;
845
846 if (strspn (str, IPV6_ADDR_STR) != strlen (str))
847 return no_match;
848
hasso726f9b22003-05-25 21:04:54 +0000849 /* use inet_pton that has a better support,
850 * for example inet_pton can support the automatic addresses:
851 * ::1.2.3.4
852 */
853 ret = inet_pton(AF_INET6, str, &sin6_dummy.sin6_addr);
854
855 if (ret == 1)
856 return exact_match;
857
paul718e3742002-12-13 20:15:29 +0000858 while (*str != '\0')
859 {
860 switch (state)
861 {
862 case STATE_START:
863 if (*str == ':')
864 {
865 if (*(str + 1) != ':' && *(str + 1) != '\0')
866 return no_match;
867 colons--;
868 state = STATE_COLON;
869 }
870 else
871 {
872 sp = str;
873 state = STATE_ADDR;
874 }
875
876 continue;
877 case STATE_COLON:
878 colons++;
879 if (*(str + 1) == ':')
880 state = STATE_DOUBLE;
881 else
882 {
883 sp = str + 1;
884 state = STATE_ADDR;
885 }
886 break;
887 case STATE_DOUBLE:
888 if (double_colon)
889 return no_match;
890
891 if (*(str + 1) == ':')
892 return no_match;
893 else
894 {
895 if (*(str + 1) != '\0')
896 colons++;
897 sp = str + 1;
898 state = STATE_ADDR;
899 }
900
901 double_colon++;
902 nums++;
903 break;
904 case STATE_ADDR:
905 if (*(str + 1) == ':' || *(str + 1) == '\0')
906 {
907 if (str - sp > 3)
908 return no_match;
909
910 nums++;
911 state = STATE_COLON;
912 }
913 if (*(str + 1) == '.')
914 state = STATE_DOT;
915 break;
916 case STATE_DOT:
917 state = STATE_ADDR;
918 break;
919 default:
920 break;
921 }
922
923 if (nums > 8)
924 return no_match;
925
926 if (colons > 7)
927 return no_match;
928
929 str++;
930 }
931
932#if 0
933 if (nums < 11)
934 return partly_match;
935#endif /* 0 */
936
937 return exact_match;
938}
939
ajs274a4a42004-12-07 15:39:31 +0000940static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000941cmd_ipv6_prefix_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000942{
943 int state = STATE_START;
944 int colons = 0, nums = 0, double_colon = 0;
945 int mask;
hasso8c328f12004-10-05 21:01:23 +0000946 const char *sp = NULL;
paul718e3742002-12-13 20:15:29 +0000947 char *endptr = NULL;
948
949 if (str == NULL)
950 return partly_match;
951
952 if (strspn (str, IPV6_PREFIX_STR) != strlen (str))
953 return no_match;
954
955 while (*str != '\0' && state != STATE_MASK)
956 {
957 switch (state)
958 {
959 case STATE_START:
960 if (*str == ':')
961 {
962 if (*(str + 1) != ':' && *(str + 1) != '\0')
963 return no_match;
964 colons--;
965 state = STATE_COLON;
966 }
967 else
968 {
969 sp = str;
970 state = STATE_ADDR;
971 }
972
973 continue;
974 case STATE_COLON:
975 colons++;
976 if (*(str + 1) == '/')
977 return no_match;
978 else if (*(str + 1) == ':')
979 state = STATE_DOUBLE;
980 else
981 {
982 sp = str + 1;
983 state = STATE_ADDR;
984 }
985 break;
986 case STATE_DOUBLE:
987 if (double_colon)
988 return no_match;
989
990 if (*(str + 1) == ':')
991 return no_match;
992 else
993 {
994 if (*(str + 1) != '\0' && *(str + 1) != '/')
995 colons++;
996 sp = str + 1;
997
998 if (*(str + 1) == '/')
999 state = STATE_SLASH;
1000 else
1001 state = STATE_ADDR;
1002 }
1003
1004 double_colon++;
1005 nums += 1;
1006 break;
1007 case STATE_ADDR:
1008 if (*(str + 1) == ':' || *(str + 1) == '.'
1009 || *(str + 1) == '\0' || *(str + 1) == '/')
1010 {
1011 if (str - sp > 3)
1012 return no_match;
1013
1014 for (; sp <= str; sp++)
1015 if (*sp == '/')
1016 return no_match;
1017
1018 nums++;
1019
1020 if (*(str + 1) == ':')
1021 state = STATE_COLON;
1022 else if (*(str + 1) == '.')
1023 state = STATE_DOT;
1024 else if (*(str + 1) == '/')
1025 state = STATE_SLASH;
1026 }
1027 break;
1028 case STATE_DOT:
1029 state = STATE_ADDR;
1030 break;
1031 case STATE_SLASH:
1032 if (*(str + 1) == '\0')
1033 return partly_match;
1034
1035 state = STATE_MASK;
1036 break;
1037 default:
1038 break;
1039 }
1040
1041 if (nums > 11)
1042 return no_match;
1043
1044 if (colons > 7)
1045 return no_match;
1046
1047 str++;
1048 }
1049
1050 if (state < STATE_MASK)
1051 return partly_match;
1052
1053 mask = strtol (str, &endptr, 10);
1054 if (*endptr != '\0')
1055 return no_match;
1056
1057 if (mask < 0 || mask > 128)
1058 return no_match;
1059
1060/* I don't know why mask < 13 makes command match partly.
1061 Forgive me to make this comments. I Want to set static default route
1062 because of lack of function to originate default in ospf6d; sorry
1063 yasu
1064 if (mask < 13)
1065 return partly_match;
1066*/
1067
1068 return exact_match;
1069}
1070
paul22e0a9e2003-07-11 17:55:46 +00001071#endif /* HAVE_IPV6 */
1072
paul718e3742002-12-13 20:15:29 +00001073#define DECIMAL_STRLEN_MAX 10
1074
ajs274a4a42004-12-07 15:39:31 +00001075static int
hasso8c328f12004-10-05 21:01:23 +00001076cmd_range_match (const char *range, const char *str)
paul718e3742002-12-13 20:15:29 +00001077{
1078 char *p;
1079 char buf[DECIMAL_STRLEN_MAX + 1];
1080 char *endptr = NULL;
1081 unsigned long min, max, val;
1082
1083 if (str == NULL)
1084 return 1;
1085
1086 val = strtoul (str, &endptr, 10);
1087 if (*endptr != '\0')
1088 return 0;
1089
1090 range++;
1091 p = strchr (range, '-');
1092 if (p == NULL)
1093 return 0;
1094 if (p - range > DECIMAL_STRLEN_MAX)
1095 return 0;
1096 strncpy (buf, range, p - range);
1097 buf[p - range] = '\0';
1098 min = strtoul (buf, &endptr, 10);
1099 if (*endptr != '\0')
1100 return 0;
1101
1102 range = p + 1;
1103 p = strchr (range, '>');
1104 if (p == NULL)
1105 return 0;
1106 if (p - range > DECIMAL_STRLEN_MAX)
1107 return 0;
1108 strncpy (buf, range, p - range);
1109 buf[p - range] = '\0';
1110 max = strtoul (buf, &endptr, 10);
1111 if (*endptr != '\0')
1112 return 0;
1113
1114 if (val < min || val > max)
1115 return 0;
1116
1117 return 1;
1118}
1119
1120/* Make completion match and return match type flag. */
ajs274a4a42004-12-07 15:39:31 +00001121static enum match_type
hasso8c328f12004-10-05 21:01:23 +00001122cmd_filter_by_completion (char *command, vector v, unsigned int index)
paul718e3742002-12-13 20:15:29 +00001123{
hasso8c328f12004-10-05 21:01:23 +00001124 unsigned int i;
1125 const char *str;
paul718e3742002-12-13 20:15:29 +00001126 struct cmd_element *cmd_element;
1127 enum match_type match_type;
1128 vector descvec;
1129 struct desc *desc;
paul909a2152005-03-14 17:41:45 +00001130
paul718e3742002-12-13 20:15:29 +00001131 match_type = no_match;
1132
1133 /* If command and cmd_element string does not match set NULL to vector */
paul55468c82005-03-14 20:19:01 +00001134 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001135 if ((cmd_element = vector_slot (v, i)) != NULL)
1136 {
paul55468c82005-03-14 20:19:01 +00001137 if (index >= vector_active (cmd_element->strvec))
paul718e3742002-12-13 20:15:29 +00001138 vector_slot (v, i) = NULL;
1139 else
1140 {
hasso8c328f12004-10-05 21:01:23 +00001141 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001142 int matched = 0;
1143
1144 descvec = vector_slot (cmd_element->strvec, index);
paul909a2152005-03-14 17:41:45 +00001145
paul55468c82005-03-14 20:19:01 +00001146 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001147 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001148 {
1149 str = desc->cmd;
1150
1151 if (CMD_VARARG (str))
1152 {
1153 if (match_type < vararg_match)
1154 match_type = vararg_match;
1155 matched++;
1156 }
1157 else if (CMD_RANGE (str))
1158 {
1159 if (cmd_range_match (str, command))
1160 {
1161 if (match_type < range_match)
1162 match_type = range_match;
paul718e3742002-12-13 20:15:29 +00001163
paul909a2152005-03-14 17:41:45 +00001164 matched++;
1165 }
1166 }
paul22e0a9e2003-07-11 17:55:46 +00001167#ifdef HAVE_IPV6
paul909a2152005-03-14 17:41:45 +00001168 else if (CMD_IPV6 (str))
1169 {
1170 if (cmd_ipv6_match (command))
1171 {
1172 if (match_type < ipv6_match)
1173 match_type = ipv6_match;
paul718e3742002-12-13 20:15:29 +00001174
paul909a2152005-03-14 17:41:45 +00001175 matched++;
1176 }
1177 }
1178 else if (CMD_IPV6_PREFIX (str))
1179 {
1180 if (cmd_ipv6_prefix_match (command))
1181 {
1182 if (match_type < ipv6_prefix_match)
1183 match_type = ipv6_prefix_match;
paul718e3742002-12-13 20:15:29 +00001184
paul909a2152005-03-14 17:41:45 +00001185 matched++;
1186 }
1187 }
1188#endif /* HAVE_IPV6 */
1189 else if (CMD_IPV4 (str))
1190 {
1191 if (cmd_ipv4_match (command))
1192 {
1193 if (match_type < ipv4_match)
1194 match_type = ipv4_match;
paul718e3742002-12-13 20:15:29 +00001195
paul909a2152005-03-14 17:41:45 +00001196 matched++;
1197 }
1198 }
1199 else if (CMD_IPV4_PREFIX (str))
1200 {
1201 if (cmd_ipv4_prefix_match (command))
1202 {
1203 if (match_type < ipv4_prefix_match)
1204 match_type = ipv4_prefix_match;
1205 matched++;
1206 }
1207 }
1208 else
1209 /* Check is this point's argument optional ? */
1210 if (CMD_OPTION (str) || CMD_VARIABLE (str))
1211 {
1212 if (match_type < extend_match)
1213 match_type = extend_match;
1214 matched++;
1215 }
1216 else if (strncmp (command, str, strlen (command)) == 0)
1217 {
1218 if (strcmp (command, str) == 0)
1219 match_type = exact_match;
1220 else
1221 {
1222 if (match_type < partly_match)
1223 match_type = partly_match;
1224 }
1225 matched++;
1226 }
1227 }
1228 if (!matched)
paul718e3742002-12-13 20:15:29 +00001229 vector_slot (v, i) = NULL;
1230 }
1231 }
1232 return match_type;
1233}
1234
1235/* Filter vector by command character with index. */
ajs274a4a42004-12-07 15:39:31 +00001236static enum match_type
hasso8c328f12004-10-05 21:01:23 +00001237cmd_filter_by_string (char *command, vector v, unsigned int index)
paul718e3742002-12-13 20:15:29 +00001238{
hasso8c328f12004-10-05 21:01:23 +00001239 unsigned int i;
1240 const char *str;
paul718e3742002-12-13 20:15:29 +00001241 struct cmd_element *cmd_element;
1242 enum match_type match_type;
1243 vector descvec;
1244 struct desc *desc;
paul909a2152005-03-14 17:41:45 +00001245
paul718e3742002-12-13 20:15:29 +00001246 match_type = no_match;
1247
1248 /* If command and cmd_element string does not match set NULL to vector */
paul55468c82005-03-14 20:19:01 +00001249 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001250 if ((cmd_element = vector_slot (v, i)) != NULL)
1251 {
1252 /* If given index is bigger than max string vector of command,
paul909a2152005-03-14 17:41:45 +00001253 set NULL */
paul55468c82005-03-14 20:19:01 +00001254 if (index >= vector_active (cmd_element->strvec))
paul718e3742002-12-13 20:15:29 +00001255 vector_slot (v, i) = NULL;
paul909a2152005-03-14 17:41:45 +00001256 else
paul718e3742002-12-13 20:15:29 +00001257 {
hasso8c328f12004-10-05 21:01:23 +00001258 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001259 int matched = 0;
1260
1261 descvec = vector_slot (cmd_element->strvec, index);
1262
paul55468c82005-03-14 20:19:01 +00001263 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001264 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001265 {
1266 str = desc->cmd;
paul718e3742002-12-13 20:15:29 +00001267
paul909a2152005-03-14 17:41:45 +00001268 if (CMD_VARARG (str))
1269 {
1270 if (match_type < vararg_match)
1271 match_type = vararg_match;
1272 matched++;
1273 }
1274 else if (CMD_RANGE (str))
1275 {
1276 if (cmd_range_match (str, command))
1277 {
1278 if (match_type < range_match)
1279 match_type = range_match;
1280 matched++;
1281 }
1282 }
paul22e0a9e2003-07-11 17:55:46 +00001283#ifdef HAVE_IPV6
paul909a2152005-03-14 17:41:45 +00001284 else if (CMD_IPV6 (str))
1285 {
1286 if (cmd_ipv6_match (command) == exact_match)
1287 {
1288 if (match_type < ipv6_match)
1289 match_type = ipv6_match;
1290 matched++;
1291 }
1292 }
1293 else if (CMD_IPV6_PREFIX (str))
1294 {
1295 if (cmd_ipv6_prefix_match (command) == exact_match)
1296 {
1297 if (match_type < ipv6_prefix_match)
1298 match_type = ipv6_prefix_match;
1299 matched++;
1300 }
1301 }
paul22e0a9e2003-07-11 17:55:46 +00001302#endif /* HAVE_IPV6 */
paul909a2152005-03-14 17:41:45 +00001303 else if (CMD_IPV4 (str))
1304 {
1305 if (cmd_ipv4_match (command) == exact_match)
1306 {
1307 if (match_type < ipv4_match)
1308 match_type = ipv4_match;
1309 matched++;
1310 }
1311 }
1312 else if (CMD_IPV4_PREFIX (str))
1313 {
1314 if (cmd_ipv4_prefix_match (command) == exact_match)
1315 {
1316 if (match_type < ipv4_prefix_match)
1317 match_type = ipv4_prefix_match;
1318 matched++;
1319 }
1320 }
1321 else if (CMD_OPTION (str) || CMD_VARIABLE (str))
1322 {
1323 if (match_type < extend_match)
1324 match_type = extend_match;
1325 matched++;
1326 }
1327 else
1328 {
1329 if (strcmp (command, str) == 0)
1330 {
1331 match_type = exact_match;
1332 matched++;
1333 }
1334 }
1335 }
1336 if (!matched)
paul718e3742002-12-13 20:15:29 +00001337 vector_slot (v, i) = NULL;
1338 }
1339 }
1340 return match_type;
1341}
1342
1343/* Check ambiguous match */
ajs274a4a42004-12-07 15:39:31 +00001344static int
paul718e3742002-12-13 20:15:29 +00001345is_cmd_ambiguous (char *command, vector v, int index, enum match_type type)
1346{
hasso8c328f12004-10-05 21:01:23 +00001347 unsigned int i;
1348 unsigned int j;
1349 const char *str = NULL;
paul718e3742002-12-13 20:15:29 +00001350 struct cmd_element *cmd_element;
hasso8c328f12004-10-05 21:01:23 +00001351 const char *matched = NULL;
paul718e3742002-12-13 20:15:29 +00001352 vector descvec;
1353 struct desc *desc;
paul909a2152005-03-14 17:41:45 +00001354
paul55468c82005-03-14 20:19:01 +00001355 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001356 if ((cmd_element = vector_slot (v, i)) != NULL)
1357 {
1358 int match = 0;
1359
1360 descvec = vector_slot (cmd_element->strvec, index);
1361
paul55468c82005-03-14 20:19:01 +00001362 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001363 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001364 {
1365 enum match_type ret;
1366
1367 str = desc->cmd;
paul718e3742002-12-13 20:15:29 +00001368
paul909a2152005-03-14 17:41:45 +00001369 switch (type)
1370 {
1371 case exact_match:
1372 if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
1373 && strcmp (command, str) == 0)
1374 match++;
1375 break;
1376 case partly_match:
1377 if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
1378 && strncmp (command, str, strlen (command)) == 0)
1379 {
1380 if (matched && strcmp (matched, str) != 0)
1381 return 1; /* There is ambiguous match. */
1382 else
1383 matched = str;
1384 match++;
1385 }
1386 break;
1387 case range_match:
1388 if (cmd_range_match (str, command))
1389 {
1390 if (matched && strcmp (matched, str) != 0)
1391 return 1;
1392 else
1393 matched = str;
1394 match++;
1395 }
1396 break;
1397#ifdef HAVE_IPV6
1398 case ipv6_match:
1399 if (CMD_IPV6 (str))
1400 match++;
1401 break;
1402 case ipv6_prefix_match:
1403 if ((ret = cmd_ipv6_prefix_match (command)) != no_match)
1404 {
1405 if (ret == partly_match)
1406 return 2; /* There is incomplete match. */
paul718e3742002-12-13 20:15:29 +00001407
paul909a2152005-03-14 17:41:45 +00001408 match++;
1409 }
1410 break;
1411#endif /* HAVE_IPV6 */
1412 case ipv4_match:
1413 if (CMD_IPV4 (str))
paul718e3742002-12-13 20:15:29 +00001414 match++;
paul909a2152005-03-14 17:41:45 +00001415 break;
1416 case ipv4_prefix_match:
1417 if ((ret = cmd_ipv4_prefix_match (command)) != no_match)
1418 {
1419 if (ret == partly_match)
1420 return 2; /* There is incomplete match. */
paul718e3742002-12-13 20:15:29 +00001421
paul909a2152005-03-14 17:41:45 +00001422 match++;
1423 }
1424 break;
1425 case extend_match:
1426 if (CMD_OPTION (str) || CMD_VARIABLE (str))
paul718e3742002-12-13 20:15:29 +00001427 match++;
paul909a2152005-03-14 17:41:45 +00001428 break;
1429 case no_match:
1430 default:
1431 break;
1432 }
1433 }
1434 if (!match)
paul718e3742002-12-13 20:15:29 +00001435 vector_slot (v, i) = NULL;
1436 }
1437 return 0;
1438}
1439
1440/* If src matches dst return dst string, otherwise return NULL */
ajs274a4a42004-12-07 15:39:31 +00001441static const char *
hasso8c328f12004-10-05 21:01:23 +00001442cmd_entry_function (const char *src, const char *dst)
paul718e3742002-12-13 20:15:29 +00001443{
1444 /* Skip variable arguments. */
1445 if (CMD_OPTION (dst) || CMD_VARIABLE (dst) || CMD_VARARG (dst) ||
1446 CMD_IPV4 (dst) || CMD_IPV4_PREFIX (dst) || CMD_RANGE (dst))
1447 return NULL;
1448
1449 /* In case of 'command \t', given src is NULL string. */
1450 if (src == NULL)
1451 return dst;
1452
1453 /* Matched with input string. */
1454 if (strncmp (src, dst, strlen (src)) == 0)
1455 return dst;
1456
1457 return NULL;
1458}
1459
1460/* If src matches dst return dst string, otherwise return NULL */
1461/* This version will return the dst string always if it is
1462 CMD_VARIABLE for '?' key processing */
ajs274a4a42004-12-07 15:39:31 +00001463static const char *
hasso8c328f12004-10-05 21:01:23 +00001464cmd_entry_function_desc (const char *src, const char *dst)
paul718e3742002-12-13 20:15:29 +00001465{
1466 if (CMD_VARARG (dst))
1467 return dst;
1468
1469 if (CMD_RANGE (dst))
1470 {
1471 if (cmd_range_match (dst, src))
1472 return dst;
1473 else
1474 return NULL;
1475 }
1476
paul22e0a9e2003-07-11 17:55:46 +00001477#ifdef HAVE_IPV6
paul718e3742002-12-13 20:15:29 +00001478 if (CMD_IPV6 (dst))
1479 {
1480 if (cmd_ipv6_match (src))
1481 return dst;
1482 else
1483 return NULL;
1484 }
1485
1486 if (CMD_IPV6_PREFIX (dst))
1487 {
1488 if (cmd_ipv6_prefix_match (src))
1489 return dst;
1490 else
1491 return NULL;
1492 }
paul22e0a9e2003-07-11 17:55:46 +00001493#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +00001494
1495 if (CMD_IPV4 (dst))
1496 {
1497 if (cmd_ipv4_match (src))
1498 return dst;
1499 else
1500 return NULL;
1501 }
1502
1503 if (CMD_IPV4_PREFIX (dst))
1504 {
1505 if (cmd_ipv4_prefix_match (src))
1506 return dst;
1507 else
1508 return NULL;
1509 }
1510
1511 /* Optional or variable commands always match on '?' */
1512 if (CMD_OPTION (dst) || CMD_VARIABLE (dst))
1513 return dst;
1514
1515 /* In case of 'command \t', given src is NULL string. */
1516 if (src == NULL)
1517 return dst;
1518
1519 if (strncmp (src, dst, strlen (src)) == 0)
1520 return dst;
1521 else
1522 return NULL;
1523}
1524
1525/* Check same string element existence. If it isn't there return
1526 1. */
ajs274a4a42004-12-07 15:39:31 +00001527static int
hasso8c328f12004-10-05 21:01:23 +00001528cmd_unique_string (vector v, const char *str)
paul718e3742002-12-13 20:15:29 +00001529{
hasso8c328f12004-10-05 21:01:23 +00001530 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001531 char *match;
1532
paul55468c82005-03-14 20:19:01 +00001533 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001534 if ((match = vector_slot (v, i)) != NULL)
1535 if (strcmp (match, str) == 0)
1536 return 0;
1537 return 1;
1538}
1539
1540/* Compare string to description vector. If there is same string
1541 return 1 else return 0. */
ajs274a4a42004-12-07 15:39:31 +00001542static int
hasso8c328f12004-10-05 21:01:23 +00001543desc_unique_string (vector v, const char *str)
paul718e3742002-12-13 20:15:29 +00001544{
hasso8c328f12004-10-05 21:01:23 +00001545 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001546 struct desc *desc;
1547
paul55468c82005-03-14 20:19:01 +00001548 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001549 if ((desc = vector_slot (v, i)) != NULL)
1550 if (strcmp (desc->cmd, str) == 0)
1551 return 1;
1552 return 0;
1553}
1554
ajs274a4a42004-12-07 15:39:31 +00001555static int
paulb92938a2002-12-13 21:20:42 +00001556cmd_try_do_shortcut (enum node_type node, char* first_word) {
1557 if ( first_word != NULL &&
1558 node != AUTH_NODE &&
1559 node != VIEW_NODE &&
1560 node != AUTH_ENABLE_NODE &&
1561 node != ENABLE_NODE &&
1562 0 == strcmp( "do", first_word ) )
1563 return 1;
1564 return 0;
1565}
1566
paul718e3742002-12-13 20:15:29 +00001567/* '?' describe command support. */
ajs274a4a42004-12-07 15:39:31 +00001568static vector
paulb92938a2002-12-13 21:20:42 +00001569cmd_describe_command_real (vector vline, struct vty *vty, int *status)
paul718e3742002-12-13 20:15:29 +00001570{
paulb8961472005-03-14 17:35:52 +00001571 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001572 vector cmd_vector;
1573#define INIT_MATCHVEC_SIZE 10
1574 vector matchvec;
1575 struct cmd_element *cmd_element;
paulb8961472005-03-14 17:35:52 +00001576 unsigned int index;
paul54aba542003-08-21 20:28:24 +00001577 int ret;
1578 enum match_type match;
1579 char *command;
paul718e3742002-12-13 20:15:29 +00001580 static struct desc desc_cr = { "<cr>", "" };
1581
1582 /* Set index. */
paul55468c82005-03-14 20:19:01 +00001583 if (vector_active (vline) == 0)
paulb8961472005-03-14 17:35:52 +00001584 {
1585 *status = CMD_ERR_NO_MATCH;
1586 return NULL;
1587 }
1588 else
paul55468c82005-03-14 20:19:01 +00001589 index = vector_active (vline) - 1;
paul909a2152005-03-14 17:41:45 +00001590
paul718e3742002-12-13 20:15:29 +00001591 /* Make copy vector of current node's command vector. */
1592 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1593
1594 /* Prepare match vector */
1595 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1596
1597 /* Filter commands. */
paul54aba542003-08-21 20:28:24 +00001598 /* Only words precedes current word will be checked in this loop. */
paul718e3742002-12-13 20:15:29 +00001599 for (i = 0; i < index; i++)
paulb8961472005-03-14 17:35:52 +00001600 if ((command = vector_slot (vline, i)))
paul909a2152005-03-14 17:41:45 +00001601 {
1602 match = cmd_filter_by_completion (command, cmd_vector, i);
1603
1604 if (match == vararg_match)
1605 {
1606 struct cmd_element *cmd_element;
1607 vector descvec;
1608 unsigned int j, k;
paul718e3742002-12-13 20:15:29 +00001609
paul55468c82005-03-14 20:19:01 +00001610 for (j = 0; j < vector_active (cmd_vector); j++)
paulb8961472005-03-14 17:35:52 +00001611 if ((cmd_element = vector_slot (cmd_vector, j)) != NULL
paul55468c82005-03-14 20:19:01 +00001612 && (vector_active (cmd_element->strvec)))
paul909a2152005-03-14 17:41:45 +00001613 {
1614 descvec = vector_slot (cmd_element->strvec,
paul55468c82005-03-14 20:19:01 +00001615 vector_active (cmd_element->strvec) - 1);
1616 for (k = 0; k < vector_active (descvec); k++)
paul909a2152005-03-14 17:41:45 +00001617 {
1618 struct desc *desc = vector_slot (descvec, k);
1619 vector_set (matchvec, desc);
1620 }
1621 }
1622
1623 vector_set (matchvec, &desc_cr);
1624 vector_free (cmd_vector);
paul718e3742002-12-13 20:15:29 +00001625
paul909a2152005-03-14 17:41:45 +00001626 return matchvec;
1627 }
paul718e3742002-12-13 20:15:29 +00001628
paul909a2152005-03-14 17:41:45 +00001629 if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
1630 {
1631 vector_free (cmd_vector);
1632 *status = CMD_ERR_AMBIGUOUS;
1633 return NULL;
1634 }
1635 else if (ret == 2)
1636 {
1637 vector_free (cmd_vector);
1638 *status = CMD_ERR_NO_MATCH;
1639 return NULL;
1640 }
1641 }
paul718e3742002-12-13 20:15:29 +00001642
1643 /* Prepare match vector */
1644 /* matchvec = vector_init (INIT_MATCHVEC_SIZE); */
1645
paul54aba542003-08-21 20:28:24 +00001646 /* Make sure that cmd_vector is filtered based on current word */
1647 command = vector_slot (vline, index);
1648 if (command)
1649 match = cmd_filter_by_completion (command, cmd_vector, index);
1650
paul718e3742002-12-13 20:15:29 +00001651 /* Make description vector. */
paul55468c82005-03-14 20:19:01 +00001652 for (i = 0; i < vector_active (cmd_vector); i++)
paul718e3742002-12-13 20:15:29 +00001653 if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
1654 {
hasso8c328f12004-10-05 21:01:23 +00001655 const char *string = NULL;
paul718e3742002-12-13 20:15:29 +00001656 vector strvec = cmd_element->strvec;
1657
paul55468c82005-03-14 20:19:01 +00001658 /* if command is NULL, index may be equal to vector_active */
1659 if (command && index >= vector_active (strvec))
paul718e3742002-12-13 20:15:29 +00001660 vector_slot (cmd_vector, i) = NULL;
1661 else
1662 {
paul54aba542003-08-21 20:28:24 +00001663 /* Check if command is completed. */
paul55468c82005-03-14 20:19:01 +00001664 if (command == NULL && index == vector_active (strvec))
paul718e3742002-12-13 20:15:29 +00001665 {
1666 string = "<cr>";
paul909a2152005-03-14 17:41:45 +00001667 if (!desc_unique_string (matchvec, string))
paul718e3742002-12-13 20:15:29 +00001668 vector_set (matchvec, &desc_cr);
1669 }
1670 else
1671 {
hasso8c328f12004-10-05 21:01:23 +00001672 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001673 vector descvec = vector_slot (strvec, index);
1674 struct desc *desc;
1675
paul55468c82005-03-14 20:19:01 +00001676 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001677 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001678 {
1679 string = cmd_entry_function_desc (command, desc->cmd);
1680 if (string)
1681 {
1682 /* Uniqueness check */
1683 if (!desc_unique_string (matchvec, string))
1684 vector_set (matchvec, desc);
1685 }
1686 }
paul718e3742002-12-13 20:15:29 +00001687 }
1688 }
1689 }
1690 vector_free (cmd_vector);
1691
1692 if (vector_slot (matchvec, 0) == NULL)
1693 {
1694 vector_free (matchvec);
paul909a2152005-03-14 17:41:45 +00001695 *status = CMD_ERR_NO_MATCH;
paul718e3742002-12-13 20:15:29 +00001696 }
1697 else
1698 *status = CMD_SUCCESS;
1699
1700 return matchvec;
1701}
1702
paulb92938a2002-12-13 21:20:42 +00001703vector
1704cmd_describe_command (vector vline, struct vty *vty, int *status)
1705{
1706 vector ret;
1707
1708 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1709 {
1710 enum node_type onode;
1711 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00001712 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00001713
1714 onode = vty->node;
1715 vty->node = ENABLE_NODE;
1716 /* We can try it on enable node, cos' the vty is authenticated */
1717
1718 shifted_vline = vector_init (vector_count(vline));
1719 /* use memcpy? */
paul55468c82005-03-14 20:19:01 +00001720 for (index = 1; index < vector_active (vline); index++)
paulb92938a2002-12-13 21:20:42 +00001721 {
1722 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1723 }
1724
1725 ret = cmd_describe_command_real (shifted_vline, vty, status);
1726
1727 vector_free(shifted_vline);
1728 vty->node = onode;
1729 return ret;
1730 }
1731
1732
1733 return cmd_describe_command_real (vline, vty, status);
1734}
1735
1736
paul718e3742002-12-13 20:15:29 +00001737/* Check LCD of matched command. */
ajs274a4a42004-12-07 15:39:31 +00001738static int
paul718e3742002-12-13 20:15:29 +00001739cmd_lcd (char **matched)
1740{
1741 int i;
1742 int j;
1743 int lcd = -1;
1744 char *s1, *s2;
1745 char c1, c2;
1746
1747 if (matched[0] == NULL || matched[1] == NULL)
1748 return 0;
1749
1750 for (i = 1; matched[i] != NULL; i++)
1751 {
1752 s1 = matched[i - 1];
1753 s2 = matched[i];
1754
1755 for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
1756 if (c1 != c2)
1757 break;
1758
1759 if (lcd < 0)
1760 lcd = j;
1761 else
1762 {
1763 if (lcd > j)
1764 lcd = j;
1765 }
1766 }
1767 return lcd;
1768}
1769
1770/* Command line completion support. */
ajs274a4a42004-12-07 15:39:31 +00001771static char **
paulb92938a2002-12-13 21:20:42 +00001772cmd_complete_command_real (vector vline, struct vty *vty, int *status)
paul718e3742002-12-13 20:15:29 +00001773{
paulb8961472005-03-14 17:35:52 +00001774 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001775 vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1776#define INIT_MATCHVEC_SIZE 10
1777 vector matchvec;
1778 struct cmd_element *cmd_element;
paulb8961472005-03-14 17:35:52 +00001779 unsigned int index;
paul718e3742002-12-13 20:15:29 +00001780 char **match_str;
1781 struct desc *desc;
1782 vector descvec;
1783 char *command;
1784 int lcd;
1785
paul55468c82005-03-14 20:19:01 +00001786 if (vector_active (vline) == 0)
paulb8961472005-03-14 17:35:52 +00001787 {
1788 *status = CMD_ERR_NO_MATCH;
1789 return NULL;
1790 }
1791 else
paul55468c82005-03-14 20:19:01 +00001792 index = vector_active (vline) - 1;
paulb8961472005-03-14 17:35:52 +00001793
paul718e3742002-12-13 20:15:29 +00001794 /* First, filter by preceeding command string */
1795 for (i = 0; i < index; i++)
paulb8961472005-03-14 17:35:52 +00001796 if ((command = vector_slot (vline, i)))
paul909a2152005-03-14 17:41:45 +00001797 {
1798 enum match_type match;
1799 int ret;
paul718e3742002-12-13 20:15:29 +00001800
paul909a2152005-03-14 17:41:45 +00001801 /* First try completion match, if there is exactly match return 1 */
1802 match = cmd_filter_by_completion (command, cmd_vector, i);
paul718e3742002-12-13 20:15:29 +00001803
paul909a2152005-03-14 17:41:45 +00001804 /* If there is exact match then filter ambiguous match else check
1805 ambiguousness. */
1806 if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
1807 {
1808 vector_free (cmd_vector);
1809 *status = CMD_ERR_AMBIGUOUS;
1810 return NULL;
1811 }
1812 /*
1813 else if (ret == 2)
1814 {
1815 vector_free (cmd_vector);
1816 *status = CMD_ERR_NO_MATCH;
1817 return NULL;
1818 }
1819 */
1820 }
1821
paul718e3742002-12-13 20:15:29 +00001822 /* Prepare match vector. */
1823 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1824
1825 /* Now we got into completion */
paul55468c82005-03-14 20:19:01 +00001826 for (i = 0; i < vector_active (cmd_vector); i++)
paulb8961472005-03-14 17:35:52 +00001827 if ((cmd_element = vector_slot (cmd_vector, i)))
paul718e3742002-12-13 20:15:29 +00001828 {
hasso8c328f12004-10-05 21:01:23 +00001829 const char *string;
paul718e3742002-12-13 20:15:29 +00001830 vector strvec = cmd_element->strvec;
paul909a2152005-03-14 17:41:45 +00001831
paul718e3742002-12-13 20:15:29 +00001832 /* Check field length */
paul55468c82005-03-14 20:19:01 +00001833 if (index >= vector_active (strvec))
paul718e3742002-12-13 20:15:29 +00001834 vector_slot (cmd_vector, i) = NULL;
paul909a2152005-03-14 17:41:45 +00001835 else
paul718e3742002-12-13 20:15:29 +00001836 {
hasso8c328f12004-10-05 21:01:23 +00001837 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001838
1839 descvec = vector_slot (strvec, index);
paul55468c82005-03-14 20:19:01 +00001840 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001841 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001842 {
paulb8961472005-03-14 17:35:52 +00001843 if ((string =
1844 cmd_entry_function (vector_slot (vline, index),
paul909a2152005-03-14 17:41:45 +00001845 desc->cmd)))
1846 if (cmd_unique_string (matchvec, string))
1847 vector_set (matchvec, XSTRDUP (MTYPE_TMP, string));
1848 }
paul718e3742002-12-13 20:15:29 +00001849 }
1850 }
1851
1852 /* We don't need cmd_vector any more. */
1853 vector_free (cmd_vector);
1854
1855 /* No matched command */
1856 if (vector_slot (matchvec, 0) == NULL)
1857 {
1858 vector_free (matchvec);
1859
1860 /* In case of 'command \t' pattern. Do you need '?' command at
1861 the end of the line. */
1862 if (vector_slot (vline, index) == '\0')
1863 *status = CMD_ERR_NOTHING_TODO;
1864 else
1865 *status = CMD_ERR_NO_MATCH;
1866 return NULL;
1867 }
1868
1869 /* Only one matched */
1870 if (vector_slot (matchvec, 1) == NULL)
1871 {
1872 match_str = (char **) matchvec->index;
1873 vector_only_wrapper_free (matchvec);
1874 *status = CMD_COMPLETE_FULL_MATCH;
1875 return match_str;
1876 }
1877 /* Make it sure last element is NULL. */
1878 vector_set (matchvec, NULL);
1879
1880 /* Check LCD of matched strings. */
1881 if (vector_slot (vline, index) != NULL)
1882 {
1883 lcd = cmd_lcd ((char **) matchvec->index);
1884
1885 if (lcd)
1886 {
1887 int len = strlen (vector_slot (vline, index));
paul909a2152005-03-14 17:41:45 +00001888
paul718e3742002-12-13 20:15:29 +00001889 if (len < lcd)
1890 {
1891 char *lcdstr;
paul909a2152005-03-14 17:41:45 +00001892
paul05865c92005-10-26 05:49:54 +00001893 lcdstr = XMALLOC (MTYPE_STRVEC, lcd + 1);
paul718e3742002-12-13 20:15:29 +00001894 memcpy (lcdstr, matchvec->index[0], lcd);
1895 lcdstr[lcd] = '\0';
1896
1897 /* match_str = (char **) &lcdstr; */
1898
1899 /* Free matchvec. */
paul55468c82005-03-14 20:19:01 +00001900 for (i = 0; i < vector_active (matchvec); i++)
paul718e3742002-12-13 20:15:29 +00001901 {
1902 if (vector_slot (matchvec, i))
paul05865c92005-10-26 05:49:54 +00001903 XFREE (MTYPE_STRVEC, vector_slot (matchvec, i));
paul718e3742002-12-13 20:15:29 +00001904 }
1905 vector_free (matchvec);
1906
paul909a2152005-03-14 17:41:45 +00001907 /* Make new matchvec. */
paul718e3742002-12-13 20:15:29 +00001908 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1909 vector_set (matchvec, lcdstr);
1910 match_str = (char **) matchvec->index;
1911 vector_only_wrapper_free (matchvec);
1912
1913 *status = CMD_COMPLETE_MATCH;
1914 return match_str;
1915 }
1916 }
1917 }
1918
1919 match_str = (char **) matchvec->index;
1920 vector_only_wrapper_free (matchvec);
1921 *status = CMD_COMPLETE_LIST_MATCH;
1922 return match_str;
1923}
1924
paulb92938a2002-12-13 21:20:42 +00001925char **
paul9ab68122003-01-18 01:16:20 +00001926cmd_complete_command (vector vline, struct vty *vty, int *status)
paulb92938a2002-12-13 21:20:42 +00001927{
1928 char **ret;
1929
1930 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1931 {
1932 enum node_type onode;
1933 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00001934 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00001935
1936 onode = vty->node;
1937 vty->node = ENABLE_NODE;
1938 /* We can try it on enable node, cos' the vty is authenticated */
1939
1940 shifted_vline = vector_init (vector_count(vline));
1941 /* use memcpy? */
paul55468c82005-03-14 20:19:01 +00001942 for (index = 1; index < vector_active (vline); index++)
paulb92938a2002-12-13 21:20:42 +00001943 {
1944 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1945 }
1946
1947 ret = cmd_complete_command_real (shifted_vline, vty, status);
1948
1949 vector_free(shifted_vline);
1950 vty->node = onode;
1951 return ret;
1952 }
1953
1954
1955 return cmd_complete_command_real (vline, vty, status);
1956}
1957
1958/* return parent node */
1959/* MUST eventually converge on CONFIG_NODE */
hasso13bfca72005-01-23 21:42:25 +00001960enum node_type
ajs274a4a42004-12-07 15:39:31 +00001961node_parent ( enum node_type node )
paulb92938a2002-12-13 21:20:42 +00001962{
1963 enum node_type ret;
1964
paul9ab68122003-01-18 01:16:20 +00001965 assert (node > CONFIG_NODE);
1966
1967 switch (node)
1968 {
1969 case BGP_VPNV4_NODE:
1970 case BGP_IPV4_NODE:
1971 case BGP_IPV4M_NODE:
1972 case BGP_IPV6_NODE:
paul1e836592005-08-22 22:39:56 +00001973 case BGP_IPV6M_NODE:
paul9ab68122003-01-18 01:16:20 +00001974 ret = BGP_NODE;
1975 break;
1976 case KEYCHAIN_KEY_NODE:
1977 ret = KEYCHAIN_NODE;
1978 break;
1979 default:
1980 ret = CONFIG_NODE;
paulb92938a2002-12-13 21:20:42 +00001981 }
1982
1983 return ret;
1984}
1985
paul718e3742002-12-13 20:15:29 +00001986/* Execute command by argument vline vector. */
ajs274a4a42004-12-07 15:39:31 +00001987static int
paulb8961472005-03-14 17:35:52 +00001988cmd_execute_command_real (vector vline, struct vty *vty,
1989 struct cmd_element **cmd)
paul718e3742002-12-13 20:15:29 +00001990{
hasso8c328f12004-10-05 21:01:23 +00001991 unsigned int i;
1992 unsigned int index;
paul718e3742002-12-13 20:15:29 +00001993 vector cmd_vector;
1994 struct cmd_element *cmd_element;
1995 struct cmd_element *matched_element;
1996 unsigned int matched_count, incomplete_count;
1997 int argc;
paul9035efa2004-10-10 11:56:56 +00001998 const char *argv[CMD_ARGC_MAX];
paul718e3742002-12-13 20:15:29 +00001999 enum match_type match = 0;
2000 int varflag;
2001 char *command;
2002
2003 /* Make copy of command elements. */
2004 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2005
paul55468c82005-03-14 20:19:01 +00002006 for (index = 0; index < vector_active (vline); index++)
paulb8961472005-03-14 17:35:52 +00002007 if ((command = vector_slot (vline, index)))
paul909a2152005-03-14 17:41:45 +00002008 {
2009 int ret;
paul718e3742002-12-13 20:15:29 +00002010
paul909a2152005-03-14 17:41:45 +00002011 match = cmd_filter_by_completion (command, cmd_vector, index);
paul718e3742002-12-13 20:15:29 +00002012
paul909a2152005-03-14 17:41:45 +00002013 if (match == vararg_match)
2014 break;
2015
2016 ret = is_cmd_ambiguous (command, cmd_vector, index, match);
paul718e3742002-12-13 20:15:29 +00002017
paul909a2152005-03-14 17:41:45 +00002018 if (ret == 1)
2019 {
2020 vector_free (cmd_vector);
2021 return CMD_ERR_AMBIGUOUS;
2022 }
2023 else if (ret == 2)
2024 {
2025 vector_free (cmd_vector);
2026 return CMD_ERR_NO_MATCH;
2027 }
2028 }
paul718e3742002-12-13 20:15:29 +00002029
2030 /* Check matched count. */
2031 matched_element = NULL;
2032 matched_count = 0;
2033 incomplete_count = 0;
2034
paul55468c82005-03-14 20:19:01 +00002035 for (i = 0; i < vector_active (cmd_vector); i++)
paulb8961472005-03-14 17:35:52 +00002036 if ((cmd_element = vector_slot (cmd_vector, i)))
paul718e3742002-12-13 20:15:29 +00002037 {
paul718e3742002-12-13 20:15:29 +00002038 if (match == vararg_match || index >= cmd_element->cmdsize)
2039 {
2040 matched_element = cmd_element;
2041#if 0
2042 printf ("DEBUG: %s\n", cmd_element->string);
2043#endif
2044 matched_count++;
2045 }
2046 else
2047 {
2048 incomplete_count++;
2049 }
2050 }
paul909a2152005-03-14 17:41:45 +00002051
paul718e3742002-12-13 20:15:29 +00002052 /* Finish of using cmd_vector. */
2053 vector_free (cmd_vector);
2054
paul909a2152005-03-14 17:41:45 +00002055 /* To execute command, matched_count must be 1. */
2056 if (matched_count == 0)
paul718e3742002-12-13 20:15:29 +00002057 {
2058 if (incomplete_count)
2059 return CMD_ERR_INCOMPLETE;
2060 else
2061 return CMD_ERR_NO_MATCH;
2062 }
2063
paul909a2152005-03-14 17:41:45 +00002064 if (matched_count > 1)
paul718e3742002-12-13 20:15:29 +00002065 return CMD_ERR_AMBIGUOUS;
2066
2067 /* Argument treatment */
2068 varflag = 0;
2069 argc = 0;
2070
paul55468c82005-03-14 20:19:01 +00002071 for (i = 0; i < vector_active (vline); i++)
paul718e3742002-12-13 20:15:29 +00002072 {
2073 if (varflag)
2074 argv[argc++] = vector_slot (vline, i);
2075 else
paul909a2152005-03-14 17:41:45 +00002076 {
paul718e3742002-12-13 20:15:29 +00002077 vector descvec = vector_slot (matched_element->strvec, i);
2078
paul55468c82005-03-14 20:19:01 +00002079 if (vector_active (descvec) == 1)
paul718e3742002-12-13 20:15:29 +00002080 {
2081 struct desc *desc = vector_slot (descvec, 0);
paul718e3742002-12-13 20:15:29 +00002082
hasso8c328f12004-10-05 21:01:23 +00002083 if (CMD_VARARG (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002084 varflag = 1;
2085
hasso8c328f12004-10-05 21:01:23 +00002086 if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002087 argv[argc++] = vector_slot (vline, i);
2088 }
2089 else
2090 argv[argc++] = vector_slot (vline, i);
2091 }
2092
2093 if (argc >= CMD_ARGC_MAX)
2094 return CMD_ERR_EXEED_ARGC_MAX;
2095 }
2096
2097 /* For vtysh execution. */
2098 if (cmd)
2099 *cmd = matched_element;
2100
2101 if (matched_element->daemon)
2102 return CMD_SUCCESS_DAEMON;
2103
2104 /* Execute matched command. */
2105 return (*matched_element->func) (matched_element, vty, argc, argv);
2106}
2107
paulb92938a2002-12-13 21:20:42 +00002108int
hasso87d683b2005-01-16 23:31:54 +00002109cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,
2110 int vtysh) {
paul9ab68122003-01-18 01:16:20 +00002111 int ret, saved_ret, tried = 0;
2112 enum node_type onode, try_node;
2113
2114 onode = try_node = vty->node;
paulb92938a2002-12-13 21:20:42 +00002115
2116 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
2117 {
2118 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00002119 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00002120
2121 vty->node = ENABLE_NODE;
2122 /* We can try it on enable node, cos' the vty is authenticated */
2123
2124 shifted_vline = vector_init (vector_count(vline));
2125 /* use memcpy? */
paul55468c82005-03-14 20:19:01 +00002126 for (index = 1; index < vector_active (vline); index++)
paulb92938a2002-12-13 21:20:42 +00002127 {
2128 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
2129 }
2130
2131 ret = cmd_execute_command_real (shifted_vline, vty, cmd);
2132
2133 vector_free(shifted_vline);
2134 vty->node = onode;
2135 return ret;
2136 }
2137
2138
paul9ab68122003-01-18 01:16:20 +00002139 saved_ret = ret = cmd_execute_command_real (vline, vty, cmd);
paulb92938a2002-12-13 21:20:42 +00002140
hasso87d683b2005-01-16 23:31:54 +00002141 if (vtysh)
2142 return saved_ret;
2143
paulb92938a2002-12-13 21:20:42 +00002144 /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
paul9ab68122003-01-18 01:16:20 +00002145 while ( ret != CMD_SUCCESS && ret != CMD_WARNING
paulb92938a2002-12-13 21:20:42 +00002146 && vty->node > CONFIG_NODE )
2147 {
paul9ab68122003-01-18 01:16:20 +00002148 try_node = node_parent(try_node);
2149 vty->node = try_node;
paulb92938a2002-12-13 21:20:42 +00002150 ret = cmd_execute_command_real (vline, vty, cmd);
paul9ab68122003-01-18 01:16:20 +00002151 tried = 1;
2152 if (ret == CMD_SUCCESS || ret == CMD_WARNING)
paulb92938a2002-12-13 21:20:42 +00002153 {
paul9ab68122003-01-18 01:16:20 +00002154 /* succesfull command, leave the node as is */
paulb92938a2002-12-13 21:20:42 +00002155 return ret;
2156 }
paulb92938a2002-12-13 21:20:42 +00002157 }
paul9ab68122003-01-18 01:16:20 +00002158 /* no command succeeded, reset the vty to the original node and
2159 return the error for this node */
2160 if ( tried )
2161 vty->node = onode;
2162 return saved_ret;
pauleda031f2003-01-18 00:39:19 +00002163}
2164
paul718e3742002-12-13 20:15:29 +00002165/* Execute command by argument readline. */
2166int
paul909a2152005-03-14 17:41:45 +00002167cmd_execute_command_strict (vector vline, struct vty *vty,
paul718e3742002-12-13 20:15:29 +00002168 struct cmd_element **cmd)
2169{
hasso8c328f12004-10-05 21:01:23 +00002170 unsigned int i;
2171 unsigned int index;
paul718e3742002-12-13 20:15:29 +00002172 vector cmd_vector;
2173 struct cmd_element *cmd_element;
2174 struct cmd_element *matched_element;
2175 unsigned int matched_count, incomplete_count;
2176 int argc;
paul9035efa2004-10-10 11:56:56 +00002177 const char *argv[CMD_ARGC_MAX];
paul718e3742002-12-13 20:15:29 +00002178 int varflag;
2179 enum match_type match = 0;
2180 char *command;
2181
2182 /* Make copy of command element */
2183 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2184
paul55468c82005-03-14 20:19:01 +00002185 for (index = 0; index < vector_active (vline); index++)
paulb8961472005-03-14 17:35:52 +00002186 if ((command = vector_slot (vline, index)))
paul909a2152005-03-14 17:41:45 +00002187 {
2188 int ret;
2189
2190 match = cmd_filter_by_string (vector_slot (vline, index),
2191 cmd_vector, index);
paul718e3742002-12-13 20:15:29 +00002192
paul909a2152005-03-14 17:41:45 +00002193 /* If command meets '.VARARG' then finish matching. */
2194 if (match == vararg_match)
2195 break;
2196
2197 ret = is_cmd_ambiguous (command, cmd_vector, index, match);
2198 if (ret == 1)
2199 {
2200 vector_free (cmd_vector);
2201 return CMD_ERR_AMBIGUOUS;
2202 }
2203 if (ret == 2)
2204 {
2205 vector_free (cmd_vector);
2206 return CMD_ERR_NO_MATCH;
2207 }
2208 }
paul718e3742002-12-13 20:15:29 +00002209
2210 /* Check matched count. */
2211 matched_element = NULL;
2212 matched_count = 0;
2213 incomplete_count = 0;
paul55468c82005-03-14 20:19:01 +00002214 for (i = 0; i < vector_active (cmd_vector); i++)
paul909a2152005-03-14 17:41:45 +00002215 if (vector_slot (cmd_vector, i) != NULL)
paul718e3742002-12-13 20:15:29 +00002216 {
paul909a2152005-03-14 17:41:45 +00002217 cmd_element = vector_slot (cmd_vector, i);
paul718e3742002-12-13 20:15:29 +00002218
2219 if (match == vararg_match || index >= cmd_element->cmdsize)
2220 {
2221 matched_element = cmd_element;
2222 matched_count++;
2223 }
2224 else
2225 incomplete_count++;
2226 }
paul909a2152005-03-14 17:41:45 +00002227
paul718e3742002-12-13 20:15:29 +00002228 /* Finish of using cmd_vector. */
2229 vector_free (cmd_vector);
2230
paul909a2152005-03-14 17:41:45 +00002231 /* To execute command, matched_count must be 1. */
2232 if (matched_count == 0)
paul718e3742002-12-13 20:15:29 +00002233 {
2234 if (incomplete_count)
2235 return CMD_ERR_INCOMPLETE;
2236 else
2237 return CMD_ERR_NO_MATCH;
2238 }
2239
paul909a2152005-03-14 17:41:45 +00002240 if (matched_count > 1)
paul718e3742002-12-13 20:15:29 +00002241 return CMD_ERR_AMBIGUOUS;
2242
2243 /* Argument treatment */
2244 varflag = 0;
2245 argc = 0;
2246
paul55468c82005-03-14 20:19:01 +00002247 for (i = 0; i < vector_active (vline); i++)
paul718e3742002-12-13 20:15:29 +00002248 {
2249 if (varflag)
2250 argv[argc++] = vector_slot (vline, i);
2251 else
paul909a2152005-03-14 17:41:45 +00002252 {
paul718e3742002-12-13 20:15:29 +00002253 vector descvec = vector_slot (matched_element->strvec, i);
2254
paul55468c82005-03-14 20:19:01 +00002255 if (vector_active (descvec) == 1)
paul718e3742002-12-13 20:15:29 +00002256 {
2257 struct desc *desc = vector_slot (descvec, 0);
paul718e3742002-12-13 20:15:29 +00002258
hasso8c328f12004-10-05 21:01:23 +00002259 if (CMD_VARARG (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002260 varflag = 1;
paul909a2152005-03-14 17:41:45 +00002261
hasso8c328f12004-10-05 21:01:23 +00002262 if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002263 argv[argc++] = vector_slot (vline, i);
2264 }
2265 else
2266 argv[argc++] = vector_slot (vline, i);
2267 }
2268
2269 if (argc >= CMD_ARGC_MAX)
2270 return CMD_ERR_EXEED_ARGC_MAX;
2271 }
2272
2273 /* For vtysh execution. */
2274 if (cmd)
2275 *cmd = matched_element;
2276
2277 if (matched_element->daemon)
2278 return CMD_SUCCESS_DAEMON;
2279
2280 /* Now execute matched command */
2281 return (*matched_element->func) (matched_element, vty, argc, argv);
2282}
2283
2284/* Configration make from file. */
2285int
2286config_from_file (struct vty *vty, FILE *fp)
2287{
2288 int ret;
2289 vector vline;
2290
2291 while (fgets (vty->buf, VTY_BUFSIZ, fp))
2292 {
2293 vline = cmd_make_strvec (vty->buf);
2294
2295 /* In case of comment line */
2296 if (vline == NULL)
2297 continue;
2298 /* Execute configuration command : this is strict match */
2299 ret = cmd_execute_command_strict (vline, vty, NULL);
2300
2301 /* Try again with setting node to CONFIG_NODE */
paulb92938a2002-12-13 21:20:42 +00002302 while (ret != CMD_SUCCESS && ret != CMD_WARNING
hassoddd85ed2004-10-13 08:18:07 +00002303 && ret != CMD_ERR_NOTHING_TODO && vty->node != CONFIG_NODE)
2304 {
paulb92938a2002-12-13 21:20:42 +00002305 vty->node = node_parent(vty->node);
hassoddd85ed2004-10-13 08:18:07 +00002306 ret = cmd_execute_command_strict (vline, vty, NULL);
2307 }
paul9ab68122003-01-18 01:16:20 +00002308
paul718e3742002-12-13 20:15:29 +00002309 cmd_free_strvec (vline);
2310
hassoddd85ed2004-10-13 08:18:07 +00002311 if (ret != CMD_SUCCESS && ret != CMD_WARNING
2312 && ret != CMD_ERR_NOTHING_TODO)
paul718e3742002-12-13 20:15:29 +00002313 return ret;
2314 }
2315 return CMD_SUCCESS;
2316}
2317
2318/* Configration from terminal */
2319DEFUN (config_terminal,
2320 config_terminal_cmd,
2321 "configure terminal",
2322 "Configuration from vty interface\n"
2323 "Configuration terminal\n")
2324{
2325 if (vty_config_lock (vty))
2326 vty->node = CONFIG_NODE;
2327 else
2328 {
2329 vty_out (vty, "VTY configuration is locked by other VTY%s", VTY_NEWLINE);
2330 return CMD_WARNING;
2331 }
2332 return CMD_SUCCESS;
2333}
2334
2335/* Enable command */
2336DEFUN (enable,
2337 config_enable_cmd,
2338 "enable",
2339 "Turn on privileged mode command\n")
2340{
2341 /* If enable password is NULL, change to ENABLE_NODE */
2342 if ((host.enable == NULL && host.enable_encrypt == NULL) ||
2343 vty->type == VTY_SHELL_SERV)
2344 vty->node = ENABLE_NODE;
2345 else
2346 vty->node = AUTH_ENABLE_NODE;
2347
2348 return CMD_SUCCESS;
2349}
2350
2351/* Disable command */
2352DEFUN (disable,
2353 config_disable_cmd,
2354 "disable",
2355 "Turn off privileged mode command\n")
2356{
2357 if (vty->node == ENABLE_NODE)
2358 vty->node = VIEW_NODE;
2359 return CMD_SUCCESS;
2360}
2361
2362/* Down vty node level. */
2363DEFUN (config_exit,
2364 config_exit_cmd,
2365 "exit",
2366 "Exit current mode and down to previous mode\n")
2367{
2368 switch (vty->node)
2369 {
2370 case VIEW_NODE:
2371 case ENABLE_NODE:
2372 if (vty_shell (vty))
2373 exit (0);
2374 else
2375 vty->status = VTY_CLOSE;
2376 break;
2377 case CONFIG_NODE:
2378 vty->node = ENABLE_NODE;
2379 vty_config_unlock (vty);
2380 break;
2381 case INTERFACE_NODE:
2382 case ZEBRA_NODE:
2383 case BGP_NODE:
2384 case RIP_NODE:
2385 case RIPNG_NODE:
2386 case OSPF_NODE:
2387 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00002388 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00002389 case KEYCHAIN_NODE:
2390 case MASC_NODE:
2391 case RMAP_NODE:
2392 case VTY_NODE:
2393 vty->node = CONFIG_NODE;
2394 break;
2395 case BGP_VPNV4_NODE:
2396 case BGP_IPV4_NODE:
2397 case BGP_IPV4M_NODE:
2398 case BGP_IPV6_NODE:
paul1e836592005-08-22 22:39:56 +00002399 case BGP_IPV6M_NODE:
paul718e3742002-12-13 20:15:29 +00002400 vty->node = BGP_NODE;
2401 break;
2402 case KEYCHAIN_KEY_NODE:
2403 vty->node = KEYCHAIN_NODE;
2404 break;
2405 default:
2406 break;
2407 }
2408 return CMD_SUCCESS;
2409}
2410
2411/* quit is alias of exit. */
2412ALIAS (config_exit,
2413 config_quit_cmd,
2414 "quit",
2415 "Exit current mode and down to previous mode\n")
2416
2417/* End of configuration. */
2418DEFUN (config_end,
2419 config_end_cmd,
2420 "end",
2421 "End current mode and change to enable mode.")
2422{
2423 switch (vty->node)
2424 {
2425 case VIEW_NODE:
2426 case ENABLE_NODE:
2427 /* Nothing to do. */
2428 break;
2429 case CONFIG_NODE:
2430 case INTERFACE_NODE:
2431 case ZEBRA_NODE:
2432 case RIP_NODE:
2433 case RIPNG_NODE:
2434 case BGP_NODE:
2435 case BGP_VPNV4_NODE:
2436 case BGP_IPV4_NODE:
2437 case BGP_IPV4M_NODE:
2438 case BGP_IPV6_NODE:
paul1e836592005-08-22 22:39:56 +00002439 case BGP_IPV6M_NODE:
paul718e3742002-12-13 20:15:29 +00002440 case RMAP_NODE:
2441 case OSPF_NODE:
2442 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00002443 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00002444 case KEYCHAIN_NODE:
2445 case KEYCHAIN_KEY_NODE:
2446 case MASC_NODE:
2447 case VTY_NODE:
2448 vty_config_unlock (vty);
2449 vty->node = ENABLE_NODE;
2450 break;
2451 default:
2452 break;
2453 }
2454 return CMD_SUCCESS;
2455}
2456
2457/* Show version. */
2458DEFUN (show_version,
2459 show_version_cmd,
2460 "show version",
2461 SHOW_STR
2462 "Displays zebra version\n")
2463{
hasso12f6ea22005-03-07 08:35:39 +00002464 vty_out (vty, "Quagga %s (%s).%s", QUAGGA_VERSION, host.name?host.name:"",
2465 VTY_NEWLINE);
hasso6590f2c2004-10-19 20:40:08 +00002466 vty_out (vty, "%s%s", QUAGGA_COPYRIGHT, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00002467
2468 return CMD_SUCCESS;
2469}
2470
2471/* Help display function for all node. */
2472DEFUN (config_help,
2473 config_help_cmd,
2474 "help",
2475 "Description of the interactive help system\n")
2476{
2477 vty_out (vty,
hasso6590f2c2004-10-19 20:40:08 +00002478 "Quagga VTY provides advanced help feature. When you need help,%s\
paul718e3742002-12-13 20:15:29 +00002479anytime at the command line please press '?'.%s\
2480%s\
2481If nothing matches, the help list will be empty and you must backup%s\
2482 until entering a '?' shows the available options.%s\
2483Two styles of help are provided:%s\
24841. Full help is available when you are ready to enter a%s\
2485command argument (e.g. 'show ?') and describes each possible%s\
2486argument.%s\
24872. Partial help is provided when an abbreviated argument is entered%s\
2488 and you want to know what arguments match the input%s\
2489 (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2490 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2491 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
2492 return CMD_SUCCESS;
2493}
2494
2495/* Help display function for all node. */
2496DEFUN (config_list,
2497 config_list_cmd,
2498 "list",
2499 "Print command list\n")
2500{
hasso8c328f12004-10-05 21:01:23 +00002501 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002502 struct cmd_node *cnode = vector_slot (cmdvec, vty->node);
2503 struct cmd_element *cmd;
2504
paul55468c82005-03-14 20:19:01 +00002505 for (i = 0; i < vector_active (cnode->cmd_vector); i++)
paul4275b1d2005-03-09 13:42:23 +00002506 if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL
2507 && !(cmd->attr == CMD_ATTR_DEPRECATED
2508 || cmd->attr == CMD_ATTR_HIDDEN))
paul718e3742002-12-13 20:15:29 +00002509 vty_out (vty, " %s%s", cmd->string,
2510 VTY_NEWLINE);
2511 return CMD_SUCCESS;
2512}
2513
2514/* Write current configuration into file. */
2515DEFUN (config_write_file,
2516 config_write_file_cmd,
2517 "write file",
2518 "Write running configuration to memory, network, or terminal\n"
2519 "Write to configuration file\n")
2520{
hasso8c328f12004-10-05 21:01:23 +00002521 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002522 int fd;
2523 struct cmd_node *node;
2524 char *config_file;
2525 char *config_file_tmp = NULL;
2526 char *config_file_sav = NULL;
paul05865c92005-10-26 05:49:54 +00002527 int ret = CMD_WARNING;
paul718e3742002-12-13 20:15:29 +00002528 struct vty *file_vty;
2529
2530 /* Check and see if we are operating under vtysh configuration */
2531 if (host.config == NULL)
2532 {
2533 vty_out (vty, "Can't save to configuration file, using vtysh.%s",
2534 VTY_NEWLINE);
2535 return CMD_WARNING;
2536 }
2537
2538 /* Get filename. */
2539 config_file = host.config;
2540
paul05865c92005-10-26 05:49:54 +00002541 config_file_sav =
2542 XMALLOC (MTYPE_TMP, strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
paul718e3742002-12-13 20:15:29 +00002543 strcpy (config_file_sav, config_file);
2544 strcat (config_file_sav, CONF_BACKUP_EXT);
2545
2546
paul05865c92005-10-26 05:49:54 +00002547 config_file_tmp = XMALLOC (MTYPE_TMP, strlen (config_file) + 8);
paul718e3742002-12-13 20:15:29 +00002548 sprintf (config_file_tmp, "%s.XXXXXX", config_file);
2549
2550 /* Open file to configuration write. */
2551 fd = mkstemp (config_file_tmp);
2552 if (fd < 0)
2553 {
2554 vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
2555 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002556 goto finished;
paul718e3742002-12-13 20:15:29 +00002557 }
2558
2559 /* Make vty for configuration file. */
2560 file_vty = vty_new ();
2561 file_vty->fd = fd;
2562 file_vty->type = VTY_FILE;
2563
2564 /* Config file header print. */
2565 vty_out (file_vty, "!\n! Zebra configuration saved from vty\n! ");
2566 vty_time_print (file_vty, 1);
2567 vty_out (file_vty, "!\n");
2568
paul55468c82005-03-14 20:19:01 +00002569 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +00002570 if ((node = vector_slot (cmdvec, i)) && node->func)
2571 {
2572 if ((*node->func) (file_vty))
2573 vty_out (file_vty, "!\n");
2574 }
2575 vty_close (file_vty);
2576
2577 if (unlink (config_file_sav) != 0)
2578 if (errno != ENOENT)
2579 {
2580 vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
2581 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002582 goto finished;
paul718e3742002-12-13 20:15:29 +00002583 }
2584 if (link (config_file, config_file_sav) != 0)
2585 {
2586 vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
2587 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002588 goto finished;
paul718e3742002-12-13 20:15:29 +00002589 }
2590 sync ();
2591 if (unlink (config_file) != 0)
2592 {
2593 vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
2594 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002595 goto finished;
paul718e3742002-12-13 20:15:29 +00002596 }
2597 if (link (config_file_tmp, config_file) != 0)
2598 {
2599 vty_out (vty, "Can't save configuration file %s.%s", config_file,
2600 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002601 goto finished;
paul718e3742002-12-13 20:15:29 +00002602 }
paul718e3742002-12-13 20:15:29 +00002603 sync ();
2604
gdtaa593d52003-12-22 20:15:53 +00002605 if (chmod (config_file, CONFIGFILE_MASK) != 0)
2606 {
2607 vty_out (vty, "Can't chmod configuration file %s: %s (%d).%s",
ajs6099b3b2004-11-20 02:06:59 +00002608 config_file, safe_strerror(errno), errno, VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002609 goto finished;
gdtaa593d52003-12-22 20:15:53 +00002610 }
2611
paul718e3742002-12-13 20:15:29 +00002612 vty_out (vty, "Configuration saved to %s%s", config_file,
2613 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002614 ret = CMD_SUCCESS;
2615
2616finished:
2617 unlink (config_file_tmp);
2618 XFREE (MTYPE_TMP, config_file_tmp);
2619 XFREE (MTYPE_TMP, config_file_sav);
2620 return ret;
paul718e3742002-12-13 20:15:29 +00002621}
2622
2623ALIAS (config_write_file,
2624 config_write_cmd,
2625 "write",
2626 "Write running configuration to memory, network, or terminal\n")
2627
2628ALIAS (config_write_file,
2629 config_write_memory_cmd,
2630 "write memory",
2631 "Write running configuration to memory, network, or terminal\n"
2632 "Write configuration to the file (same as write file)\n")
2633
2634ALIAS (config_write_file,
2635 copy_runningconfig_startupconfig_cmd,
2636 "copy running-config startup-config",
2637 "Copy configuration\n"
2638 "Copy running config to... \n"
2639 "Copy running config to startup config (same as write file)\n")
2640
2641/* Write current configuration into the terminal. */
2642DEFUN (config_write_terminal,
2643 config_write_terminal_cmd,
2644 "write terminal",
2645 "Write running configuration to memory, network, or terminal\n"
2646 "Write to terminal\n")
2647{
hasso8c328f12004-10-05 21:01:23 +00002648 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002649 struct cmd_node *node;
2650
2651 if (vty->type == VTY_SHELL_SERV)
2652 {
paul55468c82005-03-14 20:19:01 +00002653 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +00002654 if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
2655 {
2656 if ((*node->func) (vty))
2657 vty_out (vty, "!%s", VTY_NEWLINE);
2658 }
2659 }
2660 else
2661 {
2662 vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
2663 VTY_NEWLINE);
2664 vty_out (vty, "!%s", VTY_NEWLINE);
2665
paul55468c82005-03-14 20:19:01 +00002666 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +00002667 if ((node = vector_slot (cmdvec, i)) && node->func)
2668 {
2669 if ((*node->func) (vty))
2670 vty_out (vty, "!%s", VTY_NEWLINE);
2671 }
2672 vty_out (vty, "end%s",VTY_NEWLINE);
2673 }
2674 return CMD_SUCCESS;
2675}
2676
2677/* Write current configuration into the terminal. */
2678ALIAS (config_write_terminal,
2679 show_running_config_cmd,
2680 "show running-config",
2681 SHOW_STR
2682 "running configuration\n")
2683
2684/* Write startup configuration into the terminal. */
2685DEFUN (show_startup_config,
2686 show_startup_config_cmd,
2687 "show startup-config",
2688 SHOW_STR
2689 "Contentes of startup configuration\n")
2690{
2691 char buf[BUFSIZ];
2692 FILE *confp;
2693
2694 confp = fopen (host.config, "r");
2695 if (confp == NULL)
2696 {
2697 vty_out (vty, "Can't open configuration file [%s]%s",
2698 host.config, VTY_NEWLINE);
2699 return CMD_WARNING;
2700 }
2701
2702 while (fgets (buf, BUFSIZ, confp))
2703 {
2704 char *cp = buf;
2705
2706 while (*cp != '\r' && *cp != '\n' && *cp != '\0')
2707 cp++;
2708 *cp = '\0';
2709
2710 vty_out (vty, "%s%s", buf, VTY_NEWLINE);
2711 }
2712
2713 fclose (confp);
2714
2715 return CMD_SUCCESS;
2716}
2717
2718/* Hostname configuration */
2719DEFUN (config_hostname,
2720 hostname_cmd,
2721 "hostname WORD",
2722 "Set system's network name\n"
2723 "This system's network name\n")
2724{
2725 if (!isalpha((int) *argv[0]))
2726 {
2727 vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
2728 return CMD_WARNING;
2729 }
2730
2731 if (host.name)
paul05865c92005-10-26 05:49:54 +00002732 XFREE (MTYPE_HOST, host.name);
paul718e3742002-12-13 20:15:29 +00002733
paul05865c92005-10-26 05:49:54 +00002734 host.name = XSTRDUP (MTYPE_HOST, argv[0]);
paul718e3742002-12-13 20:15:29 +00002735 return CMD_SUCCESS;
2736}
2737
2738DEFUN (config_no_hostname,
2739 no_hostname_cmd,
2740 "no hostname [HOSTNAME]",
2741 NO_STR
2742 "Reset system's network name\n"
2743 "Host name of this router\n")
2744{
2745 if (host.name)
paul05865c92005-10-26 05:49:54 +00002746 XFREE (MTYPE_HOST, host.name);
paul718e3742002-12-13 20:15:29 +00002747 host.name = NULL;
2748 return CMD_SUCCESS;
2749}
2750
2751/* VTY interface password set. */
2752DEFUN (config_password, password_cmd,
2753 "password (8|) WORD",
2754 "Assign the terminal connection password\n"
2755 "Specifies a HIDDEN password will follow\n"
2756 "dummy string \n"
2757 "The HIDDEN line password string\n")
2758{
2759 /* Argument check. */
2760 if (argc == 0)
2761 {
2762 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2763 return CMD_WARNING;
2764 }
2765
2766 if (argc == 2)
2767 {
2768 if (*argv[0] == '8')
2769 {
2770 if (host.password)
paul05865c92005-10-26 05:49:54 +00002771 XFREE (MTYPE_HOST, host.password);
paul718e3742002-12-13 20:15:29 +00002772 host.password = NULL;
2773 if (host.password_encrypt)
paul05865c92005-10-26 05:49:54 +00002774 XFREE (MTYPE_HOST, host.password_encrypt);
2775 host.password_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
paul718e3742002-12-13 20:15:29 +00002776 return CMD_SUCCESS;
2777 }
2778 else
2779 {
2780 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2781 return CMD_WARNING;
2782 }
2783 }
2784
2785 if (!isalnum ((int) *argv[0]))
2786 {
2787 vty_out (vty,
2788 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2789 return CMD_WARNING;
2790 }
2791
2792 if (host.password)
paul05865c92005-10-26 05:49:54 +00002793 XFREE (MTYPE_HOST, host.password);
paul718e3742002-12-13 20:15:29 +00002794 host.password = NULL;
2795
2796 if (host.encrypt)
2797 {
2798 if (host.password_encrypt)
paul05865c92005-10-26 05:49:54 +00002799 XFREE (MTYPE_HOST, host.password_encrypt);
2800 host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
paul718e3742002-12-13 20:15:29 +00002801 }
2802 else
paul05865c92005-10-26 05:49:54 +00002803 host.password = XSTRDUP (MTYPE_HOST, argv[0]);
paul718e3742002-12-13 20:15:29 +00002804
2805 return CMD_SUCCESS;
2806}
2807
2808ALIAS (config_password, password_text_cmd,
2809 "password LINE",
2810 "Assign the terminal connection password\n"
2811 "The UNENCRYPTED (cleartext) line password\n")
2812
2813/* VTY enable password set. */
2814DEFUN (config_enable_password, enable_password_cmd,
2815 "enable password (8|) WORD",
2816 "Modify enable password parameters\n"
2817 "Assign the privileged level password\n"
2818 "Specifies a HIDDEN password will follow\n"
2819 "dummy string \n"
2820 "The HIDDEN 'enable' password string\n")
2821{
2822 /* Argument check. */
2823 if (argc == 0)
2824 {
2825 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2826 return CMD_WARNING;
2827 }
2828
2829 /* Crypt type is specified. */
2830 if (argc == 2)
2831 {
2832 if (*argv[0] == '8')
2833 {
2834 if (host.enable)
paul05865c92005-10-26 05:49:54 +00002835 XFREE (MTYPE_HOST, host.enable);
paul718e3742002-12-13 20:15:29 +00002836 host.enable = NULL;
2837
2838 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002839 XFREE (MTYPE_HOST, host.enable_encrypt);
2840 host.enable_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
paul718e3742002-12-13 20:15:29 +00002841
2842 return CMD_SUCCESS;
2843 }
2844 else
2845 {
2846 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2847 return CMD_WARNING;
2848 }
2849 }
2850
2851 if (!isalnum ((int) *argv[0]))
2852 {
2853 vty_out (vty,
2854 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2855 return CMD_WARNING;
2856 }
2857
2858 if (host.enable)
paul05865c92005-10-26 05:49:54 +00002859 XFREE (MTYPE_HOST, host.enable);
paul718e3742002-12-13 20:15:29 +00002860 host.enable = NULL;
2861
2862 /* Plain password input. */
2863 if (host.encrypt)
2864 {
2865 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002866 XFREE (MTYPE_HOST, host.enable_encrypt);
2867 host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
paul718e3742002-12-13 20:15:29 +00002868 }
2869 else
paul05865c92005-10-26 05:49:54 +00002870 host.enable = XSTRDUP (MTYPE_HOST, argv[0]);
paul718e3742002-12-13 20:15:29 +00002871
2872 return CMD_SUCCESS;
2873}
2874
2875ALIAS (config_enable_password,
2876 enable_password_text_cmd,
2877 "enable password LINE",
2878 "Modify enable password parameters\n"
2879 "Assign the privileged level password\n"
2880 "The UNENCRYPTED (cleartext) 'enable' password\n")
2881
2882/* VTY enable password delete. */
2883DEFUN (no_config_enable_password, no_enable_password_cmd,
2884 "no enable password",
2885 NO_STR
2886 "Modify enable password parameters\n"
2887 "Assign the privileged level password\n")
2888{
2889 if (host.enable)
paul05865c92005-10-26 05:49:54 +00002890 XFREE (MTYPE_HOST, host.enable);
paul718e3742002-12-13 20:15:29 +00002891 host.enable = NULL;
2892
2893 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002894 XFREE (MTYPE_HOST, host.enable_encrypt);
paul718e3742002-12-13 20:15:29 +00002895 host.enable_encrypt = NULL;
2896
2897 return CMD_SUCCESS;
2898}
2899
2900DEFUN (service_password_encrypt,
2901 service_password_encrypt_cmd,
2902 "service password-encryption",
2903 "Set up miscellaneous service\n"
2904 "Enable encrypted passwords\n")
2905{
2906 if (host.encrypt)
2907 return CMD_SUCCESS;
2908
2909 host.encrypt = 1;
2910
2911 if (host.password)
2912 {
2913 if (host.password_encrypt)
paul05865c92005-10-26 05:49:54 +00002914 XFREE (MTYPE_HOST, host.password_encrypt);
2915 host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.password));
paul718e3742002-12-13 20:15:29 +00002916 }
2917 if (host.enable)
2918 {
2919 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002920 XFREE (MTYPE_HOST, host.enable_encrypt);
2921 host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.enable));
paul718e3742002-12-13 20:15:29 +00002922 }
2923
2924 return CMD_SUCCESS;
2925}
2926
2927DEFUN (no_service_password_encrypt,
2928 no_service_password_encrypt_cmd,
2929 "no service password-encryption",
2930 NO_STR
2931 "Set up miscellaneous service\n"
2932 "Enable encrypted passwords\n")
2933{
2934 if (! host.encrypt)
2935 return CMD_SUCCESS;
2936
2937 host.encrypt = 0;
2938
2939 if (host.password_encrypt)
paul05865c92005-10-26 05:49:54 +00002940 XFREE (MTYPE_HOST, host.password_encrypt);
paul718e3742002-12-13 20:15:29 +00002941 host.password_encrypt = NULL;
2942
2943 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002944 XFREE (MTYPE_HOST, host.enable_encrypt);
paul718e3742002-12-13 20:15:29 +00002945 host.enable_encrypt = NULL;
2946
2947 return CMD_SUCCESS;
2948}
2949
2950DEFUN (config_terminal_length, config_terminal_length_cmd,
2951 "terminal length <0-512>",
2952 "Set terminal line parameters\n"
2953 "Set number of lines on a screen\n"
2954 "Number of lines on screen (0 for no pausing)\n")
2955{
2956 int lines;
2957 char *endptr = NULL;
2958
2959 lines = strtol (argv[0], &endptr, 10);
2960 if (lines < 0 || lines > 512 || *endptr != '\0')
2961 {
2962 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2963 return CMD_WARNING;
2964 }
2965 vty->lines = lines;
2966
2967 return CMD_SUCCESS;
2968}
2969
2970DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
2971 "terminal no length",
2972 "Set terminal line parameters\n"
2973 NO_STR
2974 "Set number of lines on a screen\n")
2975{
2976 vty->lines = -1;
2977 return CMD_SUCCESS;
2978}
2979
2980DEFUN (service_terminal_length, service_terminal_length_cmd,
2981 "service terminal-length <0-512>",
2982 "Set up miscellaneous service\n"
2983 "System wide terminal length configuration\n"
2984 "Number of lines of VTY (0 means no line control)\n")
2985{
2986 int lines;
2987 char *endptr = NULL;
2988
2989 lines = strtol (argv[0], &endptr, 10);
2990 if (lines < 0 || lines > 512 || *endptr != '\0')
2991 {
2992 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2993 return CMD_WARNING;
2994 }
2995 host.lines = lines;
2996
2997 return CMD_SUCCESS;
2998}
2999
3000DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
3001 "no service terminal-length [<0-512>]",
3002 NO_STR
3003 "Set up miscellaneous service\n"
3004 "System wide terminal length configuration\n"
3005 "Number of lines of VTY (0 means no line control)\n")
3006{
3007 host.lines = -1;
3008 return CMD_SUCCESS;
3009}
3010
ajs2885f722004-12-17 23:16:33 +00003011DEFUN_HIDDEN (do_echo,
3012 echo_cmd,
3013 "echo .MESSAGE",
3014 "Echo a message back to the vty\n"
3015 "The message to echo\n")
3016{
3017 char *message;
3018
ajsf6834d42005-01-28 20:28:35 +00003019 vty_out (vty, "%s%s", ((message = argv_concat(argv, argc, 0)) ? message : ""),
3020 VTY_NEWLINE);
3021 if (message)
3022 XFREE(MTYPE_TMP, message);
ajs2885f722004-12-17 23:16:33 +00003023 return CMD_SUCCESS;
3024}
3025
ajs274a4a42004-12-07 15:39:31 +00003026DEFUN (config_logmsg,
3027 config_logmsg_cmd,
3028 "logmsg "LOG_LEVELS" .MESSAGE",
3029 "Send a message to enabled logging destinations\n"
3030 LOG_LEVEL_DESC
3031 "The message to send\n")
3032{
3033 int level;
3034 char *message;
3035
3036 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3037 return CMD_ERR_NO_MATCH;
3038
ajsf6834d42005-01-28 20:28:35 +00003039 zlog(NULL, level, ((message = argv_concat(argv, argc, 1)) ? message : ""));
3040 if (message)
3041 XFREE(MTYPE_TMP, message);
ajs274a4a42004-12-07 15:39:31 +00003042 return CMD_SUCCESS;
3043}
3044
3045DEFUN (show_logging,
3046 show_logging_cmd,
3047 "show logging",
3048 SHOW_STR
3049 "Show current logging configuration\n")
3050{
3051 struct zlog *zl = zlog_default;
3052
3053 vty_out (vty, "Syslog logging: ");
3054 if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED)
3055 vty_out (vty, "disabled");
3056 else
3057 vty_out (vty, "level %s, facility %s, ident %s",
3058 zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]],
3059 facility_name(zl->facility), zl->ident);
3060 vty_out (vty, "%s", VTY_NEWLINE);
3061
3062 vty_out (vty, "Stdout logging: ");
3063 if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED)
3064 vty_out (vty, "disabled");
3065 else
3066 vty_out (vty, "level %s",
3067 zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
3068 vty_out (vty, "%s", VTY_NEWLINE);
3069
3070 vty_out (vty, "Monitor logging: ");
3071 if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
3072 vty_out (vty, "disabled");
3073 else
3074 vty_out (vty, "level %s",
3075 zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
3076 vty_out (vty, "%s", VTY_NEWLINE);
3077
3078 vty_out (vty, "File logging: ");
3079 if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) ||
3080 !zl->fp)
3081 vty_out (vty, "disabled");
3082 else
3083 vty_out (vty, "level %s, filename %s",
3084 zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
3085 zl->filename);
3086 vty_out (vty, "%s", VTY_NEWLINE);
3087
3088 vty_out (vty, "Protocol name: %s%s",
3089 zlog_proto_names[zl->protocol], VTY_NEWLINE);
3090 vty_out (vty, "Record priority: %s%s",
3091 (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE);
3092
3093 return CMD_SUCCESS;
3094}
3095
paul718e3742002-12-13 20:15:29 +00003096DEFUN (config_log_stdout,
3097 config_log_stdout_cmd,
3098 "log stdout",
3099 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003100 "Set stdout logging level\n")
paul718e3742002-12-13 20:15:29 +00003101{
ajs274a4a42004-12-07 15:39:31 +00003102 zlog_set_level (NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl);
3103 return CMD_SUCCESS;
3104}
3105
3106DEFUN (config_log_stdout_level,
3107 config_log_stdout_level_cmd,
3108 "log stdout "LOG_LEVELS,
3109 "Logging control\n"
3110 "Set stdout logging level\n"
3111 LOG_LEVEL_DESC)
3112{
3113 int level;
3114
3115 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3116 return CMD_ERR_NO_MATCH;
3117 zlog_set_level (NULL, ZLOG_DEST_STDOUT, level);
paul718e3742002-12-13 20:15:29 +00003118 return CMD_SUCCESS;
3119}
3120
3121DEFUN (no_config_log_stdout,
3122 no_config_log_stdout_cmd,
ajs274a4a42004-12-07 15:39:31 +00003123 "no log stdout [LEVEL]",
paul718e3742002-12-13 20:15:29 +00003124 NO_STR
3125 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003126 "Cancel logging to stdout\n"
3127 "Logging level\n")
paul718e3742002-12-13 20:15:29 +00003128{
ajs274a4a42004-12-07 15:39:31 +00003129 zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED);
paul718e3742002-12-13 20:15:29 +00003130 return CMD_SUCCESS;
3131}
3132
ajs274a4a42004-12-07 15:39:31 +00003133DEFUN (config_log_monitor,
3134 config_log_monitor_cmd,
3135 "log monitor",
paul718e3742002-12-13 20:15:29 +00003136 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003137 "Set terminal line (monitor) logging level\n")
3138{
3139 zlog_set_level (NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl);
3140 return CMD_SUCCESS;
3141}
3142
3143DEFUN (config_log_monitor_level,
3144 config_log_monitor_level_cmd,
3145 "log monitor "LOG_LEVELS,
3146 "Logging control\n"
3147 "Set terminal line (monitor) logging level\n"
3148 LOG_LEVEL_DESC)
3149{
3150 int level;
3151
3152 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3153 return CMD_ERR_NO_MATCH;
3154 zlog_set_level (NULL, ZLOG_DEST_MONITOR, level);
3155 return CMD_SUCCESS;
3156}
3157
3158DEFUN (no_config_log_monitor,
3159 no_config_log_monitor_cmd,
3160 "no log monitor [LEVEL]",
3161 NO_STR
3162 "Logging control\n"
3163 "Disable terminal line (monitor) logging\n"
3164 "Logging level\n")
3165{
3166 zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
3167 return CMD_SUCCESS;
3168}
3169
3170static int
3171set_log_file(struct vty *vty, const char *fname, int loglevel)
paul718e3742002-12-13 20:15:29 +00003172{
3173 int ret;
paul9035efa2004-10-10 11:56:56 +00003174 char *p = NULL;
3175 const char *fullpath;
3176
paul718e3742002-12-13 20:15:29 +00003177 /* Path detection. */
ajs274a4a42004-12-07 15:39:31 +00003178 if (! IS_DIRECTORY_SEP (*fname))
paul718e3742002-12-13 20:15:29 +00003179 {
paul9035efa2004-10-10 11:56:56 +00003180 char cwd[MAXPATHLEN+1];
3181 cwd[MAXPATHLEN] = '\0';
3182
3183 if (getcwd (cwd, MAXPATHLEN) == NULL)
3184 {
3185 zlog_err ("config_log_file: Unable to alloc mem!");
3186 return CMD_WARNING;
3187 }
3188
ajs274a4a42004-12-07 15:39:31 +00003189 if ( (p = XMALLOC (MTYPE_TMP, strlen (cwd) + strlen (fname) + 2))
paul9035efa2004-10-10 11:56:56 +00003190 == NULL)
3191 {
3192 zlog_err ("config_log_file: Unable to alloc mem!");
3193 return CMD_WARNING;
3194 }
ajs274a4a42004-12-07 15:39:31 +00003195 sprintf (p, "%s/%s", cwd, fname);
paul9035efa2004-10-10 11:56:56 +00003196 fullpath = p;
paul718e3742002-12-13 20:15:29 +00003197 }
3198 else
ajs274a4a42004-12-07 15:39:31 +00003199 fullpath = fname;
paul718e3742002-12-13 20:15:29 +00003200
ajs274a4a42004-12-07 15:39:31 +00003201 ret = zlog_set_file (NULL, fullpath, loglevel);
paul718e3742002-12-13 20:15:29 +00003202
paul9035efa2004-10-10 11:56:56 +00003203 if (p)
3204 XFREE (MTYPE_TMP, p);
3205
paul718e3742002-12-13 20:15:29 +00003206 if (!ret)
3207 {
ajs274a4a42004-12-07 15:39:31 +00003208 vty_out (vty, "can't open logfile %s\n", fname);
paul718e3742002-12-13 20:15:29 +00003209 return CMD_WARNING;
3210 }
3211
3212 if (host.logfile)
paul05865c92005-10-26 05:49:54 +00003213 XFREE (MTYPE_HOST, host.logfile);
paul718e3742002-12-13 20:15:29 +00003214
paul05865c92005-10-26 05:49:54 +00003215 host.logfile = XSTRDUP (MTYPE_HOST, fname);
paul718e3742002-12-13 20:15:29 +00003216
3217 return CMD_SUCCESS;
3218}
3219
ajs274a4a42004-12-07 15:39:31 +00003220DEFUN (config_log_file,
3221 config_log_file_cmd,
3222 "log file FILENAME",
3223 "Logging control\n"
3224 "Logging to file\n"
3225 "Logging filename\n")
3226{
3227 return set_log_file(vty, argv[0], zlog_default->default_lvl);
3228}
3229
3230DEFUN (config_log_file_level,
3231 config_log_file_level_cmd,
3232 "log file FILENAME "LOG_LEVELS,
3233 "Logging control\n"
3234 "Logging to file\n"
3235 "Logging filename\n"
3236 LOG_LEVEL_DESC)
3237{
3238 int level;
3239
3240 if ((level = level_match(argv[1])) == ZLOG_DISABLED)
3241 return CMD_ERR_NO_MATCH;
3242 return set_log_file(vty, argv[0], level);
3243}
3244
paul718e3742002-12-13 20:15:29 +00003245DEFUN (no_config_log_file,
3246 no_config_log_file_cmd,
3247 "no log file [FILENAME]",
3248 NO_STR
3249 "Logging control\n"
3250 "Cancel logging to file\n"
3251 "Logging file name\n")
3252{
3253 zlog_reset_file (NULL);
3254
3255 if (host.logfile)
paul05865c92005-10-26 05:49:54 +00003256 XFREE (MTYPE_HOST, host.logfile);
paul718e3742002-12-13 20:15:29 +00003257
3258 host.logfile = NULL;
3259
3260 return CMD_SUCCESS;
3261}
3262
ajs274a4a42004-12-07 15:39:31 +00003263ALIAS (no_config_log_file,
3264 no_config_log_file_level_cmd,
3265 "no log file FILENAME LEVEL",
3266 NO_STR
3267 "Logging control\n"
3268 "Cancel logging to file\n"
3269 "Logging file name\n"
3270 "Logging level\n")
3271
paul718e3742002-12-13 20:15:29 +00003272DEFUN (config_log_syslog,
3273 config_log_syslog_cmd,
3274 "log syslog",
3275 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003276 "Set syslog logging level\n")
paul718e3742002-12-13 20:15:29 +00003277{
ajs274a4a42004-12-07 15:39:31 +00003278 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
paul12ab19f2003-07-26 06:14:55 +00003279 return CMD_SUCCESS;
3280}
3281
ajs274a4a42004-12-07 15:39:31 +00003282DEFUN (config_log_syslog_level,
3283 config_log_syslog_level_cmd,
3284 "log syslog "LOG_LEVELS,
paul12ab19f2003-07-26 06:14:55 +00003285 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003286 "Set syslog logging level\n"
3287 LOG_LEVEL_DESC)
paul12ab19f2003-07-26 06:14:55 +00003288{
ajs274a4a42004-12-07 15:39:31 +00003289 int level;
paul12ab19f2003-07-26 06:14:55 +00003290
ajs274a4a42004-12-07 15:39:31 +00003291 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3292 return CMD_ERR_NO_MATCH;
3293 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, level);
3294 return CMD_SUCCESS;
3295}
paul12ab19f2003-07-26 06:14:55 +00003296
ajs274a4a42004-12-07 15:39:31 +00003297DEFUN_DEPRECATED (config_log_syslog_facility,
3298 config_log_syslog_facility_cmd,
3299 "log syslog facility "LOG_FACILITIES,
3300 "Logging control\n"
3301 "Logging goes to syslog\n"
3302 "(Deprecated) Facility parameter for syslog messages\n"
3303 LOG_FACILITY_DESC)
3304{
3305 int facility;
paul12ab19f2003-07-26 06:14:55 +00003306
ajs274a4a42004-12-07 15:39:31 +00003307 if ((facility = facility_match(argv[0])) < 0)
3308 return CMD_ERR_NO_MATCH;
3309
3310 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
paul12ab19f2003-07-26 06:14:55 +00003311 zlog_default->facility = facility;
paul718e3742002-12-13 20:15:29 +00003312 return CMD_SUCCESS;
3313}
3314
3315DEFUN (no_config_log_syslog,
3316 no_config_log_syslog_cmd,
ajs274a4a42004-12-07 15:39:31 +00003317 "no log syslog [LEVEL]",
paul718e3742002-12-13 20:15:29 +00003318 NO_STR
3319 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003320 "Cancel logging to syslog\n"
3321 "Logging level\n")
paul718e3742002-12-13 20:15:29 +00003322{
ajs274a4a42004-12-07 15:39:31 +00003323 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
paul718e3742002-12-13 20:15:29 +00003324 return CMD_SUCCESS;
3325}
3326
paul12ab19f2003-07-26 06:14:55 +00003327ALIAS (no_config_log_syslog,
3328 no_config_log_syslog_facility_cmd,
ajs274a4a42004-12-07 15:39:31 +00003329 "no log syslog facility "LOG_FACILITIES,
paul12ab19f2003-07-26 06:14:55 +00003330 NO_STR
3331 "Logging control\n"
3332 "Logging goes to syslog\n"
3333 "Facility parameter for syslog messages\n"
ajs274a4a42004-12-07 15:39:31 +00003334 LOG_FACILITY_DESC)
paul12ab19f2003-07-26 06:14:55 +00003335
ajs274a4a42004-12-07 15:39:31 +00003336DEFUN (config_log_facility,
3337 config_log_facility_cmd,
3338 "log facility "LOG_FACILITIES,
paul718e3742002-12-13 20:15:29 +00003339 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003340 "Facility parameter for syslog messages\n"
3341 LOG_FACILITY_DESC)
paul718e3742002-12-13 20:15:29 +00003342{
ajs274a4a42004-12-07 15:39:31 +00003343 int facility;
3344
3345 if ((facility = facility_match(argv[0])) < 0)
3346 return CMD_ERR_NO_MATCH;
3347 zlog_default->facility = facility;
3348 return CMD_SUCCESS;
paul718e3742002-12-13 20:15:29 +00003349}
3350
ajs274a4a42004-12-07 15:39:31 +00003351DEFUN (no_config_log_facility,
3352 no_config_log_facility_cmd,
3353 "no log facility [FACILITY]",
paul718e3742002-12-13 20:15:29 +00003354 NO_STR
3355 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003356 "Reset syslog facility to default (daemon)\n"
3357 "Syslog facility\n")
paul718e3742002-12-13 20:15:29 +00003358{
ajs274a4a42004-12-07 15:39:31 +00003359 zlog_default->facility = LOG_DAEMON;
3360 return CMD_SUCCESS;
3361}
3362
3363DEFUN_DEPRECATED (config_log_trap,
3364 config_log_trap_cmd,
3365 "log trap "LOG_LEVELS,
3366 "Logging control\n"
3367 "(Deprecated) Set logging level and default for all destinations\n"
3368 LOG_LEVEL_DESC)
3369{
3370 int new_level ;
3371 int i;
3372
3373 if ((new_level = level_match(argv[0])) == ZLOG_DISABLED)
3374 return CMD_ERR_NO_MATCH;
3375
3376 zlog_default->default_lvl = new_level;
3377 for (i = 0; i < ZLOG_NUM_DESTS; i++)
3378 if (zlog_default->maxlvl[i] != ZLOG_DISABLED)
3379 zlog_default->maxlvl[i] = new_level;
3380 return CMD_SUCCESS;
3381}
3382
3383DEFUN_DEPRECATED (no_config_log_trap,
3384 no_config_log_trap_cmd,
3385 "no log trap [LEVEL]",
3386 NO_STR
3387 "Logging control\n"
3388 "Permit all logging information\n"
3389 "Logging level\n")
3390{
3391 zlog_default->default_lvl = LOG_DEBUG;
paul718e3742002-12-13 20:15:29 +00003392 return CMD_SUCCESS;
3393}
3394
3395DEFUN (config_log_record_priority,
3396 config_log_record_priority_cmd,
3397 "log record-priority",
3398 "Logging control\n"
3399 "Log the priority of the message within the message\n")
3400{
3401 zlog_default->record_priority = 1 ;
3402 return CMD_SUCCESS;
3403}
3404
3405DEFUN (no_config_log_record_priority,
3406 no_config_log_record_priority_cmd,
3407 "no log record-priority",
3408 NO_STR
3409 "Logging control\n"
3410 "Do not log the priority of the message within the message\n")
3411{
3412 zlog_default->record_priority = 0 ;
3413 return CMD_SUCCESS;
3414}
3415
paul3b0c5d92005-03-08 10:43:43 +00003416DEFUN (banner_motd_file,
3417 banner_motd_file_cmd,
3418 "banner motd file [FILE]",
3419 "Set banner\n"
3420 "Banner for motd\n"
3421 "Banner from a file\n"
3422 "Filename\n")
3423{
paulb45da6f2005-03-08 15:16:57 +00003424 if (host.motdfile)
paul05865c92005-10-26 05:49:54 +00003425 XFREE (MTYPE_HOST, host.motdfile);
3426 host.motdfile = XSTRDUP (MTYPE_HOST, argv[0]);
paulb45da6f2005-03-08 15:16:57 +00003427
paul3b0c5d92005-03-08 10:43:43 +00003428 return CMD_SUCCESS;
3429}
paul718e3742002-12-13 20:15:29 +00003430
3431DEFUN (banner_motd_default,
3432 banner_motd_default_cmd,
3433 "banner motd default",
3434 "Set banner string\n"
3435 "Strings for motd\n"
3436 "Default string\n")
3437{
3438 host.motd = default_motd;
3439 return CMD_SUCCESS;
3440}
3441
3442DEFUN (no_banner_motd,
3443 no_banner_motd_cmd,
3444 "no banner motd",
3445 NO_STR
3446 "Set banner string\n"
3447 "Strings for motd\n")
3448{
3449 host.motd = NULL;
paul22085182005-03-08 16:00:12 +00003450 if (host.motdfile)
paul05865c92005-10-26 05:49:54 +00003451 XFREE (MTYPE_HOST, host.motdfile);
paul3b0c5d92005-03-08 10:43:43 +00003452 host.motdfile = NULL;
paul718e3742002-12-13 20:15:29 +00003453 return CMD_SUCCESS;
3454}
3455
3456/* Set config filename. Called from vty.c */
3457void
3458host_config_set (char *filename)
3459{
paul05865c92005-10-26 05:49:54 +00003460 host.config = XSTRDUP (MTYPE_HOST, filename);
paul718e3742002-12-13 20:15:29 +00003461}
3462
3463void
3464install_default (enum node_type node)
3465{
3466 install_element (node, &config_exit_cmd);
3467 install_element (node, &config_quit_cmd);
3468 install_element (node, &config_end_cmd);
3469 install_element (node, &config_help_cmd);
3470 install_element (node, &config_list_cmd);
3471
3472 install_element (node, &config_write_terminal_cmd);
3473 install_element (node, &config_write_file_cmd);
3474 install_element (node, &config_write_memory_cmd);
3475 install_element (node, &config_write_cmd);
3476 install_element (node, &show_running_config_cmd);
3477}
3478
3479/* Initialize command interface. Install basic nodes and commands. */
3480void
3481cmd_init (int terminal)
3482{
3483 /* Allocate initial top vector of commands. */
3484 cmdvec = vector_init (VECTOR_MIN_SIZE);
3485
3486 /* Default host value settings. */
3487 host.name = NULL;
3488 host.password = NULL;
3489 host.enable = NULL;
3490 host.logfile = NULL;
3491 host.config = NULL;
3492 host.lines = -1;
3493 host.motd = default_motd;
paul3b0c5d92005-03-08 10:43:43 +00003494 host.motdfile = NULL;
paul718e3742002-12-13 20:15:29 +00003495
3496 /* Install top nodes. */
3497 install_node (&view_node, NULL);
3498 install_node (&enable_node, NULL);
3499 install_node (&auth_node, NULL);
3500 install_node (&auth_enable_node, NULL);
3501 install_node (&config_node, config_write_host);
3502
3503 /* Each node's basic commands. */
3504 install_element (VIEW_NODE, &show_version_cmd);
3505 if (terminal)
3506 {
3507 install_element (VIEW_NODE, &config_list_cmd);
3508 install_element (VIEW_NODE, &config_exit_cmd);
3509 install_element (VIEW_NODE, &config_quit_cmd);
3510 install_element (VIEW_NODE, &config_help_cmd);
3511 install_element (VIEW_NODE, &config_enable_cmd);
3512 install_element (VIEW_NODE, &config_terminal_length_cmd);
3513 install_element (VIEW_NODE, &config_terminal_no_length_cmd);
ajs274a4a42004-12-07 15:39:31 +00003514 install_element (VIEW_NODE, &show_logging_cmd);
ajs2885f722004-12-17 23:16:33 +00003515 install_element (VIEW_NODE, &echo_cmd);
paul718e3742002-12-13 20:15:29 +00003516 }
3517
3518 if (terminal)
3519 {
3520 install_default (ENABLE_NODE);
3521 install_element (ENABLE_NODE, &config_disable_cmd);
3522 install_element (ENABLE_NODE, &config_terminal_cmd);
3523 install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
3524 }
3525 install_element (ENABLE_NODE, &show_startup_config_cmd);
3526 install_element (ENABLE_NODE, &show_version_cmd);
paul718e3742002-12-13 20:15:29 +00003527
3528 if (terminal)
paul718e3742002-12-13 20:15:29 +00003529 {
hassoe7168df2004-10-03 20:11:32 +00003530 install_element (ENABLE_NODE, &config_terminal_length_cmd);
3531 install_element (ENABLE_NODE, &config_terminal_no_length_cmd);
ajs274a4a42004-12-07 15:39:31 +00003532 install_element (ENABLE_NODE, &show_logging_cmd);
ajs2885f722004-12-17 23:16:33 +00003533 install_element (ENABLE_NODE, &echo_cmd);
ajs274a4a42004-12-07 15:39:31 +00003534 install_element (ENABLE_NODE, &config_logmsg_cmd);
hassoe7168df2004-10-03 20:11:32 +00003535
3536 install_default (CONFIG_NODE);
hassoea8e9d92004-10-07 21:32:14 +00003537 }
3538
3539 install_element (CONFIG_NODE, &hostname_cmd);
3540 install_element (CONFIG_NODE, &no_hostname_cmd);
hassoe7168df2004-10-03 20:11:32 +00003541
hassoea8e9d92004-10-07 21:32:14 +00003542 if (terminal)
3543 {
hassoe7168df2004-10-03 20:11:32 +00003544 install_element (CONFIG_NODE, &password_cmd);
3545 install_element (CONFIG_NODE, &password_text_cmd);
3546 install_element (CONFIG_NODE, &enable_password_cmd);
3547 install_element (CONFIG_NODE, &enable_password_text_cmd);
3548 install_element (CONFIG_NODE, &no_enable_password_cmd);
3549
paul718e3742002-12-13 20:15:29 +00003550 install_element (CONFIG_NODE, &config_log_stdout_cmd);
ajs274a4a42004-12-07 15:39:31 +00003551 install_element (CONFIG_NODE, &config_log_stdout_level_cmd);
paul718e3742002-12-13 20:15:29 +00003552 install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
ajs274a4a42004-12-07 15:39:31 +00003553 install_element (CONFIG_NODE, &config_log_monitor_cmd);
3554 install_element (CONFIG_NODE, &config_log_monitor_level_cmd);
3555 install_element (CONFIG_NODE, &no_config_log_monitor_cmd);
paul718e3742002-12-13 20:15:29 +00003556 install_element (CONFIG_NODE, &config_log_file_cmd);
ajs274a4a42004-12-07 15:39:31 +00003557 install_element (CONFIG_NODE, &config_log_file_level_cmd);
paul718e3742002-12-13 20:15:29 +00003558 install_element (CONFIG_NODE, &no_config_log_file_cmd);
ajs274a4a42004-12-07 15:39:31 +00003559 install_element (CONFIG_NODE, &no_config_log_file_level_cmd);
paul718e3742002-12-13 20:15:29 +00003560 install_element (CONFIG_NODE, &config_log_syslog_cmd);
ajs274a4a42004-12-07 15:39:31 +00003561 install_element (CONFIG_NODE, &config_log_syslog_level_cmd);
paul12ab19f2003-07-26 06:14:55 +00003562 install_element (CONFIG_NODE, &config_log_syslog_facility_cmd);
paul718e3742002-12-13 20:15:29 +00003563 install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
paul12ab19f2003-07-26 06:14:55 +00003564 install_element (CONFIG_NODE, &no_config_log_syslog_facility_cmd);
ajs274a4a42004-12-07 15:39:31 +00003565 install_element (CONFIG_NODE, &config_log_facility_cmd);
3566 install_element (CONFIG_NODE, &no_config_log_facility_cmd);
paul718e3742002-12-13 20:15:29 +00003567 install_element (CONFIG_NODE, &config_log_trap_cmd);
3568 install_element (CONFIG_NODE, &no_config_log_trap_cmd);
3569 install_element (CONFIG_NODE, &config_log_record_priority_cmd);
3570 install_element (CONFIG_NODE, &no_config_log_record_priority_cmd);
3571 install_element (CONFIG_NODE, &service_password_encrypt_cmd);
3572 install_element (CONFIG_NODE, &no_service_password_encrypt_cmd);
3573 install_element (CONFIG_NODE, &banner_motd_default_cmd);
paul3b0c5d92005-03-08 10:43:43 +00003574 install_element (CONFIG_NODE, &banner_motd_file_cmd);
paul718e3742002-12-13 20:15:29 +00003575 install_element (CONFIG_NODE, &no_banner_motd_cmd);
3576 install_element (CONFIG_NODE, &service_terminal_length_cmd);
3577 install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
paul718e3742002-12-13 20:15:29 +00003578
paul354d1192005-04-25 16:26:42 +00003579 install_element (VIEW_NODE, &show_thread_cpu_cmd);
3580 install_element (ENABLE_NODE, &show_thread_cpu_cmd);
3581 install_element (VIEW_NODE, &show_work_queues_cmd);
3582 install_element (ENABLE_NODE, &show_work_queues_cmd);
paul9ab68122003-01-18 01:16:20 +00003583 }
paul718e3742002-12-13 20:15:29 +00003584 srand(time(NULL));
3585}