blob: 316971e40e995ef175b55a7fa4fe05fc2f1fdcb1 [file] [log] [blame]
ajs274a4a42004-12-07 15:39:31 +00001/*
Paul Jakmae5cd7062006-06-15 12:25:55 +00002 $Id$
paul9e92eea2005-03-09 13:39:26 +00003
ajs274a4a42004-12-07 15:39:31 +00004 Command interpreter routine for virtual terminal [aka TeletYpe]
paul718e3742002-12-13 20:15:29 +00005 Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
6
7This file is part of GNU Zebra.
8
9GNU Zebra is free software; you can redistribute it and/or modify
10it under the terms of the GNU General Public License as published
11by the Free Software Foundation; either version 2, or (at your
12option) any later version.
13
14GNU Zebra is distributed in the hope that it will be useful, but
15WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with GNU Zebra; see the file COPYING. If not, write to the
21Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22Boston, MA 02111-1307, USA. */
23
24#include <zebra.h>
25
paulb21b19c2003-06-15 01:28:29 +000026
paul718e3742002-12-13 20:15:29 +000027#include "memory.h"
28#include "log.h"
gdt5e4fa162004-03-16 14:38:36 +000029#include <lib/version.h>
paul9ab68122003-01-18 01:16:20 +000030#include "thread.h"
paulb21b19c2003-06-15 01:28:29 +000031#include "vector.h"
32#include "vty.h"
33#include "command.h"
paul354d1192005-04-25 16:26:42 +000034#include "workqueue.h"
paul718e3742002-12-13 20:15:29 +000035
36/* Command vector which includes some level of command lists. Normally
37 each daemon maintains each own cmdvec. */
pauleb820af2005-09-05 11:54:13 +000038vector cmdvec = NULL;
paul718e3742002-12-13 20:15:29 +000039
40/* Host information structure. */
41struct host host;
42
paul718e3742002-12-13 20:15:29 +000043/* Standard command node structures. */
44struct cmd_node auth_node =
45{
46 AUTH_NODE,
47 "Password: ",
48};
49
50struct cmd_node view_node =
51{
52 VIEW_NODE,
53 "%s> ",
54};
55
56struct cmd_node auth_enable_node =
57{
58 AUTH_ENABLE_NODE,
59 "Password: ",
60};
61
62struct cmd_node enable_node =
63{
64 ENABLE_NODE,
65 "%s# ",
66};
67
68struct cmd_node config_node =
69{
70 CONFIG_NODE,
71 "%s(config)# ",
72 1
73};
hasso6590f2c2004-10-19 20:40:08 +000074
75/* Default motd string. */
76const char *default_motd =
77"\r\n\
78Hello, this is " QUAGGA_PROGNAME " (version " QUAGGA_VERSION ").\r\n\
79" QUAGGA_COPYRIGHT "\r\n\
80\r\n";
81
ajs274a4a42004-12-07 15:39:31 +000082
83static struct facility_map {
84 int facility;
85 const char *name;
86 size_t match;
87} syslog_facilities[] =
88 {
89 { LOG_KERN, "kern", 1 },
90 { LOG_USER, "user", 2 },
91 { LOG_MAIL, "mail", 1 },
92 { LOG_DAEMON, "daemon", 1 },
93 { LOG_AUTH, "auth", 1 },
94 { LOG_SYSLOG, "syslog", 1 },
95 { LOG_LPR, "lpr", 2 },
96 { LOG_NEWS, "news", 1 },
97 { LOG_UUCP, "uucp", 2 },
98 { LOG_CRON, "cron", 1 },
99#ifdef LOG_FTP
100 { LOG_FTP, "ftp", 1 },
101#endif
102 { LOG_LOCAL0, "local0", 6 },
103 { LOG_LOCAL1, "local1", 6 },
104 { LOG_LOCAL2, "local2", 6 },
105 { LOG_LOCAL3, "local3", 6 },
106 { LOG_LOCAL4, "local4", 6 },
107 { LOG_LOCAL5, "local5", 6 },
108 { LOG_LOCAL6, "local6", 6 },
109 { LOG_LOCAL7, "local7", 6 },
110 { 0, NULL, 0 },
111 };
112
113static const char *
114facility_name(int facility)
115{
116 struct facility_map *fm;
117
118 for (fm = syslog_facilities; fm->name; fm++)
119 if (fm->facility == facility)
120 return fm->name;
121 return "";
122}
123
124static int
125facility_match(const char *str)
126{
127 struct facility_map *fm;
128
129 for (fm = syslog_facilities; fm->name; fm++)
130 if (!strncmp(str,fm->name,fm->match))
131 return fm->facility;
132 return -1;
133}
134
135static int
136level_match(const char *s)
137{
138 int level ;
139
140 for ( level = 0 ; zlog_priority [level] != NULL ; level ++ )
141 if (!strncmp (s, zlog_priority[level], 2))
142 return level;
143 return ZLOG_DISABLED;
144}
145
ajscb585b62005-01-14 17:09:38 +0000146/* This is called from main when a daemon is invoked with -v or --version. */
hasso6590f2c2004-10-19 20:40:08 +0000147void
148print_version (const char *progname)
149{
ajscb585b62005-01-14 17:09:38 +0000150 printf ("%s version %s\n", progname, QUAGGA_VERSION);
151 printf ("%s\n", QUAGGA_COPYRIGHT);
hasso6590f2c2004-10-19 20:40:08 +0000152}
153
paul718e3742002-12-13 20:15:29 +0000154
155/* Utility function to concatenate argv argument into a single string
156 with inserting ' ' character between each argument. */
157char *
paul42d49862004-10-13 05:22:18 +0000158argv_concat (const char **argv, int argc, int shift)
paul718e3742002-12-13 20:15:29 +0000159{
160 int i;
ajsf6834d42005-01-28 20:28:35 +0000161 size_t len;
paul718e3742002-12-13 20:15:29 +0000162 char *str;
ajsf6834d42005-01-28 20:28:35 +0000163 char *p;
paul718e3742002-12-13 20:15:29 +0000164
ajsf6834d42005-01-28 20:28:35 +0000165 len = 0;
166 for (i = shift; i < argc; i++)
167 len += strlen(argv[i])+1;
168 if (!len)
169 return NULL;
170 p = str = XMALLOC(MTYPE_TMP, len);
paul718e3742002-12-13 20:15:29 +0000171 for (i = shift; i < argc; i++)
172 {
ajsf6834d42005-01-28 20:28:35 +0000173 size_t arglen;
174 memcpy(p, argv[i], (arglen = strlen(argv[i])));
175 p += arglen;
176 *p++ = ' ';
paul718e3742002-12-13 20:15:29 +0000177 }
ajsf6834d42005-01-28 20:28:35 +0000178 *(p-1) = '\0';
paul718e3742002-12-13 20:15:29 +0000179 return str;
180}
181
182/* Install top node of command vector. */
183void
184install_node (struct cmd_node *node,
185 int (*func) (struct vty *))
186{
187 vector_set_index (cmdvec, node->node, node);
188 node->func = func;
189 node->cmd_vector = vector_init (VECTOR_MIN_SIZE);
190}
191
192/* Compare two command's string. Used in sort_node (). */
ajs274a4a42004-12-07 15:39:31 +0000193static int
paul718e3742002-12-13 20:15:29 +0000194cmp_node (const void *p, const void *q)
195{
paul8cc41982005-05-06 21:25:49 +0000196 const struct cmd_element *a = *(struct cmd_element **)p;
197 const struct cmd_element *b = *(struct cmd_element **)q;
paul718e3742002-12-13 20:15:29 +0000198
199 return strcmp (a->string, b->string);
200}
201
ajs274a4a42004-12-07 15:39:31 +0000202static int
paul718e3742002-12-13 20:15:29 +0000203cmp_desc (const void *p, const void *q)
204{
paul8cc41982005-05-06 21:25:49 +0000205 const struct desc *a = *(struct desc **)p;
206 const struct desc *b = *(struct desc **)q;
paul718e3742002-12-13 20:15:29 +0000207
208 return strcmp (a->cmd, b->cmd);
209}
210
211/* Sort each node's command element according to command string. */
212void
213sort_node ()
214{
hasso8c328f12004-10-05 21:01:23 +0000215 unsigned int i, j;
paul718e3742002-12-13 20:15:29 +0000216 struct cmd_node *cnode;
217 vector descvec;
218 struct cmd_element *cmd_element;
219
paul55468c82005-03-14 20:19:01 +0000220 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +0000221 if ((cnode = vector_slot (cmdvec, i)) != NULL)
222 {
223 vector cmd_vector = cnode->cmd_vector;
paul55468c82005-03-14 20:19:01 +0000224 qsort (cmd_vector->index, vector_active (cmd_vector),
paulb8961472005-03-14 17:35:52 +0000225 sizeof (void *), cmp_node);
paul718e3742002-12-13 20:15:29 +0000226
paul55468c82005-03-14 20:19:01 +0000227 for (j = 0; j < vector_active (cmd_vector); j++)
paulb8961472005-03-14 17:35:52 +0000228 if ((cmd_element = vector_slot (cmd_vector, j)) != NULL
paul55468c82005-03-14 20:19:01 +0000229 && vector_active (cmd_element->strvec))
paul718e3742002-12-13 20:15:29 +0000230 {
231 descvec = vector_slot (cmd_element->strvec,
paul55468c82005-03-14 20:19:01 +0000232 vector_active (cmd_element->strvec) - 1);
233 qsort (descvec->index, vector_active (descvec),
paulb8961472005-03-14 17:35:52 +0000234 sizeof (void *), cmp_desc);
paul718e3742002-12-13 20:15:29 +0000235 }
236 }
237}
238
239/* Breaking up string into each command piece. I assume given
240 character is separated by a space character. Return value is a
241 vector which includes char ** data element. */
242vector
hassoea8e9d92004-10-07 21:32:14 +0000243cmd_make_strvec (const char *string)
paul718e3742002-12-13 20:15:29 +0000244{
hassoea8e9d92004-10-07 21:32:14 +0000245 const char *cp, *start;
246 char *token;
paul718e3742002-12-13 20:15:29 +0000247 int strlen;
248 vector strvec;
249
250 if (string == NULL)
251 return NULL;
252
253 cp = string;
254
255 /* Skip white spaces. */
256 while (isspace ((int) *cp) && *cp != '\0')
257 cp++;
258
259 /* Return if there is only white spaces */
260 if (*cp == '\0')
261 return NULL;
262
263 if (*cp == '!' || *cp == '#')
264 return NULL;
265
266 /* Prepare return vector. */
267 strvec = vector_init (VECTOR_MIN_SIZE);
268
269 /* Copy each command piece and set into vector. */
270 while (1)
271 {
272 start = cp;
273 while (!(isspace ((int) *cp) || *cp == '\r' || *cp == '\n') &&
274 *cp != '\0')
275 cp++;
276 strlen = cp - start;
277 token = XMALLOC (MTYPE_STRVEC, strlen + 1);
278 memcpy (token, start, strlen);
279 *(token + strlen) = '\0';
280 vector_set (strvec, token);
281
282 while ((isspace ((int) *cp) || *cp == '\n' || *cp == '\r') &&
283 *cp != '\0')
284 cp++;
285
286 if (*cp == '\0')
287 return strvec;
288 }
289}
290
291/* Free allocated string vector. */
292void
293cmd_free_strvec (vector v)
294{
hasso8c328f12004-10-05 21:01:23 +0000295 unsigned int i;
paul718e3742002-12-13 20:15:29 +0000296 char *cp;
297
298 if (!v)
299 return;
300
paul55468c82005-03-14 20:19:01 +0000301 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +0000302 if ((cp = vector_slot (v, i)) != NULL)
303 XFREE (MTYPE_STRVEC, cp);
304
305 vector_free (v);
306}
307
308/* Fetch next description. Used in cmd_make_descvec(). */
ajs274a4a42004-12-07 15:39:31 +0000309static char *
hasso6ad96ea2004-10-07 19:33:46 +0000310cmd_desc_str (const char **string)
paul718e3742002-12-13 20:15:29 +0000311{
hasso6ad96ea2004-10-07 19:33:46 +0000312 const char *cp, *start;
313 char *token;
paul718e3742002-12-13 20:15:29 +0000314 int strlen;
315
316 cp = *string;
317
318 if (cp == NULL)
319 return NULL;
320
321 /* Skip white spaces. */
322 while (isspace ((int) *cp) && *cp != '\0')
323 cp++;
324
325 /* Return if there is only white spaces */
326 if (*cp == '\0')
327 return NULL;
328
329 start = cp;
330
331 while (!(*cp == '\r' || *cp == '\n') && *cp != '\0')
332 cp++;
333
334 strlen = cp - start;
335 token = XMALLOC (MTYPE_STRVEC, strlen + 1);
336 memcpy (token, start, strlen);
337 *(token + strlen) = '\0';
338
339 *string = cp;
340
341 return token;
342}
343
344/* New string vector. */
ajs274a4a42004-12-07 15:39:31 +0000345static vector
hasso8c328f12004-10-05 21:01:23 +0000346cmd_make_descvec (const char *string, const char *descstr)
paul718e3742002-12-13 20:15:29 +0000347{
348 int multiple = 0;
hasso8c328f12004-10-05 21:01:23 +0000349 const char *sp;
paul718e3742002-12-13 20:15:29 +0000350 char *token;
351 int len;
hasso8c328f12004-10-05 21:01:23 +0000352 const char *cp;
353 const char *dp;
paul718e3742002-12-13 20:15:29 +0000354 vector allvec;
355 vector strvec = NULL;
356 struct desc *desc;
357
358 cp = string;
359 dp = descstr;
360
361 if (cp == NULL)
362 return NULL;
363
364 allvec = vector_init (VECTOR_MIN_SIZE);
365
366 while (1)
367 {
368 while (isspace ((int) *cp) && *cp != '\0')
369 cp++;
370
371 if (*cp == '(')
372 {
373 multiple = 1;
374 cp++;
375 }
376 if (*cp == ')')
377 {
378 multiple = 0;
379 cp++;
380 }
381 if (*cp == '|')
382 {
383 if (! multiple)
384 {
385 fprintf (stderr, "Command parse error!: %s\n", string);
386 exit (1);
387 }
388 cp++;
389 }
390
391 while (isspace ((int) *cp) && *cp != '\0')
392 cp++;
393
394 if (*cp == '(')
395 {
396 multiple = 1;
397 cp++;
398 }
399
400 if (*cp == '\0')
401 return allvec;
402
403 sp = cp;
404
405 while (! (isspace ((int) *cp) || *cp == '\r' || *cp == '\n' || *cp == ')' || *cp == '|') && *cp != '\0')
406 cp++;
407
408 len = cp - sp;
409
410 token = XMALLOC (MTYPE_STRVEC, len + 1);
411 memcpy (token, sp, len);
412 *(token + len) = '\0';
413
414 desc = XCALLOC (MTYPE_DESC, sizeof (struct desc));
415 desc->cmd = token;
416 desc->str = cmd_desc_str (&dp);
417
418 if (multiple)
419 {
420 if (multiple == 1)
421 {
422 strvec = vector_init (VECTOR_MIN_SIZE);
423 vector_set (allvec, strvec);
424 }
425 multiple++;
426 }
427 else
428 {
429 strvec = vector_init (VECTOR_MIN_SIZE);
430 vector_set (allvec, strvec);
431 }
432 vector_set (strvec, desc);
433 }
434}
435
436/* Count mandantory string vector size. This is to determine inputed
437 command has enough command length. */
ajs274a4a42004-12-07 15:39:31 +0000438static int
paul718e3742002-12-13 20:15:29 +0000439cmd_cmdsize (vector strvec)
440{
hasso8c328f12004-10-05 21:01:23 +0000441 unsigned int i;
paul718e3742002-12-13 20:15:29 +0000442 int size = 0;
443 vector descvec;
paulb8961472005-03-14 17:35:52 +0000444 struct desc *desc;
paul718e3742002-12-13 20:15:29 +0000445
paul55468c82005-03-14 20:19:01 +0000446 for (i = 0; i < vector_active (strvec); i++)
paulb8961472005-03-14 17:35:52 +0000447 if ((descvec = vector_slot (strvec, i)) != NULL)
paul718e3742002-12-13 20:15:29 +0000448 {
paul55468c82005-03-14 20:19:01 +0000449 if ((vector_active (descvec)) == 1
paulb8961472005-03-14 17:35:52 +0000450 && (desc = vector_slot (descvec, 0)) != NULL)
paul718e3742002-12-13 20:15:29 +0000451 {
hasso8c328f12004-10-05 21:01:23 +0000452 if (desc->cmd == NULL || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +0000453 return size;
454 else
455 size++;
456 }
457 else
458 size++;
459 }
460 return size;
461}
462
463/* Return prompt character of specified node. */
hasso8c328f12004-10-05 21:01:23 +0000464const char *
paul718e3742002-12-13 20:15:29 +0000465cmd_prompt (enum node_type node)
466{
467 struct cmd_node *cnode;
468
469 cnode = vector_slot (cmdvec, node);
470 return cnode->prompt;
471}
472
473/* Install a command into a node. */
474void
475install_element (enum node_type ntype, struct cmd_element *cmd)
476{
477 struct cmd_node *cnode;
pauleb820af2005-09-05 11:54:13 +0000478
479 /* cmd_init hasn't been called */
480 if (!cmdvec)
481 return;
482
paul718e3742002-12-13 20:15:29 +0000483 cnode = vector_slot (cmdvec, ntype);
484
485 if (cnode == NULL)
486 {
487 fprintf (stderr, "Command node %d doesn't exist, please check it\n",
488 ntype);
489 exit (1);
490 }
491
492 vector_set (cnode->cmd_vector, cmd);
493
494 cmd->strvec = cmd_make_descvec (cmd->string, cmd->doc);
495 cmd->cmdsize = cmd_cmdsize (cmd->strvec);
496}
497
498static unsigned char itoa64[] =
499"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
500
ajs274a4a42004-12-07 15:39:31 +0000501static void
paul718e3742002-12-13 20:15:29 +0000502to64(char *s, long v, int n)
503{
504 while (--n >= 0)
505 {
506 *s++ = itoa64[v&0x3f];
507 v >>= 6;
508 }
509}
510
ajs274a4a42004-12-07 15:39:31 +0000511static char *
512zencrypt (const char *passwd)
paul718e3742002-12-13 20:15:29 +0000513{
514 char salt[6];
515 struct timeval tv;
516 char *crypt (const char *, const char *);
517
518 gettimeofday(&tv,0);
519
520 to64(&salt[0], random(), 3);
521 to64(&salt[3], tv.tv_usec, 3);
522 salt[5] = '\0';
523
524 return crypt (passwd, salt);
525}
526
527/* This function write configuration of this host. */
ajs274a4a42004-12-07 15:39:31 +0000528static int
paul718e3742002-12-13 20:15:29 +0000529config_write_host (struct vty *vty)
530{
531 if (host.name)
532 vty_out (vty, "hostname %s%s", host.name, VTY_NEWLINE);
533
534 if (host.encrypt)
535 {
536 if (host.password_encrypt)
537 vty_out (vty, "password 8 %s%s", host.password_encrypt, VTY_NEWLINE);
538 if (host.enable_encrypt)
539 vty_out (vty, "enable password 8 %s%s", host.enable_encrypt, VTY_NEWLINE);
540 }
541 else
542 {
543 if (host.password)
544 vty_out (vty, "password %s%s", host.password, VTY_NEWLINE);
545 if (host.enable)
546 vty_out (vty, "enable password %s%s", host.enable, VTY_NEWLINE);
547 }
548
ajs274a4a42004-12-07 15:39:31 +0000549 if (zlog_default->default_lvl != LOG_DEBUG)
ajs82146b82004-12-07 17:15:55 +0000550 {
551 vty_out (vty, "! N.B. The 'log trap' command is deprecated.%s",
552 VTY_NEWLINE);
553 vty_out (vty, "log trap %s%s",
554 zlog_priority[zlog_default->default_lvl], VTY_NEWLINE);
555 }
paul718e3742002-12-13 20:15:29 +0000556
ajs274a4a42004-12-07 15:39:31 +0000557 if (host.logfile && (zlog_default->maxlvl[ZLOG_DEST_FILE] != ZLOG_DISABLED))
paul12ab19f2003-07-26 06:14:55 +0000558 {
ajs274a4a42004-12-07 15:39:31 +0000559 vty_out (vty, "log file %s", host.logfile);
560 if (zlog_default->maxlvl[ZLOG_DEST_FILE] != zlog_default->default_lvl)
561 vty_out (vty, " %s",
562 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_FILE]]);
paul12ab19f2003-07-26 06:14:55 +0000563 vty_out (vty, "%s", VTY_NEWLINE);
564 }
ajs274a4a42004-12-07 15:39:31 +0000565
566 if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != ZLOG_DISABLED)
567 {
568 vty_out (vty, "log stdout");
569 if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != zlog_default->default_lvl)
570 vty_out (vty, " %s",
571 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_STDOUT]]);
572 vty_out (vty, "%s", VTY_NEWLINE);
573 }
574
575 if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
576 vty_out(vty,"no log monitor%s",VTY_NEWLINE);
577 else if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] != zlog_default->default_lvl)
578 vty_out(vty,"log monitor %s%s",
579 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_MONITOR]],VTY_NEWLINE);
580
581 if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED)
582 {
583 vty_out (vty, "log syslog");
584 if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != zlog_default->default_lvl)
585 vty_out (vty, " %s",
586 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_SYSLOG]]);
587 vty_out (vty, "%s", VTY_NEWLINE);
588 }
589
590 if (zlog_default->facility != LOG_DAEMON)
591 vty_out (vty, "log facility %s%s",
592 facility_name(zlog_default->facility), VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +0000593
594 if (zlog_default->record_priority == 1)
595 vty_out (vty, "log record-priority%s", VTY_NEWLINE);
596
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);
Paul Jakmae5cd7062006-06-15 12:25:55 +00001632 vector_free (matchvec);
paul909a2152005-03-14 17:41:45 +00001633 *status = CMD_ERR_AMBIGUOUS;
1634 return NULL;
1635 }
1636 else if (ret == 2)
1637 {
1638 vector_free (cmd_vector);
Paul Jakmae5cd7062006-06-15 12:25:55 +00001639 vector_free (matchvec);
paul909a2152005-03-14 17:41:45 +00001640 *status = CMD_ERR_NO_MATCH;
1641 return NULL;
1642 }
1643 }
paul718e3742002-12-13 20:15:29 +00001644
1645 /* Prepare match vector */
1646 /* matchvec = vector_init (INIT_MATCHVEC_SIZE); */
1647
paul54aba542003-08-21 20:28:24 +00001648 /* Make sure that cmd_vector is filtered based on current word */
1649 command = vector_slot (vline, index);
1650 if (command)
1651 match = cmd_filter_by_completion (command, cmd_vector, index);
1652
paul718e3742002-12-13 20:15:29 +00001653 /* Make description vector. */
paul55468c82005-03-14 20:19:01 +00001654 for (i = 0; i < vector_active (cmd_vector); i++)
paul718e3742002-12-13 20:15:29 +00001655 if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
1656 {
hasso8c328f12004-10-05 21:01:23 +00001657 const char *string = NULL;
paul718e3742002-12-13 20:15:29 +00001658 vector strvec = cmd_element->strvec;
1659
paul55468c82005-03-14 20:19:01 +00001660 /* if command is NULL, index may be equal to vector_active */
1661 if (command && index >= vector_active (strvec))
paul718e3742002-12-13 20:15:29 +00001662 vector_slot (cmd_vector, i) = NULL;
1663 else
1664 {
paul54aba542003-08-21 20:28:24 +00001665 /* Check if command is completed. */
paul55468c82005-03-14 20:19:01 +00001666 if (command == NULL && index == vector_active (strvec))
paul718e3742002-12-13 20:15:29 +00001667 {
1668 string = "<cr>";
paul909a2152005-03-14 17:41:45 +00001669 if (!desc_unique_string (matchvec, string))
paul718e3742002-12-13 20:15:29 +00001670 vector_set (matchvec, &desc_cr);
1671 }
1672 else
1673 {
hasso8c328f12004-10-05 21:01:23 +00001674 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001675 vector descvec = vector_slot (strvec, index);
1676 struct desc *desc;
1677
paul55468c82005-03-14 20:19:01 +00001678 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001679 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001680 {
1681 string = cmd_entry_function_desc (command, desc->cmd);
1682 if (string)
1683 {
1684 /* Uniqueness check */
1685 if (!desc_unique_string (matchvec, string))
1686 vector_set (matchvec, desc);
1687 }
1688 }
paul718e3742002-12-13 20:15:29 +00001689 }
1690 }
1691 }
1692 vector_free (cmd_vector);
1693
1694 if (vector_slot (matchvec, 0) == NULL)
1695 {
1696 vector_free (matchvec);
paul909a2152005-03-14 17:41:45 +00001697 *status = CMD_ERR_NO_MATCH;
Paul Jakma5fc60512006-05-12 23:24:09 +00001698 return NULL;
paul718e3742002-12-13 20:15:29 +00001699 }
paul718e3742002-12-13 20:15:29 +00001700
Paul Jakma5fc60512006-05-12 23:24:09 +00001701 *status = CMD_SUCCESS;
paul718e3742002-12-13 20:15:29 +00001702 return matchvec;
1703}
1704
paulb92938a2002-12-13 21:20:42 +00001705vector
1706cmd_describe_command (vector vline, struct vty *vty, int *status)
1707{
1708 vector ret;
1709
1710 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1711 {
1712 enum node_type onode;
1713 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00001714 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00001715
1716 onode = vty->node;
1717 vty->node = ENABLE_NODE;
1718 /* We can try it on enable node, cos' the vty is authenticated */
1719
1720 shifted_vline = vector_init (vector_count(vline));
1721 /* use memcpy? */
paul55468c82005-03-14 20:19:01 +00001722 for (index = 1; index < vector_active (vline); index++)
paulb92938a2002-12-13 21:20:42 +00001723 {
1724 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1725 }
1726
1727 ret = cmd_describe_command_real (shifted_vline, vty, status);
1728
1729 vector_free(shifted_vline);
1730 vty->node = onode;
1731 return ret;
1732 }
1733
1734
1735 return cmd_describe_command_real (vline, vty, status);
1736}
1737
1738
paul718e3742002-12-13 20:15:29 +00001739/* Check LCD of matched command. */
ajs274a4a42004-12-07 15:39:31 +00001740static int
paul718e3742002-12-13 20:15:29 +00001741cmd_lcd (char **matched)
1742{
1743 int i;
1744 int j;
1745 int lcd = -1;
1746 char *s1, *s2;
1747 char c1, c2;
1748
1749 if (matched[0] == NULL || matched[1] == NULL)
1750 return 0;
1751
1752 for (i = 1; matched[i] != NULL; i++)
1753 {
1754 s1 = matched[i - 1];
1755 s2 = matched[i];
1756
1757 for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
1758 if (c1 != c2)
1759 break;
1760
1761 if (lcd < 0)
1762 lcd = j;
1763 else
1764 {
1765 if (lcd > j)
1766 lcd = j;
1767 }
1768 }
1769 return lcd;
1770}
1771
1772/* Command line completion support. */
ajs274a4a42004-12-07 15:39:31 +00001773static char **
paulb92938a2002-12-13 21:20:42 +00001774cmd_complete_command_real (vector vline, struct vty *vty, int *status)
paul718e3742002-12-13 20:15:29 +00001775{
paulb8961472005-03-14 17:35:52 +00001776 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001777 vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1778#define INIT_MATCHVEC_SIZE 10
1779 vector matchvec;
1780 struct cmd_element *cmd_element;
paulb8961472005-03-14 17:35:52 +00001781 unsigned int index;
paul718e3742002-12-13 20:15:29 +00001782 char **match_str;
1783 struct desc *desc;
1784 vector descvec;
1785 char *command;
1786 int lcd;
1787
paul55468c82005-03-14 20:19:01 +00001788 if (vector_active (vline) == 0)
paulb8961472005-03-14 17:35:52 +00001789 {
Paul Jakmad2519962006-05-12 23:19:37 +00001790 vector_free (cmd_vector);
paulb8961472005-03-14 17:35:52 +00001791 *status = CMD_ERR_NO_MATCH;
1792 return NULL;
1793 }
1794 else
paul55468c82005-03-14 20:19:01 +00001795 index = vector_active (vline) - 1;
paulb8961472005-03-14 17:35:52 +00001796
paul718e3742002-12-13 20:15:29 +00001797 /* First, filter by preceeding command string */
1798 for (i = 0; i < index; i++)
paulb8961472005-03-14 17:35:52 +00001799 if ((command = vector_slot (vline, i)))
paul909a2152005-03-14 17:41:45 +00001800 {
1801 enum match_type match;
1802 int ret;
paul718e3742002-12-13 20:15:29 +00001803
paul909a2152005-03-14 17:41:45 +00001804 /* First try completion match, if there is exactly match return 1 */
1805 match = cmd_filter_by_completion (command, cmd_vector, i);
paul718e3742002-12-13 20:15:29 +00001806
paul909a2152005-03-14 17:41:45 +00001807 /* If there is exact match then filter ambiguous match else check
1808 ambiguousness. */
1809 if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
1810 {
1811 vector_free (cmd_vector);
1812 *status = CMD_ERR_AMBIGUOUS;
1813 return NULL;
1814 }
1815 /*
1816 else if (ret == 2)
1817 {
1818 vector_free (cmd_vector);
1819 *status = CMD_ERR_NO_MATCH;
1820 return NULL;
1821 }
1822 */
1823 }
1824
paul718e3742002-12-13 20:15:29 +00001825 /* Prepare match vector. */
1826 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1827
1828 /* Now we got into completion */
paul55468c82005-03-14 20:19:01 +00001829 for (i = 0; i < vector_active (cmd_vector); i++)
paulb8961472005-03-14 17:35:52 +00001830 if ((cmd_element = vector_slot (cmd_vector, i)))
paul718e3742002-12-13 20:15:29 +00001831 {
hasso8c328f12004-10-05 21:01:23 +00001832 const char *string;
paul718e3742002-12-13 20:15:29 +00001833 vector strvec = cmd_element->strvec;
paul909a2152005-03-14 17:41:45 +00001834
paul718e3742002-12-13 20:15:29 +00001835 /* Check field length */
paul55468c82005-03-14 20:19:01 +00001836 if (index >= vector_active (strvec))
paul718e3742002-12-13 20:15:29 +00001837 vector_slot (cmd_vector, i) = NULL;
paul909a2152005-03-14 17:41:45 +00001838 else
paul718e3742002-12-13 20:15:29 +00001839 {
hasso8c328f12004-10-05 21:01:23 +00001840 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001841
1842 descvec = vector_slot (strvec, index);
paul55468c82005-03-14 20:19:01 +00001843 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001844 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001845 {
paulb8961472005-03-14 17:35:52 +00001846 if ((string =
1847 cmd_entry_function (vector_slot (vline, index),
paul909a2152005-03-14 17:41:45 +00001848 desc->cmd)))
1849 if (cmd_unique_string (matchvec, string))
1850 vector_set (matchvec, XSTRDUP (MTYPE_TMP, string));
1851 }
paul718e3742002-12-13 20:15:29 +00001852 }
1853 }
1854
1855 /* We don't need cmd_vector any more. */
1856 vector_free (cmd_vector);
1857
1858 /* No matched command */
1859 if (vector_slot (matchvec, 0) == NULL)
1860 {
1861 vector_free (matchvec);
1862
1863 /* In case of 'command \t' pattern. Do you need '?' command at
1864 the end of the line. */
1865 if (vector_slot (vline, index) == '\0')
1866 *status = CMD_ERR_NOTHING_TODO;
1867 else
1868 *status = CMD_ERR_NO_MATCH;
1869 return NULL;
1870 }
1871
1872 /* Only one matched */
1873 if (vector_slot (matchvec, 1) == NULL)
1874 {
1875 match_str = (char **) matchvec->index;
1876 vector_only_wrapper_free (matchvec);
1877 *status = CMD_COMPLETE_FULL_MATCH;
1878 return match_str;
1879 }
1880 /* Make it sure last element is NULL. */
1881 vector_set (matchvec, NULL);
1882
1883 /* Check LCD of matched strings. */
1884 if (vector_slot (vline, index) != NULL)
1885 {
1886 lcd = cmd_lcd ((char **) matchvec->index);
1887
1888 if (lcd)
1889 {
1890 int len = strlen (vector_slot (vline, index));
paul909a2152005-03-14 17:41:45 +00001891
paul718e3742002-12-13 20:15:29 +00001892 if (len < lcd)
1893 {
1894 char *lcdstr;
paul909a2152005-03-14 17:41:45 +00001895
paul05865c92005-10-26 05:49:54 +00001896 lcdstr = XMALLOC (MTYPE_STRVEC, lcd + 1);
paul718e3742002-12-13 20:15:29 +00001897 memcpy (lcdstr, matchvec->index[0], lcd);
1898 lcdstr[lcd] = '\0';
1899
1900 /* match_str = (char **) &lcdstr; */
1901
1902 /* Free matchvec. */
paul55468c82005-03-14 20:19:01 +00001903 for (i = 0; i < vector_active (matchvec); i++)
paul718e3742002-12-13 20:15:29 +00001904 {
1905 if (vector_slot (matchvec, i))
paul05865c92005-10-26 05:49:54 +00001906 XFREE (MTYPE_STRVEC, vector_slot (matchvec, i));
paul718e3742002-12-13 20:15:29 +00001907 }
1908 vector_free (matchvec);
1909
paul909a2152005-03-14 17:41:45 +00001910 /* Make new matchvec. */
paul718e3742002-12-13 20:15:29 +00001911 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1912 vector_set (matchvec, lcdstr);
1913 match_str = (char **) matchvec->index;
1914 vector_only_wrapper_free (matchvec);
1915
1916 *status = CMD_COMPLETE_MATCH;
1917 return match_str;
1918 }
1919 }
1920 }
1921
1922 match_str = (char **) matchvec->index;
1923 vector_only_wrapper_free (matchvec);
1924 *status = CMD_COMPLETE_LIST_MATCH;
1925 return match_str;
1926}
1927
paulb92938a2002-12-13 21:20:42 +00001928char **
paul9ab68122003-01-18 01:16:20 +00001929cmd_complete_command (vector vline, struct vty *vty, int *status)
paulb92938a2002-12-13 21:20:42 +00001930{
1931 char **ret;
1932
1933 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1934 {
1935 enum node_type onode;
1936 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00001937 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00001938
1939 onode = vty->node;
1940 vty->node = ENABLE_NODE;
1941 /* We can try it on enable node, cos' the vty is authenticated */
1942
1943 shifted_vline = vector_init (vector_count(vline));
1944 /* use memcpy? */
paul55468c82005-03-14 20:19:01 +00001945 for (index = 1; index < vector_active (vline); index++)
paulb92938a2002-12-13 21:20:42 +00001946 {
1947 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1948 }
1949
1950 ret = cmd_complete_command_real (shifted_vline, vty, status);
1951
1952 vector_free(shifted_vline);
1953 vty->node = onode;
1954 return ret;
1955 }
1956
1957
1958 return cmd_complete_command_real (vline, vty, status);
1959}
1960
1961/* return parent node */
1962/* MUST eventually converge on CONFIG_NODE */
hasso13bfca72005-01-23 21:42:25 +00001963enum node_type
ajs274a4a42004-12-07 15:39:31 +00001964node_parent ( enum node_type node )
paulb92938a2002-12-13 21:20:42 +00001965{
1966 enum node_type ret;
1967
paul9ab68122003-01-18 01:16:20 +00001968 assert (node > CONFIG_NODE);
1969
1970 switch (node)
1971 {
1972 case BGP_VPNV4_NODE:
1973 case BGP_IPV4_NODE:
1974 case BGP_IPV4M_NODE:
1975 case BGP_IPV6_NODE:
paul1e836592005-08-22 22:39:56 +00001976 case BGP_IPV6M_NODE:
paul9ab68122003-01-18 01:16:20 +00001977 ret = BGP_NODE;
1978 break;
1979 case KEYCHAIN_KEY_NODE:
1980 ret = KEYCHAIN_NODE;
1981 break;
1982 default:
1983 ret = CONFIG_NODE;
paulb92938a2002-12-13 21:20:42 +00001984 }
1985
1986 return ret;
1987}
1988
paul718e3742002-12-13 20:15:29 +00001989/* Execute command by argument vline vector. */
ajs274a4a42004-12-07 15:39:31 +00001990static int
paulb8961472005-03-14 17:35:52 +00001991cmd_execute_command_real (vector vline, struct vty *vty,
1992 struct cmd_element **cmd)
paul718e3742002-12-13 20:15:29 +00001993{
hasso8c328f12004-10-05 21:01:23 +00001994 unsigned int i;
1995 unsigned int index;
paul718e3742002-12-13 20:15:29 +00001996 vector cmd_vector;
1997 struct cmd_element *cmd_element;
1998 struct cmd_element *matched_element;
1999 unsigned int matched_count, incomplete_count;
2000 int argc;
paul9035efa2004-10-10 11:56:56 +00002001 const char *argv[CMD_ARGC_MAX];
paul718e3742002-12-13 20:15:29 +00002002 enum match_type match = 0;
2003 int varflag;
2004 char *command;
2005
2006 /* Make copy of command elements. */
2007 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2008
paul55468c82005-03-14 20:19:01 +00002009 for (index = 0; index < vector_active (vline); index++)
paulb8961472005-03-14 17:35:52 +00002010 if ((command = vector_slot (vline, index)))
paul909a2152005-03-14 17:41:45 +00002011 {
2012 int ret;
paul718e3742002-12-13 20:15:29 +00002013
paul909a2152005-03-14 17:41:45 +00002014 match = cmd_filter_by_completion (command, cmd_vector, index);
paul718e3742002-12-13 20:15:29 +00002015
paul909a2152005-03-14 17:41:45 +00002016 if (match == vararg_match)
2017 break;
2018
2019 ret = is_cmd_ambiguous (command, cmd_vector, index, match);
paul718e3742002-12-13 20:15:29 +00002020
paul909a2152005-03-14 17:41:45 +00002021 if (ret == 1)
2022 {
2023 vector_free (cmd_vector);
2024 return CMD_ERR_AMBIGUOUS;
2025 }
2026 else if (ret == 2)
2027 {
2028 vector_free (cmd_vector);
2029 return CMD_ERR_NO_MATCH;
2030 }
2031 }
paul718e3742002-12-13 20:15:29 +00002032
2033 /* Check matched count. */
2034 matched_element = NULL;
2035 matched_count = 0;
2036 incomplete_count = 0;
2037
paul55468c82005-03-14 20:19:01 +00002038 for (i = 0; i < vector_active (cmd_vector); i++)
paulb8961472005-03-14 17:35:52 +00002039 if ((cmd_element = vector_slot (cmd_vector, i)))
paul718e3742002-12-13 20:15:29 +00002040 {
paul718e3742002-12-13 20:15:29 +00002041 if (match == vararg_match || index >= cmd_element->cmdsize)
2042 {
2043 matched_element = cmd_element;
2044#if 0
2045 printf ("DEBUG: %s\n", cmd_element->string);
2046#endif
2047 matched_count++;
2048 }
2049 else
2050 {
2051 incomplete_count++;
2052 }
2053 }
paul909a2152005-03-14 17:41:45 +00002054
paul718e3742002-12-13 20:15:29 +00002055 /* Finish of using cmd_vector. */
2056 vector_free (cmd_vector);
2057
paul909a2152005-03-14 17:41:45 +00002058 /* To execute command, matched_count must be 1. */
2059 if (matched_count == 0)
paul718e3742002-12-13 20:15:29 +00002060 {
2061 if (incomplete_count)
2062 return CMD_ERR_INCOMPLETE;
2063 else
2064 return CMD_ERR_NO_MATCH;
2065 }
2066
paul909a2152005-03-14 17:41:45 +00002067 if (matched_count > 1)
paul718e3742002-12-13 20:15:29 +00002068 return CMD_ERR_AMBIGUOUS;
2069
2070 /* Argument treatment */
2071 varflag = 0;
2072 argc = 0;
2073
paul55468c82005-03-14 20:19:01 +00002074 for (i = 0; i < vector_active (vline); i++)
paul718e3742002-12-13 20:15:29 +00002075 {
2076 if (varflag)
2077 argv[argc++] = vector_slot (vline, i);
2078 else
paul909a2152005-03-14 17:41:45 +00002079 {
paul718e3742002-12-13 20:15:29 +00002080 vector descvec = vector_slot (matched_element->strvec, i);
2081
paul55468c82005-03-14 20:19:01 +00002082 if (vector_active (descvec) == 1)
paul718e3742002-12-13 20:15:29 +00002083 {
2084 struct desc *desc = vector_slot (descvec, 0);
paul718e3742002-12-13 20:15:29 +00002085
hasso8c328f12004-10-05 21:01:23 +00002086 if (CMD_VARARG (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002087 varflag = 1;
2088
hasso8c328f12004-10-05 21:01:23 +00002089 if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002090 argv[argc++] = vector_slot (vline, i);
2091 }
2092 else
2093 argv[argc++] = vector_slot (vline, i);
2094 }
2095
2096 if (argc >= CMD_ARGC_MAX)
2097 return CMD_ERR_EXEED_ARGC_MAX;
2098 }
2099
2100 /* For vtysh execution. */
2101 if (cmd)
2102 *cmd = matched_element;
2103
2104 if (matched_element->daemon)
2105 return CMD_SUCCESS_DAEMON;
2106
2107 /* Execute matched command. */
2108 return (*matched_element->func) (matched_element, vty, argc, argv);
2109}
2110
paulb92938a2002-12-13 21:20:42 +00002111int
hasso87d683b2005-01-16 23:31:54 +00002112cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,
2113 int vtysh) {
paul9ab68122003-01-18 01:16:20 +00002114 int ret, saved_ret, tried = 0;
2115 enum node_type onode, try_node;
2116
2117 onode = try_node = vty->node;
paulb92938a2002-12-13 21:20:42 +00002118
2119 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
2120 {
2121 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00002122 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00002123
2124 vty->node = ENABLE_NODE;
2125 /* We can try it on enable node, cos' the vty is authenticated */
2126
2127 shifted_vline = vector_init (vector_count(vline));
2128 /* use memcpy? */
paul55468c82005-03-14 20:19:01 +00002129 for (index = 1; index < vector_active (vline); index++)
paulb92938a2002-12-13 21:20:42 +00002130 {
2131 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
2132 }
2133
2134 ret = cmd_execute_command_real (shifted_vline, vty, cmd);
2135
2136 vector_free(shifted_vline);
2137 vty->node = onode;
2138 return ret;
2139 }
2140
2141
paul9ab68122003-01-18 01:16:20 +00002142 saved_ret = ret = cmd_execute_command_real (vline, vty, cmd);
paulb92938a2002-12-13 21:20:42 +00002143
hasso87d683b2005-01-16 23:31:54 +00002144 if (vtysh)
2145 return saved_ret;
2146
paulb92938a2002-12-13 21:20:42 +00002147 /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
paul9ab68122003-01-18 01:16:20 +00002148 while ( ret != CMD_SUCCESS && ret != CMD_WARNING
paulb92938a2002-12-13 21:20:42 +00002149 && vty->node > CONFIG_NODE )
2150 {
paul9ab68122003-01-18 01:16:20 +00002151 try_node = node_parent(try_node);
2152 vty->node = try_node;
paulb92938a2002-12-13 21:20:42 +00002153 ret = cmd_execute_command_real (vline, vty, cmd);
paul9ab68122003-01-18 01:16:20 +00002154 tried = 1;
2155 if (ret == CMD_SUCCESS || ret == CMD_WARNING)
paulb92938a2002-12-13 21:20:42 +00002156 {
paul9ab68122003-01-18 01:16:20 +00002157 /* succesfull command, leave the node as is */
paulb92938a2002-12-13 21:20:42 +00002158 return ret;
2159 }
paulb92938a2002-12-13 21:20:42 +00002160 }
paul9ab68122003-01-18 01:16:20 +00002161 /* no command succeeded, reset the vty to the original node and
2162 return the error for this node */
2163 if ( tried )
2164 vty->node = onode;
2165 return saved_ret;
pauleda031f2003-01-18 00:39:19 +00002166}
2167
paul718e3742002-12-13 20:15:29 +00002168/* Execute command by argument readline. */
2169int
paul909a2152005-03-14 17:41:45 +00002170cmd_execute_command_strict (vector vline, struct vty *vty,
paul718e3742002-12-13 20:15:29 +00002171 struct cmd_element **cmd)
2172{
hasso8c328f12004-10-05 21:01:23 +00002173 unsigned int i;
2174 unsigned int index;
paul718e3742002-12-13 20:15:29 +00002175 vector cmd_vector;
2176 struct cmd_element *cmd_element;
2177 struct cmd_element *matched_element;
2178 unsigned int matched_count, incomplete_count;
2179 int argc;
paul9035efa2004-10-10 11:56:56 +00002180 const char *argv[CMD_ARGC_MAX];
paul718e3742002-12-13 20:15:29 +00002181 int varflag;
2182 enum match_type match = 0;
2183 char *command;
2184
2185 /* Make copy of command element */
2186 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2187
paul55468c82005-03-14 20:19:01 +00002188 for (index = 0; index < vector_active (vline); index++)
paulb8961472005-03-14 17:35:52 +00002189 if ((command = vector_slot (vline, index)))
paul909a2152005-03-14 17:41:45 +00002190 {
2191 int ret;
2192
2193 match = cmd_filter_by_string (vector_slot (vline, index),
2194 cmd_vector, index);
paul718e3742002-12-13 20:15:29 +00002195
paul909a2152005-03-14 17:41:45 +00002196 /* If command meets '.VARARG' then finish matching. */
2197 if (match == vararg_match)
2198 break;
2199
2200 ret = is_cmd_ambiguous (command, cmd_vector, index, match);
2201 if (ret == 1)
2202 {
2203 vector_free (cmd_vector);
2204 return CMD_ERR_AMBIGUOUS;
2205 }
2206 if (ret == 2)
2207 {
2208 vector_free (cmd_vector);
2209 return CMD_ERR_NO_MATCH;
2210 }
2211 }
paul718e3742002-12-13 20:15:29 +00002212
2213 /* Check matched count. */
2214 matched_element = NULL;
2215 matched_count = 0;
2216 incomplete_count = 0;
paul55468c82005-03-14 20:19:01 +00002217 for (i = 0; i < vector_active (cmd_vector); i++)
paul909a2152005-03-14 17:41:45 +00002218 if (vector_slot (cmd_vector, i) != NULL)
paul718e3742002-12-13 20:15:29 +00002219 {
paul909a2152005-03-14 17:41:45 +00002220 cmd_element = vector_slot (cmd_vector, i);
paul718e3742002-12-13 20:15:29 +00002221
2222 if (match == vararg_match || index >= cmd_element->cmdsize)
2223 {
2224 matched_element = cmd_element;
2225 matched_count++;
2226 }
2227 else
2228 incomplete_count++;
2229 }
paul909a2152005-03-14 17:41:45 +00002230
paul718e3742002-12-13 20:15:29 +00002231 /* Finish of using cmd_vector. */
2232 vector_free (cmd_vector);
2233
paul909a2152005-03-14 17:41:45 +00002234 /* To execute command, matched_count must be 1. */
2235 if (matched_count == 0)
paul718e3742002-12-13 20:15:29 +00002236 {
2237 if (incomplete_count)
2238 return CMD_ERR_INCOMPLETE;
2239 else
2240 return CMD_ERR_NO_MATCH;
2241 }
2242
paul909a2152005-03-14 17:41:45 +00002243 if (matched_count > 1)
paul718e3742002-12-13 20:15:29 +00002244 return CMD_ERR_AMBIGUOUS;
2245
2246 /* Argument treatment */
2247 varflag = 0;
2248 argc = 0;
2249
paul55468c82005-03-14 20:19:01 +00002250 for (i = 0; i < vector_active (vline); i++)
paul718e3742002-12-13 20:15:29 +00002251 {
2252 if (varflag)
2253 argv[argc++] = vector_slot (vline, i);
2254 else
paul909a2152005-03-14 17:41:45 +00002255 {
paul718e3742002-12-13 20:15:29 +00002256 vector descvec = vector_slot (matched_element->strvec, i);
2257
paul55468c82005-03-14 20:19:01 +00002258 if (vector_active (descvec) == 1)
paul718e3742002-12-13 20:15:29 +00002259 {
2260 struct desc *desc = vector_slot (descvec, 0);
paul718e3742002-12-13 20:15:29 +00002261
hasso8c328f12004-10-05 21:01:23 +00002262 if (CMD_VARARG (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002263 varflag = 1;
paul909a2152005-03-14 17:41:45 +00002264
hasso8c328f12004-10-05 21:01:23 +00002265 if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002266 argv[argc++] = vector_slot (vline, i);
2267 }
2268 else
2269 argv[argc++] = vector_slot (vline, i);
2270 }
2271
2272 if (argc >= CMD_ARGC_MAX)
2273 return CMD_ERR_EXEED_ARGC_MAX;
2274 }
2275
2276 /* For vtysh execution. */
2277 if (cmd)
2278 *cmd = matched_element;
2279
2280 if (matched_element->daemon)
2281 return CMD_SUCCESS_DAEMON;
2282
2283 /* Now execute matched command */
2284 return (*matched_element->func) (matched_element, vty, argc, argv);
2285}
2286
2287/* Configration make from file. */
2288int
2289config_from_file (struct vty *vty, FILE *fp)
2290{
2291 int ret;
2292 vector vline;
2293
2294 while (fgets (vty->buf, VTY_BUFSIZ, fp))
2295 {
2296 vline = cmd_make_strvec (vty->buf);
2297
2298 /* In case of comment line */
2299 if (vline == NULL)
2300 continue;
2301 /* Execute configuration command : this is strict match */
2302 ret = cmd_execute_command_strict (vline, vty, NULL);
2303
2304 /* Try again with setting node to CONFIG_NODE */
paulb92938a2002-12-13 21:20:42 +00002305 while (ret != CMD_SUCCESS && ret != CMD_WARNING
hassoddd85ed2004-10-13 08:18:07 +00002306 && ret != CMD_ERR_NOTHING_TODO && vty->node != CONFIG_NODE)
2307 {
paulb92938a2002-12-13 21:20:42 +00002308 vty->node = node_parent(vty->node);
hassoddd85ed2004-10-13 08:18:07 +00002309 ret = cmd_execute_command_strict (vline, vty, NULL);
2310 }
paul9ab68122003-01-18 01:16:20 +00002311
paul718e3742002-12-13 20:15:29 +00002312 cmd_free_strvec (vline);
2313
hassoddd85ed2004-10-13 08:18:07 +00002314 if (ret != CMD_SUCCESS && ret != CMD_WARNING
2315 && ret != CMD_ERR_NOTHING_TODO)
paul718e3742002-12-13 20:15:29 +00002316 return ret;
2317 }
2318 return CMD_SUCCESS;
2319}
2320
2321/* Configration from terminal */
2322DEFUN (config_terminal,
2323 config_terminal_cmd,
2324 "configure terminal",
2325 "Configuration from vty interface\n"
2326 "Configuration terminal\n")
2327{
2328 if (vty_config_lock (vty))
2329 vty->node = CONFIG_NODE;
2330 else
2331 {
2332 vty_out (vty, "VTY configuration is locked by other VTY%s", VTY_NEWLINE);
2333 return CMD_WARNING;
2334 }
2335 return CMD_SUCCESS;
2336}
2337
2338/* Enable command */
2339DEFUN (enable,
2340 config_enable_cmd,
2341 "enable",
2342 "Turn on privileged mode command\n")
2343{
2344 /* If enable password is NULL, change to ENABLE_NODE */
2345 if ((host.enable == NULL && host.enable_encrypt == NULL) ||
2346 vty->type == VTY_SHELL_SERV)
2347 vty->node = ENABLE_NODE;
2348 else
2349 vty->node = AUTH_ENABLE_NODE;
2350
2351 return CMD_SUCCESS;
2352}
2353
2354/* Disable command */
2355DEFUN (disable,
2356 config_disable_cmd,
2357 "disable",
2358 "Turn off privileged mode command\n")
2359{
2360 if (vty->node == ENABLE_NODE)
2361 vty->node = VIEW_NODE;
2362 return CMD_SUCCESS;
2363}
2364
2365/* Down vty node level. */
2366DEFUN (config_exit,
2367 config_exit_cmd,
2368 "exit",
2369 "Exit current mode and down to previous mode\n")
2370{
2371 switch (vty->node)
2372 {
2373 case VIEW_NODE:
2374 case ENABLE_NODE:
2375 if (vty_shell (vty))
2376 exit (0);
2377 else
2378 vty->status = VTY_CLOSE;
2379 break;
2380 case CONFIG_NODE:
2381 vty->node = ENABLE_NODE;
2382 vty_config_unlock (vty);
2383 break;
2384 case INTERFACE_NODE:
2385 case ZEBRA_NODE:
2386 case BGP_NODE:
2387 case RIP_NODE:
2388 case RIPNG_NODE:
2389 case OSPF_NODE:
2390 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00002391 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00002392 case KEYCHAIN_NODE:
2393 case MASC_NODE:
2394 case RMAP_NODE:
2395 case VTY_NODE:
2396 vty->node = CONFIG_NODE;
2397 break;
2398 case BGP_VPNV4_NODE:
2399 case BGP_IPV4_NODE:
2400 case BGP_IPV4M_NODE:
2401 case BGP_IPV6_NODE:
paul1e836592005-08-22 22:39:56 +00002402 case BGP_IPV6M_NODE:
paul718e3742002-12-13 20:15:29 +00002403 vty->node = BGP_NODE;
2404 break;
2405 case KEYCHAIN_KEY_NODE:
2406 vty->node = KEYCHAIN_NODE;
2407 break;
2408 default:
2409 break;
2410 }
2411 return CMD_SUCCESS;
2412}
2413
2414/* quit is alias of exit. */
2415ALIAS (config_exit,
2416 config_quit_cmd,
2417 "quit",
2418 "Exit current mode and down to previous mode\n")
2419
2420/* End of configuration. */
2421DEFUN (config_end,
2422 config_end_cmd,
2423 "end",
2424 "End current mode and change to enable mode.")
2425{
2426 switch (vty->node)
2427 {
2428 case VIEW_NODE:
2429 case ENABLE_NODE:
2430 /* Nothing to do. */
2431 break;
2432 case CONFIG_NODE:
2433 case INTERFACE_NODE:
2434 case ZEBRA_NODE:
2435 case RIP_NODE:
2436 case RIPNG_NODE:
2437 case BGP_NODE:
2438 case BGP_VPNV4_NODE:
2439 case BGP_IPV4_NODE:
2440 case BGP_IPV4M_NODE:
2441 case BGP_IPV6_NODE:
paul1e836592005-08-22 22:39:56 +00002442 case BGP_IPV6M_NODE:
paul718e3742002-12-13 20:15:29 +00002443 case RMAP_NODE:
2444 case OSPF_NODE:
2445 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00002446 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00002447 case KEYCHAIN_NODE:
2448 case KEYCHAIN_KEY_NODE:
2449 case MASC_NODE:
2450 case VTY_NODE:
2451 vty_config_unlock (vty);
2452 vty->node = ENABLE_NODE;
2453 break;
2454 default:
2455 break;
2456 }
2457 return CMD_SUCCESS;
2458}
2459
2460/* Show version. */
2461DEFUN (show_version,
2462 show_version_cmd,
2463 "show version",
2464 SHOW_STR
2465 "Displays zebra version\n")
2466{
hasso12f6ea22005-03-07 08:35:39 +00002467 vty_out (vty, "Quagga %s (%s).%s", QUAGGA_VERSION, host.name?host.name:"",
2468 VTY_NEWLINE);
hasso6590f2c2004-10-19 20:40:08 +00002469 vty_out (vty, "%s%s", QUAGGA_COPYRIGHT, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00002470
2471 return CMD_SUCCESS;
2472}
2473
2474/* Help display function for all node. */
2475DEFUN (config_help,
2476 config_help_cmd,
2477 "help",
2478 "Description of the interactive help system\n")
2479{
2480 vty_out (vty,
hasso6590f2c2004-10-19 20:40:08 +00002481 "Quagga VTY provides advanced help feature. When you need help,%s\
paul718e3742002-12-13 20:15:29 +00002482anytime at the command line please press '?'.%s\
2483%s\
2484If nothing matches, the help list will be empty and you must backup%s\
2485 until entering a '?' shows the available options.%s\
2486Two styles of help are provided:%s\
24871. Full help is available when you are ready to enter a%s\
2488command argument (e.g. 'show ?') and describes each possible%s\
2489argument.%s\
24902. Partial help is provided when an abbreviated argument is entered%s\
2491 and you want to know what arguments match the input%s\
2492 (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2493 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2494 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
2495 return CMD_SUCCESS;
2496}
2497
2498/* Help display function for all node. */
2499DEFUN (config_list,
2500 config_list_cmd,
2501 "list",
2502 "Print command list\n")
2503{
hasso8c328f12004-10-05 21:01:23 +00002504 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002505 struct cmd_node *cnode = vector_slot (cmdvec, vty->node);
2506 struct cmd_element *cmd;
2507
paul55468c82005-03-14 20:19:01 +00002508 for (i = 0; i < vector_active (cnode->cmd_vector); i++)
paul4275b1d2005-03-09 13:42:23 +00002509 if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL
2510 && !(cmd->attr == CMD_ATTR_DEPRECATED
2511 || cmd->attr == CMD_ATTR_HIDDEN))
paul718e3742002-12-13 20:15:29 +00002512 vty_out (vty, " %s%s", cmd->string,
2513 VTY_NEWLINE);
2514 return CMD_SUCCESS;
2515}
2516
2517/* Write current configuration into file. */
2518DEFUN (config_write_file,
2519 config_write_file_cmd,
2520 "write file",
2521 "Write running configuration to memory, network, or terminal\n"
2522 "Write to configuration file\n")
2523{
hasso8c328f12004-10-05 21:01:23 +00002524 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002525 int fd;
2526 struct cmd_node *node;
2527 char *config_file;
2528 char *config_file_tmp = NULL;
2529 char *config_file_sav = NULL;
paul05865c92005-10-26 05:49:54 +00002530 int ret = CMD_WARNING;
paul718e3742002-12-13 20:15:29 +00002531 struct vty *file_vty;
2532
2533 /* Check and see if we are operating under vtysh configuration */
2534 if (host.config == NULL)
2535 {
2536 vty_out (vty, "Can't save to configuration file, using vtysh.%s",
2537 VTY_NEWLINE);
2538 return CMD_WARNING;
2539 }
2540
2541 /* Get filename. */
2542 config_file = host.config;
2543
paul05865c92005-10-26 05:49:54 +00002544 config_file_sav =
2545 XMALLOC (MTYPE_TMP, strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
paul718e3742002-12-13 20:15:29 +00002546 strcpy (config_file_sav, config_file);
2547 strcat (config_file_sav, CONF_BACKUP_EXT);
2548
2549
paul05865c92005-10-26 05:49:54 +00002550 config_file_tmp = XMALLOC (MTYPE_TMP, strlen (config_file) + 8);
paul718e3742002-12-13 20:15:29 +00002551 sprintf (config_file_tmp, "%s.XXXXXX", config_file);
2552
2553 /* Open file to configuration write. */
2554 fd = mkstemp (config_file_tmp);
2555 if (fd < 0)
2556 {
2557 vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
2558 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002559 goto finished;
paul718e3742002-12-13 20:15:29 +00002560 }
2561
2562 /* Make vty for configuration file. */
2563 file_vty = vty_new ();
2564 file_vty->fd = fd;
2565 file_vty->type = VTY_FILE;
2566
2567 /* Config file header print. */
2568 vty_out (file_vty, "!\n! Zebra configuration saved from vty\n! ");
2569 vty_time_print (file_vty, 1);
2570 vty_out (file_vty, "!\n");
2571
paul55468c82005-03-14 20:19:01 +00002572 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +00002573 if ((node = vector_slot (cmdvec, i)) && node->func)
2574 {
2575 if ((*node->func) (file_vty))
2576 vty_out (file_vty, "!\n");
2577 }
2578 vty_close (file_vty);
2579
2580 if (unlink (config_file_sav) != 0)
2581 if (errno != ENOENT)
2582 {
2583 vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
2584 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002585 goto finished;
paul718e3742002-12-13 20:15:29 +00002586 }
2587 if (link (config_file, config_file_sav) != 0)
2588 {
2589 vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
2590 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002591 goto finished;
paul718e3742002-12-13 20:15:29 +00002592 }
2593 sync ();
2594 if (unlink (config_file) != 0)
2595 {
2596 vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
2597 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002598 goto finished;
paul718e3742002-12-13 20:15:29 +00002599 }
2600 if (link (config_file_tmp, config_file) != 0)
2601 {
2602 vty_out (vty, "Can't save configuration file %s.%s", config_file,
2603 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002604 goto finished;
paul718e3742002-12-13 20:15:29 +00002605 }
paul718e3742002-12-13 20:15:29 +00002606 sync ();
2607
gdtaa593d52003-12-22 20:15:53 +00002608 if (chmod (config_file, CONFIGFILE_MASK) != 0)
2609 {
2610 vty_out (vty, "Can't chmod configuration file %s: %s (%d).%s",
ajs6099b3b2004-11-20 02:06:59 +00002611 config_file, safe_strerror(errno), errno, VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002612 goto finished;
gdtaa593d52003-12-22 20:15:53 +00002613 }
2614
paul718e3742002-12-13 20:15:29 +00002615 vty_out (vty, "Configuration saved to %s%s", config_file,
2616 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002617 ret = CMD_SUCCESS;
2618
2619finished:
2620 unlink (config_file_tmp);
2621 XFREE (MTYPE_TMP, config_file_tmp);
2622 XFREE (MTYPE_TMP, config_file_sav);
2623 return ret;
paul718e3742002-12-13 20:15:29 +00002624}
2625
2626ALIAS (config_write_file,
2627 config_write_cmd,
2628 "write",
2629 "Write running configuration to memory, network, or terminal\n")
2630
2631ALIAS (config_write_file,
2632 config_write_memory_cmd,
2633 "write memory",
2634 "Write running configuration to memory, network, or terminal\n"
2635 "Write configuration to the file (same as write file)\n")
2636
2637ALIAS (config_write_file,
2638 copy_runningconfig_startupconfig_cmd,
2639 "copy running-config startup-config",
2640 "Copy configuration\n"
2641 "Copy running config to... \n"
2642 "Copy running config to startup config (same as write file)\n")
2643
2644/* Write current configuration into the terminal. */
2645DEFUN (config_write_terminal,
2646 config_write_terminal_cmd,
2647 "write terminal",
2648 "Write running configuration to memory, network, or terminal\n"
2649 "Write to terminal\n")
2650{
hasso8c328f12004-10-05 21:01:23 +00002651 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002652 struct cmd_node *node;
2653
2654 if (vty->type == VTY_SHELL_SERV)
2655 {
paul55468c82005-03-14 20:19:01 +00002656 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +00002657 if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
2658 {
2659 if ((*node->func) (vty))
2660 vty_out (vty, "!%s", VTY_NEWLINE);
2661 }
2662 }
2663 else
2664 {
2665 vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
2666 VTY_NEWLINE);
2667 vty_out (vty, "!%s", VTY_NEWLINE);
2668
paul55468c82005-03-14 20:19:01 +00002669 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +00002670 if ((node = vector_slot (cmdvec, i)) && node->func)
2671 {
2672 if ((*node->func) (vty))
2673 vty_out (vty, "!%s", VTY_NEWLINE);
2674 }
2675 vty_out (vty, "end%s",VTY_NEWLINE);
2676 }
2677 return CMD_SUCCESS;
2678}
2679
2680/* Write current configuration into the terminal. */
2681ALIAS (config_write_terminal,
2682 show_running_config_cmd,
2683 "show running-config",
2684 SHOW_STR
2685 "running configuration\n")
2686
2687/* Write startup configuration into the terminal. */
2688DEFUN (show_startup_config,
2689 show_startup_config_cmd,
2690 "show startup-config",
2691 SHOW_STR
2692 "Contentes of startup configuration\n")
2693{
2694 char buf[BUFSIZ];
2695 FILE *confp;
2696
2697 confp = fopen (host.config, "r");
2698 if (confp == NULL)
2699 {
2700 vty_out (vty, "Can't open configuration file [%s]%s",
2701 host.config, VTY_NEWLINE);
2702 return CMD_WARNING;
2703 }
2704
2705 while (fgets (buf, BUFSIZ, confp))
2706 {
2707 char *cp = buf;
2708
2709 while (*cp != '\r' && *cp != '\n' && *cp != '\0')
2710 cp++;
2711 *cp = '\0';
2712
2713 vty_out (vty, "%s%s", buf, VTY_NEWLINE);
2714 }
2715
2716 fclose (confp);
2717
2718 return CMD_SUCCESS;
2719}
2720
2721/* Hostname configuration */
2722DEFUN (config_hostname,
2723 hostname_cmd,
2724 "hostname WORD",
2725 "Set system's network name\n"
2726 "This system's network name\n")
2727{
2728 if (!isalpha((int) *argv[0]))
2729 {
2730 vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
2731 return CMD_WARNING;
2732 }
2733
2734 if (host.name)
paul05865c92005-10-26 05:49:54 +00002735 XFREE (MTYPE_HOST, host.name);
paul718e3742002-12-13 20:15:29 +00002736
paul05865c92005-10-26 05:49:54 +00002737 host.name = XSTRDUP (MTYPE_HOST, argv[0]);
paul718e3742002-12-13 20:15:29 +00002738 return CMD_SUCCESS;
2739}
2740
2741DEFUN (config_no_hostname,
2742 no_hostname_cmd,
2743 "no hostname [HOSTNAME]",
2744 NO_STR
2745 "Reset system's network name\n"
2746 "Host name of this router\n")
2747{
2748 if (host.name)
paul05865c92005-10-26 05:49:54 +00002749 XFREE (MTYPE_HOST, host.name);
paul718e3742002-12-13 20:15:29 +00002750 host.name = NULL;
2751 return CMD_SUCCESS;
2752}
2753
2754/* VTY interface password set. */
2755DEFUN (config_password, password_cmd,
2756 "password (8|) WORD",
2757 "Assign the terminal connection password\n"
2758 "Specifies a HIDDEN password will follow\n"
2759 "dummy string \n"
2760 "The HIDDEN line password string\n")
2761{
2762 /* Argument check. */
2763 if (argc == 0)
2764 {
2765 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2766 return CMD_WARNING;
2767 }
2768
2769 if (argc == 2)
2770 {
2771 if (*argv[0] == '8')
2772 {
2773 if (host.password)
paul05865c92005-10-26 05:49:54 +00002774 XFREE (MTYPE_HOST, host.password);
paul718e3742002-12-13 20:15:29 +00002775 host.password = NULL;
2776 if (host.password_encrypt)
paul05865c92005-10-26 05:49:54 +00002777 XFREE (MTYPE_HOST, host.password_encrypt);
2778 host.password_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
paul718e3742002-12-13 20:15:29 +00002779 return CMD_SUCCESS;
2780 }
2781 else
2782 {
2783 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2784 return CMD_WARNING;
2785 }
2786 }
2787
2788 if (!isalnum ((int) *argv[0]))
2789 {
2790 vty_out (vty,
2791 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2792 return CMD_WARNING;
2793 }
2794
2795 if (host.password)
paul05865c92005-10-26 05:49:54 +00002796 XFREE (MTYPE_HOST, host.password);
paul718e3742002-12-13 20:15:29 +00002797 host.password = NULL;
2798
2799 if (host.encrypt)
2800 {
2801 if (host.password_encrypt)
paul05865c92005-10-26 05:49:54 +00002802 XFREE (MTYPE_HOST, host.password_encrypt);
2803 host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
paul718e3742002-12-13 20:15:29 +00002804 }
2805 else
paul05865c92005-10-26 05:49:54 +00002806 host.password = XSTRDUP (MTYPE_HOST, argv[0]);
paul718e3742002-12-13 20:15:29 +00002807
2808 return CMD_SUCCESS;
2809}
2810
2811ALIAS (config_password, password_text_cmd,
2812 "password LINE",
2813 "Assign the terminal connection password\n"
2814 "The UNENCRYPTED (cleartext) line password\n")
2815
2816/* VTY enable password set. */
2817DEFUN (config_enable_password, enable_password_cmd,
2818 "enable password (8|) WORD",
2819 "Modify enable password parameters\n"
2820 "Assign the privileged level password\n"
2821 "Specifies a HIDDEN password will follow\n"
2822 "dummy string \n"
2823 "The HIDDEN 'enable' password string\n")
2824{
2825 /* Argument check. */
2826 if (argc == 0)
2827 {
2828 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2829 return CMD_WARNING;
2830 }
2831
2832 /* Crypt type is specified. */
2833 if (argc == 2)
2834 {
2835 if (*argv[0] == '8')
2836 {
2837 if (host.enable)
paul05865c92005-10-26 05:49:54 +00002838 XFREE (MTYPE_HOST, host.enable);
paul718e3742002-12-13 20:15:29 +00002839 host.enable = NULL;
2840
2841 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002842 XFREE (MTYPE_HOST, host.enable_encrypt);
2843 host.enable_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
paul718e3742002-12-13 20:15:29 +00002844
2845 return CMD_SUCCESS;
2846 }
2847 else
2848 {
2849 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2850 return CMD_WARNING;
2851 }
2852 }
2853
2854 if (!isalnum ((int) *argv[0]))
2855 {
2856 vty_out (vty,
2857 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2858 return CMD_WARNING;
2859 }
2860
2861 if (host.enable)
paul05865c92005-10-26 05:49:54 +00002862 XFREE (MTYPE_HOST, host.enable);
paul718e3742002-12-13 20:15:29 +00002863 host.enable = NULL;
2864
2865 /* Plain password input. */
2866 if (host.encrypt)
2867 {
2868 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002869 XFREE (MTYPE_HOST, host.enable_encrypt);
2870 host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
paul718e3742002-12-13 20:15:29 +00002871 }
2872 else
paul05865c92005-10-26 05:49:54 +00002873 host.enable = XSTRDUP (MTYPE_HOST, argv[0]);
paul718e3742002-12-13 20:15:29 +00002874
2875 return CMD_SUCCESS;
2876}
2877
2878ALIAS (config_enable_password,
2879 enable_password_text_cmd,
2880 "enable password LINE",
2881 "Modify enable password parameters\n"
2882 "Assign the privileged level password\n"
2883 "The UNENCRYPTED (cleartext) 'enable' password\n")
2884
2885/* VTY enable password delete. */
2886DEFUN (no_config_enable_password, no_enable_password_cmd,
2887 "no enable password",
2888 NO_STR
2889 "Modify enable password parameters\n"
2890 "Assign the privileged level password\n")
2891{
2892 if (host.enable)
paul05865c92005-10-26 05:49:54 +00002893 XFREE (MTYPE_HOST, host.enable);
paul718e3742002-12-13 20:15:29 +00002894 host.enable = NULL;
2895
2896 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002897 XFREE (MTYPE_HOST, host.enable_encrypt);
paul718e3742002-12-13 20:15:29 +00002898 host.enable_encrypt = NULL;
2899
2900 return CMD_SUCCESS;
2901}
2902
2903DEFUN (service_password_encrypt,
2904 service_password_encrypt_cmd,
2905 "service password-encryption",
2906 "Set up miscellaneous service\n"
2907 "Enable encrypted passwords\n")
2908{
2909 if (host.encrypt)
2910 return CMD_SUCCESS;
2911
2912 host.encrypt = 1;
2913
2914 if (host.password)
2915 {
2916 if (host.password_encrypt)
paul05865c92005-10-26 05:49:54 +00002917 XFREE (MTYPE_HOST, host.password_encrypt);
2918 host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.password));
paul718e3742002-12-13 20:15:29 +00002919 }
2920 if (host.enable)
2921 {
2922 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002923 XFREE (MTYPE_HOST, host.enable_encrypt);
2924 host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.enable));
paul718e3742002-12-13 20:15:29 +00002925 }
2926
2927 return CMD_SUCCESS;
2928}
2929
2930DEFUN (no_service_password_encrypt,
2931 no_service_password_encrypt_cmd,
2932 "no service password-encryption",
2933 NO_STR
2934 "Set up miscellaneous service\n"
2935 "Enable encrypted passwords\n")
2936{
2937 if (! host.encrypt)
2938 return CMD_SUCCESS;
2939
2940 host.encrypt = 0;
2941
2942 if (host.password_encrypt)
paul05865c92005-10-26 05:49:54 +00002943 XFREE (MTYPE_HOST, host.password_encrypt);
paul718e3742002-12-13 20:15:29 +00002944 host.password_encrypt = NULL;
2945
2946 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002947 XFREE (MTYPE_HOST, host.enable_encrypt);
paul718e3742002-12-13 20:15:29 +00002948 host.enable_encrypt = NULL;
2949
2950 return CMD_SUCCESS;
2951}
2952
2953DEFUN (config_terminal_length, config_terminal_length_cmd,
2954 "terminal length <0-512>",
2955 "Set terminal line parameters\n"
2956 "Set number of lines on a screen\n"
2957 "Number of lines on screen (0 for no pausing)\n")
2958{
2959 int lines;
2960 char *endptr = NULL;
2961
2962 lines = strtol (argv[0], &endptr, 10);
2963 if (lines < 0 || lines > 512 || *endptr != '\0')
2964 {
2965 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2966 return CMD_WARNING;
2967 }
2968 vty->lines = lines;
2969
2970 return CMD_SUCCESS;
2971}
2972
2973DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
2974 "terminal no length",
2975 "Set terminal line parameters\n"
2976 NO_STR
2977 "Set number of lines on a screen\n")
2978{
2979 vty->lines = -1;
2980 return CMD_SUCCESS;
2981}
2982
2983DEFUN (service_terminal_length, service_terminal_length_cmd,
2984 "service terminal-length <0-512>",
2985 "Set up miscellaneous service\n"
2986 "System wide terminal length configuration\n"
2987 "Number of lines of VTY (0 means no line control)\n")
2988{
2989 int lines;
2990 char *endptr = NULL;
2991
2992 lines = strtol (argv[0], &endptr, 10);
2993 if (lines < 0 || lines > 512 || *endptr != '\0')
2994 {
2995 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2996 return CMD_WARNING;
2997 }
2998 host.lines = lines;
2999
3000 return CMD_SUCCESS;
3001}
3002
3003DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
3004 "no service terminal-length [<0-512>]",
3005 NO_STR
3006 "Set up miscellaneous service\n"
3007 "System wide terminal length configuration\n"
3008 "Number of lines of VTY (0 means no line control)\n")
3009{
3010 host.lines = -1;
3011 return CMD_SUCCESS;
3012}
3013
ajs2885f722004-12-17 23:16:33 +00003014DEFUN_HIDDEN (do_echo,
3015 echo_cmd,
3016 "echo .MESSAGE",
3017 "Echo a message back to the vty\n"
3018 "The message to echo\n")
3019{
3020 char *message;
3021
ajsf6834d42005-01-28 20:28:35 +00003022 vty_out (vty, "%s%s", ((message = argv_concat(argv, argc, 0)) ? message : ""),
3023 VTY_NEWLINE);
3024 if (message)
3025 XFREE(MTYPE_TMP, message);
ajs2885f722004-12-17 23:16:33 +00003026 return CMD_SUCCESS;
3027}
3028
ajs274a4a42004-12-07 15:39:31 +00003029DEFUN (config_logmsg,
3030 config_logmsg_cmd,
3031 "logmsg "LOG_LEVELS" .MESSAGE",
3032 "Send a message to enabled logging destinations\n"
3033 LOG_LEVEL_DESC
3034 "The message to send\n")
3035{
3036 int level;
3037 char *message;
3038
3039 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3040 return CMD_ERR_NO_MATCH;
3041
ajsf6834d42005-01-28 20:28:35 +00003042 zlog(NULL, level, ((message = argv_concat(argv, argc, 1)) ? message : ""));
3043 if (message)
3044 XFREE(MTYPE_TMP, message);
ajs274a4a42004-12-07 15:39:31 +00003045 return CMD_SUCCESS;
3046}
3047
3048DEFUN (show_logging,
3049 show_logging_cmd,
3050 "show logging",
3051 SHOW_STR
3052 "Show current logging configuration\n")
3053{
3054 struct zlog *zl = zlog_default;
3055
3056 vty_out (vty, "Syslog logging: ");
3057 if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED)
3058 vty_out (vty, "disabled");
3059 else
3060 vty_out (vty, "level %s, facility %s, ident %s",
3061 zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]],
3062 facility_name(zl->facility), zl->ident);
3063 vty_out (vty, "%s", VTY_NEWLINE);
3064
3065 vty_out (vty, "Stdout logging: ");
3066 if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED)
3067 vty_out (vty, "disabled");
3068 else
3069 vty_out (vty, "level %s",
3070 zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
3071 vty_out (vty, "%s", VTY_NEWLINE);
3072
3073 vty_out (vty, "Monitor logging: ");
3074 if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
3075 vty_out (vty, "disabled");
3076 else
3077 vty_out (vty, "level %s",
3078 zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
3079 vty_out (vty, "%s", VTY_NEWLINE);
3080
3081 vty_out (vty, "File logging: ");
3082 if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) ||
3083 !zl->fp)
3084 vty_out (vty, "disabled");
3085 else
3086 vty_out (vty, "level %s, filename %s",
3087 zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
3088 zl->filename);
3089 vty_out (vty, "%s", VTY_NEWLINE);
3090
3091 vty_out (vty, "Protocol name: %s%s",
3092 zlog_proto_names[zl->protocol], VTY_NEWLINE);
3093 vty_out (vty, "Record priority: %s%s",
3094 (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE);
3095
3096 return CMD_SUCCESS;
3097}
3098
paul718e3742002-12-13 20:15:29 +00003099DEFUN (config_log_stdout,
3100 config_log_stdout_cmd,
3101 "log stdout",
3102 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003103 "Set stdout logging level\n")
paul718e3742002-12-13 20:15:29 +00003104{
ajs274a4a42004-12-07 15:39:31 +00003105 zlog_set_level (NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl);
3106 return CMD_SUCCESS;
3107}
3108
3109DEFUN (config_log_stdout_level,
3110 config_log_stdout_level_cmd,
3111 "log stdout "LOG_LEVELS,
3112 "Logging control\n"
3113 "Set stdout logging level\n"
3114 LOG_LEVEL_DESC)
3115{
3116 int level;
3117
3118 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3119 return CMD_ERR_NO_MATCH;
3120 zlog_set_level (NULL, ZLOG_DEST_STDOUT, level);
paul718e3742002-12-13 20:15:29 +00003121 return CMD_SUCCESS;
3122}
3123
3124DEFUN (no_config_log_stdout,
3125 no_config_log_stdout_cmd,
ajs274a4a42004-12-07 15:39:31 +00003126 "no log stdout [LEVEL]",
paul718e3742002-12-13 20:15:29 +00003127 NO_STR
3128 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003129 "Cancel logging to stdout\n"
3130 "Logging level\n")
paul718e3742002-12-13 20:15:29 +00003131{
ajs274a4a42004-12-07 15:39:31 +00003132 zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED);
paul718e3742002-12-13 20:15:29 +00003133 return CMD_SUCCESS;
3134}
3135
ajs274a4a42004-12-07 15:39:31 +00003136DEFUN (config_log_monitor,
3137 config_log_monitor_cmd,
3138 "log monitor",
paul718e3742002-12-13 20:15:29 +00003139 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003140 "Set terminal line (monitor) logging level\n")
3141{
3142 zlog_set_level (NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl);
3143 return CMD_SUCCESS;
3144}
3145
3146DEFUN (config_log_monitor_level,
3147 config_log_monitor_level_cmd,
3148 "log monitor "LOG_LEVELS,
3149 "Logging control\n"
3150 "Set terminal line (monitor) logging level\n"
3151 LOG_LEVEL_DESC)
3152{
3153 int level;
3154
3155 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3156 return CMD_ERR_NO_MATCH;
3157 zlog_set_level (NULL, ZLOG_DEST_MONITOR, level);
3158 return CMD_SUCCESS;
3159}
3160
3161DEFUN (no_config_log_monitor,
3162 no_config_log_monitor_cmd,
3163 "no log monitor [LEVEL]",
3164 NO_STR
3165 "Logging control\n"
3166 "Disable terminal line (monitor) logging\n"
3167 "Logging level\n")
3168{
3169 zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
3170 return CMD_SUCCESS;
3171}
3172
3173static int
3174set_log_file(struct vty *vty, const char *fname, int loglevel)
paul718e3742002-12-13 20:15:29 +00003175{
3176 int ret;
paul9035efa2004-10-10 11:56:56 +00003177 char *p = NULL;
3178 const char *fullpath;
3179
paul718e3742002-12-13 20:15:29 +00003180 /* Path detection. */
ajs274a4a42004-12-07 15:39:31 +00003181 if (! IS_DIRECTORY_SEP (*fname))
paul718e3742002-12-13 20:15:29 +00003182 {
paul9035efa2004-10-10 11:56:56 +00003183 char cwd[MAXPATHLEN+1];
3184 cwd[MAXPATHLEN] = '\0';
3185
3186 if (getcwd (cwd, MAXPATHLEN) == NULL)
3187 {
3188 zlog_err ("config_log_file: Unable to alloc mem!");
3189 return CMD_WARNING;
3190 }
3191
ajs274a4a42004-12-07 15:39:31 +00003192 if ( (p = XMALLOC (MTYPE_TMP, strlen (cwd) + strlen (fname) + 2))
paul9035efa2004-10-10 11:56:56 +00003193 == NULL)
3194 {
3195 zlog_err ("config_log_file: Unable to alloc mem!");
3196 return CMD_WARNING;
3197 }
ajs274a4a42004-12-07 15:39:31 +00003198 sprintf (p, "%s/%s", cwd, fname);
paul9035efa2004-10-10 11:56:56 +00003199 fullpath = p;
paul718e3742002-12-13 20:15:29 +00003200 }
3201 else
ajs274a4a42004-12-07 15:39:31 +00003202 fullpath = fname;
paul718e3742002-12-13 20:15:29 +00003203
ajs274a4a42004-12-07 15:39:31 +00003204 ret = zlog_set_file (NULL, fullpath, loglevel);
paul718e3742002-12-13 20:15:29 +00003205
paul9035efa2004-10-10 11:56:56 +00003206 if (p)
3207 XFREE (MTYPE_TMP, p);
3208
paul718e3742002-12-13 20:15:29 +00003209 if (!ret)
3210 {
ajs274a4a42004-12-07 15:39:31 +00003211 vty_out (vty, "can't open logfile %s\n", fname);
paul718e3742002-12-13 20:15:29 +00003212 return CMD_WARNING;
3213 }
3214
3215 if (host.logfile)
paul05865c92005-10-26 05:49:54 +00003216 XFREE (MTYPE_HOST, host.logfile);
paul718e3742002-12-13 20:15:29 +00003217
paul05865c92005-10-26 05:49:54 +00003218 host.logfile = XSTRDUP (MTYPE_HOST, fname);
paul718e3742002-12-13 20:15:29 +00003219
3220 return CMD_SUCCESS;
3221}
3222
ajs274a4a42004-12-07 15:39:31 +00003223DEFUN (config_log_file,
3224 config_log_file_cmd,
3225 "log file FILENAME",
3226 "Logging control\n"
3227 "Logging to file\n"
3228 "Logging filename\n")
3229{
3230 return set_log_file(vty, argv[0], zlog_default->default_lvl);
3231}
3232
3233DEFUN (config_log_file_level,
3234 config_log_file_level_cmd,
3235 "log file FILENAME "LOG_LEVELS,
3236 "Logging control\n"
3237 "Logging to file\n"
3238 "Logging filename\n"
3239 LOG_LEVEL_DESC)
3240{
3241 int level;
3242
3243 if ((level = level_match(argv[1])) == ZLOG_DISABLED)
3244 return CMD_ERR_NO_MATCH;
3245 return set_log_file(vty, argv[0], level);
3246}
3247
paul718e3742002-12-13 20:15:29 +00003248DEFUN (no_config_log_file,
3249 no_config_log_file_cmd,
3250 "no log file [FILENAME]",
3251 NO_STR
3252 "Logging control\n"
3253 "Cancel logging to file\n"
3254 "Logging file name\n")
3255{
3256 zlog_reset_file (NULL);
3257
3258 if (host.logfile)
paul05865c92005-10-26 05:49:54 +00003259 XFREE (MTYPE_HOST, host.logfile);
paul718e3742002-12-13 20:15:29 +00003260
3261 host.logfile = NULL;
3262
3263 return CMD_SUCCESS;
3264}
3265
ajs274a4a42004-12-07 15:39:31 +00003266ALIAS (no_config_log_file,
3267 no_config_log_file_level_cmd,
3268 "no log file FILENAME LEVEL",
3269 NO_STR
3270 "Logging control\n"
3271 "Cancel logging to file\n"
3272 "Logging file name\n"
3273 "Logging level\n")
3274
paul718e3742002-12-13 20:15:29 +00003275DEFUN (config_log_syslog,
3276 config_log_syslog_cmd,
3277 "log syslog",
3278 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003279 "Set syslog logging level\n")
paul718e3742002-12-13 20:15:29 +00003280{
ajs274a4a42004-12-07 15:39:31 +00003281 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
paul12ab19f2003-07-26 06:14:55 +00003282 return CMD_SUCCESS;
3283}
3284
ajs274a4a42004-12-07 15:39:31 +00003285DEFUN (config_log_syslog_level,
3286 config_log_syslog_level_cmd,
3287 "log syslog "LOG_LEVELS,
paul12ab19f2003-07-26 06:14:55 +00003288 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003289 "Set syslog logging level\n"
3290 LOG_LEVEL_DESC)
paul12ab19f2003-07-26 06:14:55 +00003291{
ajs274a4a42004-12-07 15:39:31 +00003292 int level;
paul12ab19f2003-07-26 06:14:55 +00003293
ajs274a4a42004-12-07 15:39:31 +00003294 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3295 return CMD_ERR_NO_MATCH;
3296 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, level);
3297 return CMD_SUCCESS;
3298}
paul12ab19f2003-07-26 06:14:55 +00003299
ajs274a4a42004-12-07 15:39:31 +00003300DEFUN_DEPRECATED (config_log_syslog_facility,
3301 config_log_syslog_facility_cmd,
3302 "log syslog facility "LOG_FACILITIES,
3303 "Logging control\n"
3304 "Logging goes to syslog\n"
3305 "(Deprecated) Facility parameter for syslog messages\n"
3306 LOG_FACILITY_DESC)
3307{
3308 int facility;
paul12ab19f2003-07-26 06:14:55 +00003309
ajs274a4a42004-12-07 15:39:31 +00003310 if ((facility = facility_match(argv[0])) < 0)
3311 return CMD_ERR_NO_MATCH;
3312
3313 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
paul12ab19f2003-07-26 06:14:55 +00003314 zlog_default->facility = facility;
paul718e3742002-12-13 20:15:29 +00003315 return CMD_SUCCESS;
3316}
3317
3318DEFUN (no_config_log_syslog,
3319 no_config_log_syslog_cmd,
ajs274a4a42004-12-07 15:39:31 +00003320 "no log syslog [LEVEL]",
paul718e3742002-12-13 20:15:29 +00003321 NO_STR
3322 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003323 "Cancel logging to syslog\n"
3324 "Logging level\n")
paul718e3742002-12-13 20:15:29 +00003325{
ajs274a4a42004-12-07 15:39:31 +00003326 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
paul718e3742002-12-13 20:15:29 +00003327 return CMD_SUCCESS;
3328}
3329
paul12ab19f2003-07-26 06:14:55 +00003330ALIAS (no_config_log_syslog,
3331 no_config_log_syslog_facility_cmd,
ajs274a4a42004-12-07 15:39:31 +00003332 "no log syslog facility "LOG_FACILITIES,
paul12ab19f2003-07-26 06:14:55 +00003333 NO_STR
3334 "Logging control\n"
3335 "Logging goes to syslog\n"
3336 "Facility parameter for syslog messages\n"
ajs274a4a42004-12-07 15:39:31 +00003337 LOG_FACILITY_DESC)
paul12ab19f2003-07-26 06:14:55 +00003338
ajs274a4a42004-12-07 15:39:31 +00003339DEFUN (config_log_facility,
3340 config_log_facility_cmd,
3341 "log facility "LOG_FACILITIES,
paul718e3742002-12-13 20:15:29 +00003342 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003343 "Facility parameter for syslog messages\n"
3344 LOG_FACILITY_DESC)
paul718e3742002-12-13 20:15:29 +00003345{
ajs274a4a42004-12-07 15:39:31 +00003346 int facility;
3347
3348 if ((facility = facility_match(argv[0])) < 0)
3349 return CMD_ERR_NO_MATCH;
3350 zlog_default->facility = facility;
3351 return CMD_SUCCESS;
paul718e3742002-12-13 20:15:29 +00003352}
3353
ajs274a4a42004-12-07 15:39:31 +00003354DEFUN (no_config_log_facility,
3355 no_config_log_facility_cmd,
3356 "no log facility [FACILITY]",
paul718e3742002-12-13 20:15:29 +00003357 NO_STR
3358 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003359 "Reset syslog facility to default (daemon)\n"
3360 "Syslog facility\n")
paul718e3742002-12-13 20:15:29 +00003361{
ajs274a4a42004-12-07 15:39:31 +00003362 zlog_default->facility = LOG_DAEMON;
3363 return CMD_SUCCESS;
3364}
3365
3366DEFUN_DEPRECATED (config_log_trap,
3367 config_log_trap_cmd,
3368 "log trap "LOG_LEVELS,
3369 "Logging control\n"
3370 "(Deprecated) Set logging level and default for all destinations\n"
3371 LOG_LEVEL_DESC)
3372{
3373 int new_level ;
3374 int i;
3375
3376 if ((new_level = level_match(argv[0])) == ZLOG_DISABLED)
3377 return CMD_ERR_NO_MATCH;
3378
3379 zlog_default->default_lvl = new_level;
3380 for (i = 0; i < ZLOG_NUM_DESTS; i++)
3381 if (zlog_default->maxlvl[i] != ZLOG_DISABLED)
3382 zlog_default->maxlvl[i] = new_level;
3383 return CMD_SUCCESS;
3384}
3385
3386DEFUN_DEPRECATED (no_config_log_trap,
3387 no_config_log_trap_cmd,
3388 "no log trap [LEVEL]",
3389 NO_STR
3390 "Logging control\n"
3391 "Permit all logging information\n"
3392 "Logging level\n")
3393{
3394 zlog_default->default_lvl = LOG_DEBUG;
paul718e3742002-12-13 20:15:29 +00003395 return CMD_SUCCESS;
3396}
3397
3398DEFUN (config_log_record_priority,
3399 config_log_record_priority_cmd,
3400 "log record-priority",
3401 "Logging control\n"
3402 "Log the priority of the message within the message\n")
3403{
3404 zlog_default->record_priority = 1 ;
3405 return CMD_SUCCESS;
3406}
3407
3408DEFUN (no_config_log_record_priority,
3409 no_config_log_record_priority_cmd,
3410 "no log record-priority",
3411 NO_STR
3412 "Logging control\n"
3413 "Do not log the priority of the message within the message\n")
3414{
3415 zlog_default->record_priority = 0 ;
3416 return CMD_SUCCESS;
3417}
3418
paul3b0c5d92005-03-08 10:43:43 +00003419DEFUN (banner_motd_file,
3420 banner_motd_file_cmd,
3421 "banner motd file [FILE]",
3422 "Set banner\n"
3423 "Banner for motd\n"
3424 "Banner from a file\n"
3425 "Filename\n")
3426{
paulb45da6f2005-03-08 15:16:57 +00003427 if (host.motdfile)
paul05865c92005-10-26 05:49:54 +00003428 XFREE (MTYPE_HOST, host.motdfile);
3429 host.motdfile = XSTRDUP (MTYPE_HOST, argv[0]);
paulb45da6f2005-03-08 15:16:57 +00003430
paul3b0c5d92005-03-08 10:43:43 +00003431 return CMD_SUCCESS;
3432}
paul718e3742002-12-13 20:15:29 +00003433
3434DEFUN (banner_motd_default,
3435 banner_motd_default_cmd,
3436 "banner motd default",
3437 "Set banner string\n"
3438 "Strings for motd\n"
3439 "Default string\n")
3440{
3441 host.motd = default_motd;
3442 return CMD_SUCCESS;
3443}
3444
3445DEFUN (no_banner_motd,
3446 no_banner_motd_cmd,
3447 "no banner motd",
3448 NO_STR
3449 "Set banner string\n"
3450 "Strings for motd\n")
3451{
3452 host.motd = NULL;
paul22085182005-03-08 16:00:12 +00003453 if (host.motdfile)
paul05865c92005-10-26 05:49:54 +00003454 XFREE (MTYPE_HOST, host.motdfile);
paul3b0c5d92005-03-08 10:43:43 +00003455 host.motdfile = NULL;
paul718e3742002-12-13 20:15:29 +00003456 return CMD_SUCCESS;
3457}
3458
3459/* Set config filename. Called from vty.c */
3460void
3461host_config_set (char *filename)
3462{
paul05865c92005-10-26 05:49:54 +00003463 host.config = XSTRDUP (MTYPE_HOST, filename);
paul718e3742002-12-13 20:15:29 +00003464}
3465
3466void
3467install_default (enum node_type node)
3468{
3469 install_element (node, &config_exit_cmd);
3470 install_element (node, &config_quit_cmd);
3471 install_element (node, &config_end_cmd);
3472 install_element (node, &config_help_cmd);
3473 install_element (node, &config_list_cmd);
3474
3475 install_element (node, &config_write_terminal_cmd);
3476 install_element (node, &config_write_file_cmd);
3477 install_element (node, &config_write_memory_cmd);
3478 install_element (node, &config_write_cmd);
3479 install_element (node, &show_running_config_cmd);
3480}
3481
3482/* Initialize command interface. Install basic nodes and commands. */
3483void
3484cmd_init (int terminal)
3485{
3486 /* Allocate initial top vector of commands. */
3487 cmdvec = vector_init (VECTOR_MIN_SIZE);
3488
3489 /* Default host value settings. */
3490 host.name = NULL;
3491 host.password = NULL;
3492 host.enable = NULL;
3493 host.logfile = NULL;
3494 host.config = NULL;
3495 host.lines = -1;
3496 host.motd = default_motd;
paul3b0c5d92005-03-08 10:43:43 +00003497 host.motdfile = NULL;
paul718e3742002-12-13 20:15:29 +00003498
3499 /* Install top nodes. */
3500 install_node (&view_node, NULL);
3501 install_node (&enable_node, NULL);
3502 install_node (&auth_node, NULL);
3503 install_node (&auth_enable_node, NULL);
3504 install_node (&config_node, config_write_host);
3505
3506 /* Each node's basic commands. */
3507 install_element (VIEW_NODE, &show_version_cmd);
3508 if (terminal)
3509 {
3510 install_element (VIEW_NODE, &config_list_cmd);
3511 install_element (VIEW_NODE, &config_exit_cmd);
3512 install_element (VIEW_NODE, &config_quit_cmd);
3513 install_element (VIEW_NODE, &config_help_cmd);
3514 install_element (VIEW_NODE, &config_enable_cmd);
3515 install_element (VIEW_NODE, &config_terminal_length_cmd);
3516 install_element (VIEW_NODE, &config_terminal_no_length_cmd);
ajs274a4a42004-12-07 15:39:31 +00003517 install_element (VIEW_NODE, &show_logging_cmd);
ajs2885f722004-12-17 23:16:33 +00003518 install_element (VIEW_NODE, &echo_cmd);
paul718e3742002-12-13 20:15:29 +00003519 }
3520
3521 if (terminal)
3522 {
3523 install_default (ENABLE_NODE);
3524 install_element (ENABLE_NODE, &config_disable_cmd);
3525 install_element (ENABLE_NODE, &config_terminal_cmd);
3526 install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
3527 }
3528 install_element (ENABLE_NODE, &show_startup_config_cmd);
3529 install_element (ENABLE_NODE, &show_version_cmd);
paul718e3742002-12-13 20:15:29 +00003530
3531 if (terminal)
paul718e3742002-12-13 20:15:29 +00003532 {
hassoe7168df2004-10-03 20:11:32 +00003533 install_element (ENABLE_NODE, &config_terminal_length_cmd);
3534 install_element (ENABLE_NODE, &config_terminal_no_length_cmd);
ajs274a4a42004-12-07 15:39:31 +00003535 install_element (ENABLE_NODE, &show_logging_cmd);
ajs2885f722004-12-17 23:16:33 +00003536 install_element (ENABLE_NODE, &echo_cmd);
ajs274a4a42004-12-07 15:39:31 +00003537 install_element (ENABLE_NODE, &config_logmsg_cmd);
hassoe7168df2004-10-03 20:11:32 +00003538
3539 install_default (CONFIG_NODE);
hassoea8e9d92004-10-07 21:32:14 +00003540 }
3541
3542 install_element (CONFIG_NODE, &hostname_cmd);
3543 install_element (CONFIG_NODE, &no_hostname_cmd);
hassoe7168df2004-10-03 20:11:32 +00003544
hassoea8e9d92004-10-07 21:32:14 +00003545 if (terminal)
3546 {
hassoe7168df2004-10-03 20:11:32 +00003547 install_element (CONFIG_NODE, &password_cmd);
3548 install_element (CONFIG_NODE, &password_text_cmd);
3549 install_element (CONFIG_NODE, &enable_password_cmd);
3550 install_element (CONFIG_NODE, &enable_password_text_cmd);
3551 install_element (CONFIG_NODE, &no_enable_password_cmd);
3552
paul718e3742002-12-13 20:15:29 +00003553 install_element (CONFIG_NODE, &config_log_stdout_cmd);
ajs274a4a42004-12-07 15:39:31 +00003554 install_element (CONFIG_NODE, &config_log_stdout_level_cmd);
paul718e3742002-12-13 20:15:29 +00003555 install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
ajs274a4a42004-12-07 15:39:31 +00003556 install_element (CONFIG_NODE, &config_log_monitor_cmd);
3557 install_element (CONFIG_NODE, &config_log_monitor_level_cmd);
3558 install_element (CONFIG_NODE, &no_config_log_monitor_cmd);
paul718e3742002-12-13 20:15:29 +00003559 install_element (CONFIG_NODE, &config_log_file_cmd);
ajs274a4a42004-12-07 15:39:31 +00003560 install_element (CONFIG_NODE, &config_log_file_level_cmd);
paul718e3742002-12-13 20:15:29 +00003561 install_element (CONFIG_NODE, &no_config_log_file_cmd);
ajs274a4a42004-12-07 15:39:31 +00003562 install_element (CONFIG_NODE, &no_config_log_file_level_cmd);
paul718e3742002-12-13 20:15:29 +00003563 install_element (CONFIG_NODE, &config_log_syslog_cmd);
ajs274a4a42004-12-07 15:39:31 +00003564 install_element (CONFIG_NODE, &config_log_syslog_level_cmd);
paul12ab19f2003-07-26 06:14:55 +00003565 install_element (CONFIG_NODE, &config_log_syslog_facility_cmd);
paul718e3742002-12-13 20:15:29 +00003566 install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
paul12ab19f2003-07-26 06:14:55 +00003567 install_element (CONFIG_NODE, &no_config_log_syslog_facility_cmd);
ajs274a4a42004-12-07 15:39:31 +00003568 install_element (CONFIG_NODE, &config_log_facility_cmd);
3569 install_element (CONFIG_NODE, &no_config_log_facility_cmd);
paul718e3742002-12-13 20:15:29 +00003570 install_element (CONFIG_NODE, &config_log_trap_cmd);
3571 install_element (CONFIG_NODE, &no_config_log_trap_cmd);
3572 install_element (CONFIG_NODE, &config_log_record_priority_cmd);
3573 install_element (CONFIG_NODE, &no_config_log_record_priority_cmd);
3574 install_element (CONFIG_NODE, &service_password_encrypt_cmd);
3575 install_element (CONFIG_NODE, &no_service_password_encrypt_cmd);
3576 install_element (CONFIG_NODE, &banner_motd_default_cmd);
paul3b0c5d92005-03-08 10:43:43 +00003577 install_element (CONFIG_NODE, &banner_motd_file_cmd);
paul718e3742002-12-13 20:15:29 +00003578 install_element (CONFIG_NODE, &no_banner_motd_cmd);
3579 install_element (CONFIG_NODE, &service_terminal_length_cmd);
3580 install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
paul718e3742002-12-13 20:15:29 +00003581
paul354d1192005-04-25 16:26:42 +00003582 install_element (VIEW_NODE, &show_thread_cpu_cmd);
3583 install_element (ENABLE_NODE, &show_thread_cpu_cmd);
3584 install_element (VIEW_NODE, &show_work_queues_cmd);
3585 install_element (ENABLE_NODE, &show_work_queues_cmd);
paul9ab68122003-01-18 01:16:20 +00003586 }
paul718e3742002-12-13 20:15:29 +00003587 srand(time(NULL));
3588}