blob: 07297effd4efe3ba8276fe082955908549939da8 [file] [log] [blame]
ajs274a4a42004-12-07 15:39:31 +00001/*
Paul Jakma5fc60512006-05-12 23:24:09 +00002 $Id: command.c,v 1.53 2006/05/12 23:24:09 paul Exp $
paul9e92eea2005-03-09 13:39:26 +00003
ajs274a4a42004-12-07 15:39:31 +00004 Command interpreter routine for virtual terminal [aka TeletYpe]
paul718e3742002-12-13 20:15:29 +00005 Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
6
7This file is part of GNU Zebra.
8
9GNU Zebra is free software; you can redistribute it and/or modify
10it under the terms of the GNU General Public License as published
11by the Free Software Foundation; either version 2, or (at your
12option) any later version.
13
14GNU Zebra is distributed in the hope that it will be useful, but
15WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with GNU Zebra; see the file COPYING. If not, write to the
21Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22Boston, MA 02111-1307, USA. */
23
24#include <zebra.h>
25
paulb21b19c2003-06-15 01:28:29 +000026
paul718e3742002-12-13 20:15:29 +000027#include "memory.h"
28#include "log.h"
gdt5e4fa162004-03-16 14:38:36 +000029#include <lib/version.h>
paul9ab68122003-01-18 01:16:20 +000030#include "thread.h"
paulb21b19c2003-06-15 01:28:29 +000031#include "vector.h"
32#include "vty.h"
33#include "command.h"
paul354d1192005-04-25 16:26:42 +000034#include "workqueue.h"
paul718e3742002-12-13 20:15:29 +000035
36/* Command vector which includes some level of command lists. Normally
37 each daemon maintains each own cmdvec. */
pauleb820af2005-09-05 11:54:13 +000038vector cmdvec = NULL;
paul718e3742002-12-13 20:15:29 +000039
40/* Host information structure. */
41struct host host;
42
paul718e3742002-12-13 20:15:29 +000043/* Standard command node structures. */
44struct cmd_node auth_node =
45{
46 AUTH_NODE,
47 "Password: ",
48};
49
50struct cmd_node view_node =
51{
52 VIEW_NODE,
53 "%s> ",
54};
55
56struct cmd_node auth_enable_node =
57{
58 AUTH_ENABLE_NODE,
59 "Password: ",
60};
61
62struct cmd_node enable_node =
63{
64 ENABLE_NODE,
65 "%s# ",
66};
67
68struct cmd_node config_node =
69{
70 CONFIG_NODE,
71 "%s(config)# ",
72 1
73};
hasso6590f2c2004-10-19 20:40:08 +000074
75/* Default motd string. */
76const char *default_motd =
77"\r\n\
78Hello, this is " QUAGGA_PROGNAME " (version " QUAGGA_VERSION ").\r\n\
79" QUAGGA_COPYRIGHT "\r\n\
80\r\n";
81
ajs274a4a42004-12-07 15:39:31 +000082
83static struct facility_map {
84 int facility;
85 const char *name;
86 size_t match;
87} syslog_facilities[] =
88 {
89 { LOG_KERN, "kern", 1 },
90 { LOG_USER, "user", 2 },
91 { LOG_MAIL, "mail", 1 },
92 { LOG_DAEMON, "daemon", 1 },
93 { LOG_AUTH, "auth", 1 },
94 { LOG_SYSLOG, "syslog", 1 },
95 { LOG_LPR, "lpr", 2 },
96 { LOG_NEWS, "news", 1 },
97 { LOG_UUCP, "uucp", 2 },
98 { LOG_CRON, "cron", 1 },
99#ifdef LOG_FTP
100 { LOG_FTP, "ftp", 1 },
101#endif
102 { LOG_LOCAL0, "local0", 6 },
103 { LOG_LOCAL1, "local1", 6 },
104 { LOG_LOCAL2, "local2", 6 },
105 { LOG_LOCAL3, "local3", 6 },
106 { LOG_LOCAL4, "local4", 6 },
107 { LOG_LOCAL5, "local5", 6 },
108 { LOG_LOCAL6, "local6", 6 },
109 { LOG_LOCAL7, "local7", 6 },
110 { 0, NULL, 0 },
111 };
112
113static const char *
114facility_name(int facility)
115{
116 struct facility_map *fm;
117
118 for (fm = syslog_facilities; fm->name; fm++)
119 if (fm->facility == facility)
120 return fm->name;
121 return "";
122}
123
124static int
125facility_match(const char *str)
126{
127 struct facility_map *fm;
128
129 for (fm = syslog_facilities; fm->name; fm++)
130 if (!strncmp(str,fm->name,fm->match))
131 return fm->facility;
132 return -1;
133}
134
135static int
136level_match(const char *s)
137{
138 int level ;
139
140 for ( level = 0 ; zlog_priority [level] != NULL ; level ++ )
141 if (!strncmp (s, zlog_priority[level], 2))
142 return level;
143 return ZLOG_DISABLED;
144}
145
ajscb585b62005-01-14 17:09:38 +0000146/* This is called from main when a daemon is invoked with -v or --version. */
hasso6590f2c2004-10-19 20:40:08 +0000147void
148print_version (const char *progname)
149{
ajscb585b62005-01-14 17:09:38 +0000150 printf ("%s version %s\n", progname, QUAGGA_VERSION);
151 printf ("%s\n", QUAGGA_COPYRIGHT);
hasso6590f2c2004-10-19 20:40:08 +0000152}
153
paul718e3742002-12-13 20:15:29 +0000154
155/* Utility function to concatenate argv argument into a single string
156 with inserting ' ' character between each argument. */
157char *
paul42d49862004-10-13 05:22:18 +0000158argv_concat (const char **argv, int argc, int shift)
paul718e3742002-12-13 20:15:29 +0000159{
160 int i;
ajsf6834d42005-01-28 20:28:35 +0000161 size_t len;
paul718e3742002-12-13 20:15:29 +0000162 char *str;
ajsf6834d42005-01-28 20:28:35 +0000163 char *p;
paul718e3742002-12-13 20:15:29 +0000164
ajsf6834d42005-01-28 20:28:35 +0000165 len = 0;
166 for (i = shift; i < argc; i++)
167 len += strlen(argv[i])+1;
168 if (!len)
169 return NULL;
170 p = str = XMALLOC(MTYPE_TMP, len);
paul718e3742002-12-13 20:15:29 +0000171 for (i = shift; i < argc; i++)
172 {
ajsf6834d42005-01-28 20:28:35 +0000173 size_t arglen;
174 memcpy(p, argv[i], (arglen = strlen(argv[i])));
175 p += arglen;
176 *p++ = ' ';
paul718e3742002-12-13 20:15:29 +0000177 }
ajsf6834d42005-01-28 20:28:35 +0000178 *(p-1) = '\0';
paul718e3742002-12-13 20:15:29 +0000179 return str;
180}
181
182/* Install top node of command vector. */
183void
184install_node (struct cmd_node *node,
185 int (*func) (struct vty *))
186{
187 vector_set_index (cmdvec, node->node, node);
188 node->func = func;
189 node->cmd_vector = vector_init (VECTOR_MIN_SIZE);
190}
191
192/* Compare two command's string. Used in sort_node (). */
ajs274a4a42004-12-07 15:39:31 +0000193static int
paul718e3742002-12-13 20:15:29 +0000194cmp_node (const void *p, const void *q)
195{
paul8cc41982005-05-06 21:25:49 +0000196 const struct cmd_element *a = *(struct cmd_element **)p;
197 const struct cmd_element *b = *(struct cmd_element **)q;
paul718e3742002-12-13 20:15:29 +0000198
199 return strcmp (a->string, b->string);
200}
201
ajs274a4a42004-12-07 15:39:31 +0000202static int
paul718e3742002-12-13 20:15:29 +0000203cmp_desc (const void *p, const void *q)
204{
paul8cc41982005-05-06 21:25:49 +0000205 const struct desc *a = *(struct desc **)p;
206 const struct desc *b = *(struct desc **)q;
paul718e3742002-12-13 20:15:29 +0000207
208 return strcmp (a->cmd, b->cmd);
209}
210
211/* Sort each node's command element according to command string. */
212void
213sort_node ()
214{
hasso8c328f12004-10-05 21:01:23 +0000215 unsigned int i, j;
paul718e3742002-12-13 20:15:29 +0000216 struct cmd_node *cnode;
217 vector descvec;
218 struct cmd_element *cmd_element;
219
paul55468c82005-03-14 20:19:01 +0000220 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +0000221 if ((cnode = vector_slot (cmdvec, i)) != NULL)
222 {
223 vector cmd_vector = cnode->cmd_vector;
paul55468c82005-03-14 20:19:01 +0000224 qsort (cmd_vector->index, vector_active (cmd_vector),
paulb8961472005-03-14 17:35:52 +0000225 sizeof (void *), cmp_node);
paul718e3742002-12-13 20:15:29 +0000226
paul55468c82005-03-14 20:19:01 +0000227 for (j = 0; j < vector_active (cmd_vector); j++)
paulb8961472005-03-14 17:35:52 +0000228 if ((cmd_element = vector_slot (cmd_vector, j)) != NULL
paul55468c82005-03-14 20:19:01 +0000229 && vector_active (cmd_element->strvec))
paul718e3742002-12-13 20:15:29 +0000230 {
231 descvec = vector_slot (cmd_element->strvec,
paul55468c82005-03-14 20:19:01 +0000232 vector_active (cmd_element->strvec) - 1);
233 qsort (descvec->index, vector_active (descvec),
paulb8961472005-03-14 17:35:52 +0000234 sizeof (void *), cmp_desc);
paul718e3742002-12-13 20:15:29 +0000235 }
236 }
237}
238
239/* Breaking up string into each command piece. I assume given
240 character is separated by a space character. Return value is a
241 vector which includes char ** data element. */
242vector
hassoea8e9d92004-10-07 21:32:14 +0000243cmd_make_strvec (const char *string)
paul718e3742002-12-13 20:15:29 +0000244{
hassoea8e9d92004-10-07 21:32:14 +0000245 const char *cp, *start;
246 char *token;
paul718e3742002-12-13 20:15:29 +0000247 int strlen;
248 vector strvec;
249
250 if (string == NULL)
251 return NULL;
252
253 cp = string;
254
255 /* Skip white spaces. */
256 while (isspace ((int) *cp) && *cp != '\0')
257 cp++;
258
259 /* Return if there is only white spaces */
260 if (*cp == '\0')
261 return NULL;
262
263 if (*cp == '!' || *cp == '#')
264 return NULL;
265
266 /* Prepare return vector. */
267 strvec = vector_init (VECTOR_MIN_SIZE);
268
269 /* Copy each command piece and set into vector. */
270 while (1)
271 {
272 start = cp;
273 while (!(isspace ((int) *cp) || *cp == '\r' || *cp == '\n') &&
274 *cp != '\0')
275 cp++;
276 strlen = cp - start;
277 token = XMALLOC (MTYPE_STRVEC, strlen + 1);
278 memcpy (token, start, strlen);
279 *(token + strlen) = '\0';
280 vector_set (strvec, token);
281
282 while ((isspace ((int) *cp) || *cp == '\n' || *cp == '\r') &&
283 *cp != '\0')
284 cp++;
285
286 if (*cp == '\0')
287 return strvec;
288 }
289}
290
291/* Free allocated string vector. */
292void
293cmd_free_strvec (vector v)
294{
hasso8c328f12004-10-05 21:01:23 +0000295 unsigned int i;
paul718e3742002-12-13 20:15:29 +0000296 char *cp;
297
298 if (!v)
299 return;
300
paul55468c82005-03-14 20:19:01 +0000301 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +0000302 if ((cp = vector_slot (v, i)) != NULL)
303 XFREE (MTYPE_STRVEC, cp);
304
305 vector_free (v);
306}
307
308/* Fetch next description. Used in cmd_make_descvec(). */
ajs274a4a42004-12-07 15:39:31 +0000309static char *
hasso6ad96ea2004-10-07 19:33:46 +0000310cmd_desc_str (const char **string)
paul718e3742002-12-13 20:15:29 +0000311{
hasso6ad96ea2004-10-07 19:33:46 +0000312 const char *cp, *start;
313 char *token;
paul718e3742002-12-13 20:15:29 +0000314 int strlen;
315
316 cp = *string;
317
318 if (cp == NULL)
319 return NULL;
320
321 /* Skip white spaces. */
322 while (isspace ((int) *cp) && *cp != '\0')
323 cp++;
324
325 /* Return if there is only white spaces */
326 if (*cp == '\0')
327 return NULL;
328
329 start = cp;
330
331 while (!(*cp == '\r' || *cp == '\n') && *cp != '\0')
332 cp++;
333
334 strlen = cp - start;
335 token = XMALLOC (MTYPE_STRVEC, strlen + 1);
336 memcpy (token, start, strlen);
337 *(token + strlen) = '\0';
338
339 *string = cp;
340
341 return token;
342}
343
344/* New string vector. */
ajs274a4a42004-12-07 15:39:31 +0000345static vector
hasso8c328f12004-10-05 21:01:23 +0000346cmd_make_descvec (const char *string, const char *descstr)
paul718e3742002-12-13 20:15:29 +0000347{
348 int multiple = 0;
hasso8c328f12004-10-05 21:01:23 +0000349 const char *sp;
paul718e3742002-12-13 20:15:29 +0000350 char *token;
351 int len;
hasso8c328f12004-10-05 21:01:23 +0000352 const char *cp;
353 const char *dp;
paul718e3742002-12-13 20:15:29 +0000354 vector allvec;
355 vector strvec = NULL;
356 struct desc *desc;
357
358 cp = string;
359 dp = descstr;
360
361 if (cp == NULL)
362 return NULL;
363
364 allvec = vector_init (VECTOR_MIN_SIZE);
365
366 while (1)
367 {
368 while (isspace ((int) *cp) && *cp != '\0')
369 cp++;
370
371 if (*cp == '(')
372 {
373 multiple = 1;
374 cp++;
375 }
376 if (*cp == ')')
377 {
378 multiple = 0;
379 cp++;
380 }
381 if (*cp == '|')
382 {
383 if (! multiple)
384 {
385 fprintf (stderr, "Command parse error!: %s\n", string);
386 exit (1);
387 }
388 cp++;
389 }
390
391 while (isspace ((int) *cp) && *cp != '\0')
392 cp++;
393
394 if (*cp == '(')
395 {
396 multiple = 1;
397 cp++;
398 }
399
400 if (*cp == '\0')
401 return allvec;
402
403 sp = cp;
404
405 while (! (isspace ((int) *cp) || *cp == '\r' || *cp == '\n' || *cp == ')' || *cp == '|') && *cp != '\0')
406 cp++;
407
408 len = cp - sp;
409
410 token = XMALLOC (MTYPE_STRVEC, len + 1);
411 memcpy (token, sp, len);
412 *(token + len) = '\0';
413
414 desc = XCALLOC (MTYPE_DESC, sizeof (struct desc));
415 desc->cmd = token;
416 desc->str = cmd_desc_str (&dp);
417
418 if (multiple)
419 {
420 if (multiple == 1)
421 {
422 strvec = vector_init (VECTOR_MIN_SIZE);
423 vector_set (allvec, strvec);
424 }
425 multiple++;
426 }
427 else
428 {
429 strvec = vector_init (VECTOR_MIN_SIZE);
430 vector_set (allvec, strvec);
431 }
432 vector_set (strvec, desc);
433 }
434}
435
436/* Count mandantory string vector size. This is to determine inputed
437 command has enough command length. */
ajs274a4a42004-12-07 15:39:31 +0000438static int
paul718e3742002-12-13 20:15:29 +0000439cmd_cmdsize (vector strvec)
440{
hasso8c328f12004-10-05 21:01:23 +0000441 unsigned int i;
paul718e3742002-12-13 20:15:29 +0000442 int size = 0;
443 vector descvec;
paulb8961472005-03-14 17:35:52 +0000444 struct desc *desc;
paul718e3742002-12-13 20:15:29 +0000445
paul55468c82005-03-14 20:19:01 +0000446 for (i = 0; i < vector_active (strvec); i++)
paulb8961472005-03-14 17:35:52 +0000447 if ((descvec = vector_slot (strvec, i)) != NULL)
paul718e3742002-12-13 20:15:29 +0000448 {
paul55468c82005-03-14 20:19:01 +0000449 if ((vector_active (descvec)) == 1
paulb8961472005-03-14 17:35:52 +0000450 && (desc = vector_slot (descvec, 0)) != NULL)
paul718e3742002-12-13 20:15:29 +0000451 {
hasso8c328f12004-10-05 21:01:23 +0000452 if (desc->cmd == NULL || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +0000453 return size;
454 else
455 size++;
456 }
457 else
458 size++;
459 }
460 return size;
461}
462
463/* Return prompt character of specified node. */
hasso8c328f12004-10-05 21:01:23 +0000464const char *
paul718e3742002-12-13 20:15:29 +0000465cmd_prompt (enum node_type node)
466{
467 struct cmd_node *cnode;
468
469 cnode = vector_slot (cmdvec, node);
470 return cnode->prompt;
471}
472
473/* Install a command into a node. */
474void
475install_element (enum node_type ntype, struct cmd_element *cmd)
476{
477 struct cmd_node *cnode;
pauleb820af2005-09-05 11:54:13 +0000478
479 /* cmd_init hasn't been called */
480 if (!cmdvec)
481 return;
482
paul718e3742002-12-13 20:15:29 +0000483 cnode = vector_slot (cmdvec, ntype);
484
485 if (cnode == NULL)
486 {
487 fprintf (stderr, "Command node %d doesn't exist, please check it\n",
488 ntype);
489 exit (1);
490 }
491
492 vector_set (cnode->cmd_vector, cmd);
493
494 cmd->strvec = cmd_make_descvec (cmd->string, cmd->doc);
495 cmd->cmdsize = cmd_cmdsize (cmd->strvec);
496}
497
498static unsigned char itoa64[] =
499"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
500
ajs274a4a42004-12-07 15:39:31 +0000501static void
paul718e3742002-12-13 20:15:29 +0000502to64(char *s, long v, int n)
503{
504 while (--n >= 0)
505 {
506 *s++ = itoa64[v&0x3f];
507 v >>= 6;
508 }
509}
510
ajs274a4a42004-12-07 15:39:31 +0000511static char *
512zencrypt (const char *passwd)
paul718e3742002-12-13 20:15:29 +0000513{
514 char salt[6];
515 struct timeval tv;
516 char *crypt (const char *, const char *);
517
518 gettimeofday(&tv,0);
519
520 to64(&salt[0], random(), 3);
521 to64(&salt[3], tv.tv_usec, 3);
522 salt[5] = '\0';
523
524 return crypt (passwd, salt);
525}
526
527/* This function write configuration of this host. */
ajs274a4a42004-12-07 15:39:31 +0000528static int
paul718e3742002-12-13 20:15:29 +0000529config_write_host (struct vty *vty)
530{
531 if (host.name)
532 vty_out (vty, "hostname %s%s", host.name, VTY_NEWLINE);
533
534 if (host.encrypt)
535 {
536 if (host.password_encrypt)
537 vty_out (vty, "password 8 %s%s", host.password_encrypt, VTY_NEWLINE);
538 if (host.enable_encrypt)
539 vty_out (vty, "enable password 8 %s%s", host.enable_encrypt, VTY_NEWLINE);
540 }
541 else
542 {
543 if (host.password)
544 vty_out (vty, "password %s%s", host.password, VTY_NEWLINE);
545 if (host.enable)
546 vty_out (vty, "enable password %s%s", host.enable, VTY_NEWLINE);
547 }
548
ajs274a4a42004-12-07 15:39:31 +0000549 if (zlog_default->default_lvl != LOG_DEBUG)
ajs82146b82004-12-07 17:15:55 +0000550 {
551 vty_out (vty, "! N.B. The 'log trap' command is deprecated.%s",
552 VTY_NEWLINE);
553 vty_out (vty, "log trap %s%s",
554 zlog_priority[zlog_default->default_lvl], VTY_NEWLINE);
555 }
paul718e3742002-12-13 20:15:29 +0000556
ajs274a4a42004-12-07 15:39:31 +0000557 if (host.logfile && (zlog_default->maxlvl[ZLOG_DEST_FILE] != ZLOG_DISABLED))
paul12ab19f2003-07-26 06:14:55 +0000558 {
ajs274a4a42004-12-07 15:39:31 +0000559 vty_out (vty, "log file %s", host.logfile);
560 if (zlog_default->maxlvl[ZLOG_DEST_FILE] != zlog_default->default_lvl)
561 vty_out (vty, " %s",
562 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_FILE]]);
paul12ab19f2003-07-26 06:14:55 +0000563 vty_out (vty, "%s", VTY_NEWLINE);
564 }
ajs274a4a42004-12-07 15:39:31 +0000565
566 if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != ZLOG_DISABLED)
567 {
568 vty_out (vty, "log stdout");
569 if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != zlog_default->default_lvl)
570 vty_out (vty, " %s",
571 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_STDOUT]]);
572 vty_out (vty, "%s", VTY_NEWLINE);
573 }
574
575 if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
576 vty_out(vty,"no log monitor%s",VTY_NEWLINE);
577 else if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] != zlog_default->default_lvl)
578 vty_out(vty,"log monitor %s%s",
579 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_MONITOR]],VTY_NEWLINE);
580
581 if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED)
582 {
583 vty_out (vty, "log syslog");
584 if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != zlog_default->default_lvl)
585 vty_out (vty, " %s",
586 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_SYSLOG]]);
587 vty_out (vty, "%s", VTY_NEWLINE);
588 }
589
590 if (zlog_default->facility != LOG_DAEMON)
591 vty_out (vty, "log facility %s%s",
592 facility_name(zlog_default->facility), VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +0000593
594 if (zlog_default->record_priority == 1)
595 vty_out (vty, "log record-priority%s", VTY_NEWLINE);
596
597 if (host.advanced)
598 vty_out (vty, "service advanced-vty%s", VTY_NEWLINE);
599
600 if (host.encrypt)
601 vty_out (vty, "service password-encryption%s", VTY_NEWLINE);
602
603 if (host.lines >= 0)
604 vty_out (vty, "service terminal-length %d%s", host.lines,
605 VTY_NEWLINE);
606
paul3b0c5d92005-03-08 10:43:43 +0000607 if (host.motdfile)
608 vty_out (vty, "banner motd file %s%s", host.motdfile, VTY_NEWLINE);
609 else if (! host.motd)
paul718e3742002-12-13 20:15:29 +0000610 vty_out (vty, "no banner motd%s", VTY_NEWLINE);
611
612 return 1;
613}
614
615/* Utility function for getting command vector. */
ajs274a4a42004-12-07 15:39:31 +0000616static vector
paul718e3742002-12-13 20:15:29 +0000617cmd_node_vector (vector v, enum node_type ntype)
618{
619 struct cmd_node *cnode = vector_slot (v, ntype);
620 return cnode->cmd_vector;
621}
622
ajs274a4a42004-12-07 15:39:31 +0000623#if 0
624/* Filter command vector by symbol. This function is not actually used;
625 * should it be deleted? */
626static int
paul718e3742002-12-13 20:15:29 +0000627cmd_filter_by_symbol (char *command, char *symbol)
628{
629 int i, lim;
630
631 if (strcmp (symbol, "IPV4_ADDRESS") == 0)
632 {
633 i = 0;
634 lim = strlen (command);
635 while (i < lim)
636 {
637 if (! (isdigit ((int) command[i]) || command[i] == '.' || command[i] == '/'))
638 return 1;
639 i++;
640 }
641 return 0;
642 }
643 if (strcmp (symbol, "STRING") == 0)
644 {
645 i = 0;
646 lim = strlen (command);
647 while (i < lim)
648 {
649 if (! (isalpha ((int) command[i]) || command[i] == '_' || command[i] == '-'))
650 return 1;
651 i++;
652 }
653 return 0;
654 }
655 if (strcmp (symbol, "IFNAME") == 0)
656 {
657 i = 0;
658 lim = strlen (command);
659 while (i < lim)
660 {
661 if (! isalnum ((int) command[i]))
662 return 1;
663 i++;
664 }
665 return 0;
666 }
667 return 0;
668}
ajs274a4a42004-12-07 15:39:31 +0000669#endif
paul718e3742002-12-13 20:15:29 +0000670
671/* Completion match types. */
672enum match_type
673{
674 no_match,
675 extend_match,
676 ipv4_prefix_match,
677 ipv4_match,
678 ipv6_prefix_match,
679 ipv6_match,
680 range_match,
681 vararg_match,
682 partly_match,
683 exact_match
684};
685
ajs274a4a42004-12-07 15:39:31 +0000686static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000687cmd_ipv4_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000688{
hasso8c328f12004-10-05 21:01:23 +0000689 const char *sp;
paul718e3742002-12-13 20:15:29 +0000690 int dots = 0, nums = 0;
691 char buf[4];
692
693 if (str == NULL)
694 return partly_match;
695
696 for (;;)
697 {
698 memset (buf, 0, sizeof (buf));
699 sp = str;
700 while (*str != '\0')
701 {
702 if (*str == '.')
703 {
704 if (dots >= 3)
705 return no_match;
706
707 if (*(str + 1) == '.')
708 return no_match;
709
710 if (*(str + 1) == '\0')
711 return partly_match;
712
713 dots++;
714 break;
715 }
716 if (!isdigit ((int) *str))
717 return no_match;
718
719 str++;
720 }
721
722 if (str - sp > 3)
723 return no_match;
724
725 strncpy (buf, sp, str - sp);
726 if (atoi (buf) > 255)
727 return no_match;
728
729 nums++;
730
731 if (*str == '\0')
732 break;
733
734 str++;
735 }
736
737 if (nums < 4)
738 return partly_match;
739
740 return exact_match;
741}
742
ajs274a4a42004-12-07 15:39:31 +0000743static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000744cmd_ipv4_prefix_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000745{
hasso8c328f12004-10-05 21:01:23 +0000746 const char *sp;
paul718e3742002-12-13 20:15:29 +0000747 int dots = 0;
748 char buf[4];
749
750 if (str == NULL)
751 return partly_match;
752
753 for (;;)
754 {
755 memset (buf, 0, sizeof (buf));
756 sp = str;
757 while (*str != '\0' && *str != '/')
758 {
759 if (*str == '.')
760 {
761 if (dots == 3)
762 return no_match;
763
764 if (*(str + 1) == '.' || *(str + 1) == '/')
765 return no_match;
766
767 if (*(str + 1) == '\0')
768 return partly_match;
769
770 dots++;
771 break;
772 }
773
774 if (!isdigit ((int) *str))
775 return no_match;
776
777 str++;
778 }
779
780 if (str - sp > 3)
781 return no_match;
782
783 strncpy (buf, sp, str - sp);
784 if (atoi (buf) > 255)
785 return no_match;
786
787 if (dots == 3)
788 {
789 if (*str == '/')
790 {
791 if (*(str + 1) == '\0')
792 return partly_match;
793
794 str++;
795 break;
796 }
797 else if (*str == '\0')
798 return partly_match;
799 }
800
801 if (*str == '\0')
802 return partly_match;
803
804 str++;
805 }
806
807 sp = str;
808 while (*str != '\0')
809 {
810 if (!isdigit ((int) *str))
811 return no_match;
812
813 str++;
814 }
815
816 if (atoi (sp) > 32)
817 return no_match;
818
819 return exact_match;
820}
821
822#define IPV6_ADDR_STR "0123456789abcdefABCDEF:.%"
823#define IPV6_PREFIX_STR "0123456789abcdefABCDEF:.%/"
824#define STATE_START 1
825#define STATE_COLON 2
826#define STATE_DOUBLE 3
827#define STATE_ADDR 4
828#define STATE_DOT 5
829#define STATE_SLASH 6
830#define STATE_MASK 7
831
paul22e0a9e2003-07-11 17:55:46 +0000832#ifdef HAVE_IPV6
833
ajs274a4a42004-12-07 15:39:31 +0000834static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000835cmd_ipv6_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000836{
837 int state = STATE_START;
838 int colons = 0, nums = 0, double_colon = 0;
hasso8c328f12004-10-05 21:01:23 +0000839 const char *sp = NULL;
hasso726f9b22003-05-25 21:04:54 +0000840 struct sockaddr_in6 sin6_dummy;
841 int ret;
paul718e3742002-12-13 20:15:29 +0000842
843 if (str == NULL)
844 return partly_match;
845
846 if (strspn (str, IPV6_ADDR_STR) != strlen (str))
847 return no_match;
848
hasso726f9b22003-05-25 21:04:54 +0000849 /* use inet_pton that has a better support,
850 * for example inet_pton can support the automatic addresses:
851 * ::1.2.3.4
852 */
853 ret = inet_pton(AF_INET6, str, &sin6_dummy.sin6_addr);
854
855 if (ret == 1)
856 return exact_match;
857
paul718e3742002-12-13 20:15:29 +0000858 while (*str != '\0')
859 {
860 switch (state)
861 {
862 case STATE_START:
863 if (*str == ':')
864 {
865 if (*(str + 1) != ':' && *(str + 1) != '\0')
866 return no_match;
867 colons--;
868 state = STATE_COLON;
869 }
870 else
871 {
872 sp = str;
873 state = STATE_ADDR;
874 }
875
876 continue;
877 case STATE_COLON:
878 colons++;
879 if (*(str + 1) == ':')
880 state = STATE_DOUBLE;
881 else
882 {
883 sp = str + 1;
884 state = STATE_ADDR;
885 }
886 break;
887 case STATE_DOUBLE:
888 if (double_colon)
889 return no_match;
890
891 if (*(str + 1) == ':')
892 return no_match;
893 else
894 {
895 if (*(str + 1) != '\0')
896 colons++;
897 sp = str + 1;
898 state = STATE_ADDR;
899 }
900
901 double_colon++;
902 nums++;
903 break;
904 case STATE_ADDR:
905 if (*(str + 1) == ':' || *(str + 1) == '\0')
906 {
907 if (str - sp > 3)
908 return no_match;
909
910 nums++;
911 state = STATE_COLON;
912 }
913 if (*(str + 1) == '.')
914 state = STATE_DOT;
915 break;
916 case STATE_DOT:
917 state = STATE_ADDR;
918 break;
919 default:
920 break;
921 }
922
923 if (nums > 8)
924 return no_match;
925
926 if (colons > 7)
927 return no_match;
928
929 str++;
930 }
931
932#if 0
933 if (nums < 11)
934 return partly_match;
935#endif /* 0 */
936
937 return exact_match;
938}
939
ajs274a4a42004-12-07 15:39:31 +0000940static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000941cmd_ipv6_prefix_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000942{
943 int state = STATE_START;
944 int colons = 0, nums = 0, double_colon = 0;
945 int mask;
hasso8c328f12004-10-05 21:01:23 +0000946 const char *sp = NULL;
paul718e3742002-12-13 20:15:29 +0000947 char *endptr = NULL;
948
949 if (str == NULL)
950 return partly_match;
951
952 if (strspn (str, IPV6_PREFIX_STR) != strlen (str))
953 return no_match;
954
955 while (*str != '\0' && state != STATE_MASK)
956 {
957 switch (state)
958 {
959 case STATE_START:
960 if (*str == ':')
961 {
962 if (*(str + 1) != ':' && *(str + 1) != '\0')
963 return no_match;
964 colons--;
965 state = STATE_COLON;
966 }
967 else
968 {
969 sp = str;
970 state = STATE_ADDR;
971 }
972
973 continue;
974 case STATE_COLON:
975 colons++;
976 if (*(str + 1) == '/')
977 return no_match;
978 else if (*(str + 1) == ':')
979 state = STATE_DOUBLE;
980 else
981 {
982 sp = str + 1;
983 state = STATE_ADDR;
984 }
985 break;
986 case STATE_DOUBLE:
987 if (double_colon)
988 return no_match;
989
990 if (*(str + 1) == ':')
991 return no_match;
992 else
993 {
994 if (*(str + 1) != '\0' && *(str + 1) != '/')
995 colons++;
996 sp = str + 1;
997
998 if (*(str + 1) == '/')
999 state = STATE_SLASH;
1000 else
1001 state = STATE_ADDR;
1002 }
1003
1004 double_colon++;
1005 nums += 1;
1006 break;
1007 case STATE_ADDR:
1008 if (*(str + 1) == ':' || *(str + 1) == '.'
1009 || *(str + 1) == '\0' || *(str + 1) == '/')
1010 {
1011 if (str - sp > 3)
1012 return no_match;
1013
1014 for (; sp <= str; sp++)
1015 if (*sp == '/')
1016 return no_match;
1017
1018 nums++;
1019
1020 if (*(str + 1) == ':')
1021 state = STATE_COLON;
1022 else if (*(str + 1) == '.')
1023 state = STATE_DOT;
1024 else if (*(str + 1) == '/')
1025 state = STATE_SLASH;
1026 }
1027 break;
1028 case STATE_DOT:
1029 state = STATE_ADDR;
1030 break;
1031 case STATE_SLASH:
1032 if (*(str + 1) == '\0')
1033 return partly_match;
1034
1035 state = STATE_MASK;
1036 break;
1037 default:
1038 break;
1039 }
1040
1041 if (nums > 11)
1042 return no_match;
1043
1044 if (colons > 7)
1045 return no_match;
1046
1047 str++;
1048 }
1049
1050 if (state < STATE_MASK)
1051 return partly_match;
1052
1053 mask = strtol (str, &endptr, 10);
1054 if (*endptr != '\0')
1055 return no_match;
1056
1057 if (mask < 0 || mask > 128)
1058 return no_match;
1059
1060/* I don't know why mask < 13 makes command match partly.
1061 Forgive me to make this comments. I Want to set static default route
1062 because of lack of function to originate default in ospf6d; sorry
1063 yasu
1064 if (mask < 13)
1065 return partly_match;
1066*/
1067
1068 return exact_match;
1069}
1070
paul22e0a9e2003-07-11 17:55:46 +00001071#endif /* HAVE_IPV6 */
1072
paul718e3742002-12-13 20:15:29 +00001073#define DECIMAL_STRLEN_MAX 10
1074
ajs274a4a42004-12-07 15:39:31 +00001075static int
hasso8c328f12004-10-05 21:01:23 +00001076cmd_range_match (const char *range, const char *str)
paul718e3742002-12-13 20:15:29 +00001077{
1078 char *p;
1079 char buf[DECIMAL_STRLEN_MAX + 1];
1080 char *endptr = NULL;
1081 unsigned long min, max, val;
1082
1083 if (str == NULL)
1084 return 1;
1085
1086 val = strtoul (str, &endptr, 10);
1087 if (*endptr != '\0')
1088 return 0;
1089
1090 range++;
1091 p = strchr (range, '-');
1092 if (p == NULL)
1093 return 0;
1094 if (p - range > DECIMAL_STRLEN_MAX)
1095 return 0;
1096 strncpy (buf, range, p - range);
1097 buf[p - range] = '\0';
1098 min = strtoul (buf, &endptr, 10);
1099 if (*endptr != '\0')
1100 return 0;
1101
1102 range = p + 1;
1103 p = strchr (range, '>');
1104 if (p == NULL)
1105 return 0;
1106 if (p - range > DECIMAL_STRLEN_MAX)
1107 return 0;
1108 strncpy (buf, range, p - range);
1109 buf[p - range] = '\0';
1110 max = strtoul (buf, &endptr, 10);
1111 if (*endptr != '\0')
1112 return 0;
1113
1114 if (val < min || val > max)
1115 return 0;
1116
1117 return 1;
1118}
1119
1120/* Make completion match and return match type flag. */
ajs274a4a42004-12-07 15:39:31 +00001121static enum match_type
hasso8c328f12004-10-05 21:01:23 +00001122cmd_filter_by_completion (char *command, vector v, unsigned int index)
paul718e3742002-12-13 20:15:29 +00001123{
hasso8c328f12004-10-05 21:01:23 +00001124 unsigned int i;
1125 const char *str;
paul718e3742002-12-13 20:15:29 +00001126 struct cmd_element *cmd_element;
1127 enum match_type match_type;
1128 vector descvec;
1129 struct desc *desc;
paul909a2152005-03-14 17:41:45 +00001130
paul718e3742002-12-13 20:15:29 +00001131 match_type = no_match;
1132
1133 /* If command and cmd_element string does not match set NULL to vector */
paul55468c82005-03-14 20:19:01 +00001134 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001135 if ((cmd_element = vector_slot (v, i)) != NULL)
1136 {
paul55468c82005-03-14 20:19:01 +00001137 if (index >= vector_active (cmd_element->strvec))
paul718e3742002-12-13 20:15:29 +00001138 vector_slot (v, i) = NULL;
1139 else
1140 {
hasso8c328f12004-10-05 21:01:23 +00001141 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001142 int matched = 0;
1143
1144 descvec = vector_slot (cmd_element->strvec, index);
paul909a2152005-03-14 17:41:45 +00001145
paul55468c82005-03-14 20:19:01 +00001146 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001147 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001148 {
1149 str = desc->cmd;
1150
1151 if (CMD_VARARG (str))
1152 {
1153 if (match_type < vararg_match)
1154 match_type = vararg_match;
1155 matched++;
1156 }
1157 else if (CMD_RANGE (str))
1158 {
1159 if (cmd_range_match (str, command))
1160 {
1161 if (match_type < range_match)
1162 match_type = range_match;
paul718e3742002-12-13 20:15:29 +00001163
paul909a2152005-03-14 17:41:45 +00001164 matched++;
1165 }
1166 }
paul22e0a9e2003-07-11 17:55:46 +00001167#ifdef HAVE_IPV6
paul909a2152005-03-14 17:41:45 +00001168 else if (CMD_IPV6 (str))
1169 {
1170 if (cmd_ipv6_match (command))
1171 {
1172 if (match_type < ipv6_match)
1173 match_type = ipv6_match;
paul718e3742002-12-13 20:15:29 +00001174
paul909a2152005-03-14 17:41:45 +00001175 matched++;
1176 }
1177 }
1178 else if (CMD_IPV6_PREFIX (str))
1179 {
1180 if (cmd_ipv6_prefix_match (command))
1181 {
1182 if (match_type < ipv6_prefix_match)
1183 match_type = ipv6_prefix_match;
paul718e3742002-12-13 20:15:29 +00001184
paul909a2152005-03-14 17:41:45 +00001185 matched++;
1186 }
1187 }
1188#endif /* HAVE_IPV6 */
1189 else if (CMD_IPV4 (str))
1190 {
1191 if (cmd_ipv4_match (command))
1192 {
1193 if (match_type < ipv4_match)
1194 match_type = ipv4_match;
paul718e3742002-12-13 20:15:29 +00001195
paul909a2152005-03-14 17:41:45 +00001196 matched++;
1197 }
1198 }
1199 else if (CMD_IPV4_PREFIX (str))
1200 {
1201 if (cmd_ipv4_prefix_match (command))
1202 {
1203 if (match_type < ipv4_prefix_match)
1204 match_type = ipv4_prefix_match;
1205 matched++;
1206 }
1207 }
1208 else
1209 /* Check is this point's argument optional ? */
1210 if (CMD_OPTION (str) || CMD_VARIABLE (str))
1211 {
1212 if (match_type < extend_match)
1213 match_type = extend_match;
1214 matched++;
1215 }
1216 else if (strncmp (command, str, strlen (command)) == 0)
1217 {
1218 if (strcmp (command, str) == 0)
1219 match_type = exact_match;
1220 else
1221 {
1222 if (match_type < partly_match)
1223 match_type = partly_match;
1224 }
1225 matched++;
1226 }
1227 }
1228 if (!matched)
paul718e3742002-12-13 20:15:29 +00001229 vector_slot (v, i) = NULL;
1230 }
1231 }
1232 return match_type;
1233}
1234
1235/* Filter vector by command character with index. */
ajs274a4a42004-12-07 15:39:31 +00001236static enum match_type
hasso8c328f12004-10-05 21:01:23 +00001237cmd_filter_by_string (char *command, vector v, unsigned int index)
paul718e3742002-12-13 20:15:29 +00001238{
hasso8c328f12004-10-05 21:01:23 +00001239 unsigned int i;
1240 const char *str;
paul718e3742002-12-13 20:15:29 +00001241 struct cmd_element *cmd_element;
1242 enum match_type match_type;
1243 vector descvec;
1244 struct desc *desc;
paul909a2152005-03-14 17:41:45 +00001245
paul718e3742002-12-13 20:15:29 +00001246 match_type = no_match;
1247
1248 /* If command and cmd_element string does not match set NULL to vector */
paul55468c82005-03-14 20:19:01 +00001249 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001250 if ((cmd_element = vector_slot (v, i)) != NULL)
1251 {
1252 /* If given index is bigger than max string vector of command,
paul909a2152005-03-14 17:41:45 +00001253 set NULL */
paul55468c82005-03-14 20:19:01 +00001254 if (index >= vector_active (cmd_element->strvec))
paul718e3742002-12-13 20:15:29 +00001255 vector_slot (v, i) = NULL;
paul909a2152005-03-14 17:41:45 +00001256 else
paul718e3742002-12-13 20:15:29 +00001257 {
hasso8c328f12004-10-05 21:01:23 +00001258 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001259 int matched = 0;
1260
1261 descvec = vector_slot (cmd_element->strvec, index);
1262
paul55468c82005-03-14 20:19:01 +00001263 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001264 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001265 {
1266 str = desc->cmd;
paul718e3742002-12-13 20:15:29 +00001267
paul909a2152005-03-14 17:41:45 +00001268 if (CMD_VARARG (str))
1269 {
1270 if (match_type < vararg_match)
1271 match_type = vararg_match;
1272 matched++;
1273 }
1274 else if (CMD_RANGE (str))
1275 {
1276 if (cmd_range_match (str, command))
1277 {
1278 if (match_type < range_match)
1279 match_type = range_match;
1280 matched++;
1281 }
1282 }
paul22e0a9e2003-07-11 17:55:46 +00001283#ifdef HAVE_IPV6
paul909a2152005-03-14 17:41:45 +00001284 else if (CMD_IPV6 (str))
1285 {
1286 if (cmd_ipv6_match (command) == exact_match)
1287 {
1288 if (match_type < ipv6_match)
1289 match_type = ipv6_match;
1290 matched++;
1291 }
1292 }
1293 else if (CMD_IPV6_PREFIX (str))
1294 {
1295 if (cmd_ipv6_prefix_match (command) == exact_match)
1296 {
1297 if (match_type < ipv6_prefix_match)
1298 match_type = ipv6_prefix_match;
1299 matched++;
1300 }
1301 }
paul22e0a9e2003-07-11 17:55:46 +00001302#endif /* HAVE_IPV6 */
paul909a2152005-03-14 17:41:45 +00001303 else if (CMD_IPV4 (str))
1304 {
1305 if (cmd_ipv4_match (command) == exact_match)
1306 {
1307 if (match_type < ipv4_match)
1308 match_type = ipv4_match;
1309 matched++;
1310 }
1311 }
1312 else if (CMD_IPV4_PREFIX (str))
1313 {
1314 if (cmd_ipv4_prefix_match (command) == exact_match)
1315 {
1316 if (match_type < ipv4_prefix_match)
1317 match_type = ipv4_prefix_match;
1318 matched++;
1319 }
1320 }
1321 else if (CMD_OPTION (str) || CMD_VARIABLE (str))
1322 {
1323 if (match_type < extend_match)
1324 match_type = extend_match;
1325 matched++;
1326 }
1327 else
1328 {
1329 if (strcmp (command, str) == 0)
1330 {
1331 match_type = exact_match;
1332 matched++;
1333 }
1334 }
1335 }
1336 if (!matched)
paul718e3742002-12-13 20:15:29 +00001337 vector_slot (v, i) = NULL;
1338 }
1339 }
1340 return match_type;
1341}
1342
1343/* Check ambiguous match */
ajs274a4a42004-12-07 15:39:31 +00001344static int
paul718e3742002-12-13 20:15:29 +00001345is_cmd_ambiguous (char *command, vector v, int index, enum match_type type)
1346{
hasso8c328f12004-10-05 21:01:23 +00001347 unsigned int i;
1348 unsigned int j;
1349 const char *str = NULL;
paul718e3742002-12-13 20:15:29 +00001350 struct cmd_element *cmd_element;
hasso8c328f12004-10-05 21:01:23 +00001351 const char *matched = NULL;
paul718e3742002-12-13 20:15:29 +00001352 vector descvec;
1353 struct desc *desc;
paul909a2152005-03-14 17:41:45 +00001354
paul55468c82005-03-14 20:19:01 +00001355 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001356 if ((cmd_element = vector_slot (v, i)) != NULL)
1357 {
1358 int match = 0;
1359
1360 descvec = vector_slot (cmd_element->strvec, index);
1361
paul55468c82005-03-14 20:19:01 +00001362 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001363 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001364 {
1365 enum match_type ret;
1366
1367 str = desc->cmd;
paul718e3742002-12-13 20:15:29 +00001368
paul909a2152005-03-14 17:41:45 +00001369 switch (type)
1370 {
1371 case exact_match:
1372 if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
1373 && strcmp (command, str) == 0)
1374 match++;
1375 break;
1376 case partly_match:
1377 if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
1378 && strncmp (command, str, strlen (command)) == 0)
1379 {
1380 if (matched && strcmp (matched, str) != 0)
1381 return 1; /* There is ambiguous match. */
1382 else
1383 matched = str;
1384 match++;
1385 }
1386 break;
1387 case range_match:
1388 if (cmd_range_match (str, command))
1389 {
1390 if (matched && strcmp (matched, str) != 0)
1391 return 1;
1392 else
1393 matched = str;
1394 match++;
1395 }
1396 break;
1397#ifdef HAVE_IPV6
1398 case ipv6_match:
1399 if (CMD_IPV6 (str))
1400 match++;
1401 break;
1402 case ipv6_prefix_match:
1403 if ((ret = cmd_ipv6_prefix_match (command)) != no_match)
1404 {
1405 if (ret == partly_match)
1406 return 2; /* There is incomplete match. */
paul718e3742002-12-13 20:15:29 +00001407
paul909a2152005-03-14 17:41:45 +00001408 match++;
1409 }
1410 break;
1411#endif /* HAVE_IPV6 */
1412 case ipv4_match:
1413 if (CMD_IPV4 (str))
paul718e3742002-12-13 20:15:29 +00001414 match++;
paul909a2152005-03-14 17:41:45 +00001415 break;
1416 case ipv4_prefix_match:
1417 if ((ret = cmd_ipv4_prefix_match (command)) != no_match)
1418 {
1419 if (ret == partly_match)
1420 return 2; /* There is incomplete match. */
paul718e3742002-12-13 20:15:29 +00001421
paul909a2152005-03-14 17:41:45 +00001422 match++;
1423 }
1424 break;
1425 case extend_match:
1426 if (CMD_OPTION (str) || CMD_VARIABLE (str))
paul718e3742002-12-13 20:15:29 +00001427 match++;
paul909a2152005-03-14 17:41:45 +00001428 break;
1429 case no_match:
1430 default:
1431 break;
1432 }
1433 }
1434 if (!match)
paul718e3742002-12-13 20:15:29 +00001435 vector_slot (v, i) = NULL;
1436 }
1437 return 0;
1438}
1439
1440/* If src matches dst return dst string, otherwise return NULL */
ajs274a4a42004-12-07 15:39:31 +00001441static const char *
hasso8c328f12004-10-05 21:01:23 +00001442cmd_entry_function (const char *src, const char *dst)
paul718e3742002-12-13 20:15:29 +00001443{
1444 /* Skip variable arguments. */
1445 if (CMD_OPTION (dst) || CMD_VARIABLE (dst) || CMD_VARARG (dst) ||
1446 CMD_IPV4 (dst) || CMD_IPV4_PREFIX (dst) || CMD_RANGE (dst))
1447 return NULL;
1448
1449 /* In case of 'command \t', given src is NULL string. */
1450 if (src == NULL)
1451 return dst;
1452
1453 /* Matched with input string. */
1454 if (strncmp (src, dst, strlen (src)) == 0)
1455 return dst;
1456
1457 return NULL;
1458}
1459
1460/* If src matches dst return dst string, otherwise return NULL */
1461/* This version will return the dst string always if it is
1462 CMD_VARIABLE for '?' key processing */
ajs274a4a42004-12-07 15:39:31 +00001463static const char *
hasso8c328f12004-10-05 21:01:23 +00001464cmd_entry_function_desc (const char *src, const char *dst)
paul718e3742002-12-13 20:15:29 +00001465{
1466 if (CMD_VARARG (dst))
1467 return dst;
1468
1469 if (CMD_RANGE (dst))
1470 {
1471 if (cmd_range_match (dst, src))
1472 return dst;
1473 else
1474 return NULL;
1475 }
1476
paul22e0a9e2003-07-11 17:55:46 +00001477#ifdef HAVE_IPV6
paul718e3742002-12-13 20:15:29 +00001478 if (CMD_IPV6 (dst))
1479 {
1480 if (cmd_ipv6_match (src))
1481 return dst;
1482 else
1483 return NULL;
1484 }
1485
1486 if (CMD_IPV6_PREFIX (dst))
1487 {
1488 if (cmd_ipv6_prefix_match (src))
1489 return dst;
1490 else
1491 return NULL;
1492 }
paul22e0a9e2003-07-11 17:55:46 +00001493#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +00001494
1495 if (CMD_IPV4 (dst))
1496 {
1497 if (cmd_ipv4_match (src))
1498 return dst;
1499 else
1500 return NULL;
1501 }
1502
1503 if (CMD_IPV4_PREFIX (dst))
1504 {
1505 if (cmd_ipv4_prefix_match (src))
1506 return dst;
1507 else
1508 return NULL;
1509 }
1510
1511 /* Optional or variable commands always match on '?' */
1512 if (CMD_OPTION (dst) || CMD_VARIABLE (dst))
1513 return dst;
1514
1515 /* In case of 'command \t', given src is NULL string. */
1516 if (src == NULL)
1517 return dst;
1518
1519 if (strncmp (src, dst, strlen (src)) == 0)
1520 return dst;
1521 else
1522 return NULL;
1523}
1524
1525/* Check same string element existence. If it isn't there return
1526 1. */
ajs274a4a42004-12-07 15:39:31 +00001527static int
hasso8c328f12004-10-05 21:01:23 +00001528cmd_unique_string (vector v, const char *str)
paul718e3742002-12-13 20:15:29 +00001529{
hasso8c328f12004-10-05 21:01:23 +00001530 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001531 char *match;
1532
paul55468c82005-03-14 20:19:01 +00001533 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001534 if ((match = vector_slot (v, i)) != NULL)
1535 if (strcmp (match, str) == 0)
1536 return 0;
1537 return 1;
1538}
1539
1540/* Compare string to description vector. If there is same string
1541 return 1 else return 0. */
ajs274a4a42004-12-07 15:39:31 +00001542static int
hasso8c328f12004-10-05 21:01:23 +00001543desc_unique_string (vector v, const char *str)
paul718e3742002-12-13 20:15:29 +00001544{
hasso8c328f12004-10-05 21:01:23 +00001545 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001546 struct desc *desc;
1547
paul55468c82005-03-14 20:19:01 +00001548 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001549 if ((desc = vector_slot (v, i)) != NULL)
1550 if (strcmp (desc->cmd, str) == 0)
1551 return 1;
1552 return 0;
1553}
1554
ajs274a4a42004-12-07 15:39:31 +00001555static int
paulb92938a2002-12-13 21:20:42 +00001556cmd_try_do_shortcut (enum node_type node, char* first_word) {
1557 if ( first_word != NULL &&
1558 node != AUTH_NODE &&
1559 node != VIEW_NODE &&
1560 node != AUTH_ENABLE_NODE &&
1561 node != ENABLE_NODE &&
1562 0 == strcmp( "do", first_word ) )
1563 return 1;
1564 return 0;
1565}
1566
paul718e3742002-12-13 20:15:29 +00001567/* '?' describe command support. */
ajs274a4a42004-12-07 15:39:31 +00001568static vector
paulb92938a2002-12-13 21:20:42 +00001569cmd_describe_command_real (vector vline, struct vty *vty, int *status)
paul718e3742002-12-13 20:15:29 +00001570{
paulb8961472005-03-14 17:35:52 +00001571 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001572 vector cmd_vector;
1573#define INIT_MATCHVEC_SIZE 10
1574 vector matchvec;
1575 struct cmd_element *cmd_element;
paulb8961472005-03-14 17:35:52 +00001576 unsigned int index;
paul54aba542003-08-21 20:28:24 +00001577 int ret;
1578 enum match_type match;
1579 char *command;
paul718e3742002-12-13 20:15:29 +00001580 static struct desc desc_cr = { "<cr>", "" };
1581
1582 /* Set index. */
paul55468c82005-03-14 20:19:01 +00001583 if (vector_active (vline) == 0)
paulb8961472005-03-14 17:35:52 +00001584 {
1585 *status = CMD_ERR_NO_MATCH;
1586 return NULL;
1587 }
1588 else
paul55468c82005-03-14 20:19:01 +00001589 index = vector_active (vline) - 1;
paul909a2152005-03-14 17:41:45 +00001590
paul718e3742002-12-13 20:15:29 +00001591 /* Make copy vector of current node's command vector. */
1592 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1593
1594 /* Prepare match vector */
1595 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1596
1597 /* Filter commands. */
paul54aba542003-08-21 20:28:24 +00001598 /* Only words precedes current word will be checked in this loop. */
paul718e3742002-12-13 20:15:29 +00001599 for (i = 0; i < index; i++)
paulb8961472005-03-14 17:35:52 +00001600 if ((command = vector_slot (vline, i)))
paul909a2152005-03-14 17:41:45 +00001601 {
1602 match = cmd_filter_by_completion (command, cmd_vector, i);
1603
1604 if (match == vararg_match)
1605 {
1606 struct cmd_element *cmd_element;
1607 vector descvec;
1608 unsigned int j, k;
paul718e3742002-12-13 20:15:29 +00001609
paul55468c82005-03-14 20:19:01 +00001610 for (j = 0; j < vector_active (cmd_vector); j++)
paulb8961472005-03-14 17:35:52 +00001611 if ((cmd_element = vector_slot (cmd_vector, j)) != NULL
paul55468c82005-03-14 20:19:01 +00001612 && (vector_active (cmd_element->strvec)))
paul909a2152005-03-14 17:41:45 +00001613 {
1614 descvec = vector_slot (cmd_element->strvec,
paul55468c82005-03-14 20:19:01 +00001615 vector_active (cmd_element->strvec) - 1);
1616 for (k = 0; k < vector_active (descvec); k++)
paul909a2152005-03-14 17:41:45 +00001617 {
1618 struct desc *desc = vector_slot (descvec, k);
1619 vector_set (matchvec, desc);
1620 }
1621 }
1622
1623 vector_set (matchvec, &desc_cr);
1624 vector_free (cmd_vector);
paul718e3742002-12-13 20:15:29 +00001625
paul909a2152005-03-14 17:41:45 +00001626 return matchvec;
1627 }
paul718e3742002-12-13 20:15:29 +00001628
paul909a2152005-03-14 17:41:45 +00001629 if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
1630 {
1631 vector_free (cmd_vector);
1632 *status = CMD_ERR_AMBIGUOUS;
1633 return NULL;
1634 }
1635 else if (ret == 2)
1636 {
1637 vector_free (cmd_vector);
1638 *status = CMD_ERR_NO_MATCH;
1639 return NULL;
1640 }
1641 }
paul718e3742002-12-13 20:15:29 +00001642
1643 /* Prepare match vector */
1644 /* matchvec = vector_init (INIT_MATCHVEC_SIZE); */
1645
paul54aba542003-08-21 20:28:24 +00001646 /* Make sure that cmd_vector is filtered based on current word */
1647 command = vector_slot (vline, index);
1648 if (command)
1649 match = cmd_filter_by_completion (command, cmd_vector, index);
1650
paul718e3742002-12-13 20:15:29 +00001651 /* Make description vector. */
paul55468c82005-03-14 20:19:01 +00001652 for (i = 0; i < vector_active (cmd_vector); i++)
paul718e3742002-12-13 20:15:29 +00001653 if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
1654 {
hasso8c328f12004-10-05 21:01:23 +00001655 const char *string = NULL;
paul718e3742002-12-13 20:15:29 +00001656 vector strvec = cmd_element->strvec;
1657
paul55468c82005-03-14 20:19:01 +00001658 /* if command is NULL, index may be equal to vector_active */
1659 if (command && index >= vector_active (strvec))
paul718e3742002-12-13 20:15:29 +00001660 vector_slot (cmd_vector, i) = NULL;
1661 else
1662 {
paul54aba542003-08-21 20:28:24 +00001663 /* Check if command is completed. */
paul55468c82005-03-14 20:19:01 +00001664 if (command == NULL && index == vector_active (strvec))
paul718e3742002-12-13 20:15:29 +00001665 {
1666 string = "<cr>";
paul909a2152005-03-14 17:41:45 +00001667 if (!desc_unique_string (matchvec, string))
paul718e3742002-12-13 20:15:29 +00001668 vector_set (matchvec, &desc_cr);
1669 }
1670 else
1671 {
hasso8c328f12004-10-05 21:01:23 +00001672 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001673 vector descvec = vector_slot (strvec, index);
1674 struct desc *desc;
1675
paul55468c82005-03-14 20:19:01 +00001676 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001677 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001678 {
1679 string = cmd_entry_function_desc (command, desc->cmd);
1680 if (string)
1681 {
1682 /* Uniqueness check */
1683 if (!desc_unique_string (matchvec, string))
1684 vector_set (matchvec, desc);
1685 }
1686 }
paul718e3742002-12-13 20:15:29 +00001687 }
1688 }
1689 }
1690 vector_free (cmd_vector);
1691
1692 if (vector_slot (matchvec, 0) == NULL)
1693 {
1694 vector_free (matchvec);
paul909a2152005-03-14 17:41:45 +00001695 *status = CMD_ERR_NO_MATCH;
Paul Jakma5fc60512006-05-12 23:24:09 +00001696 return NULL;
paul718e3742002-12-13 20:15:29 +00001697 }
paul718e3742002-12-13 20:15:29 +00001698
Paul Jakma5fc60512006-05-12 23:24:09 +00001699 *status = CMD_SUCCESS;
paul718e3742002-12-13 20:15:29 +00001700 return matchvec;
1701}
1702
paulb92938a2002-12-13 21:20:42 +00001703vector
1704cmd_describe_command (vector vline, struct vty *vty, int *status)
1705{
1706 vector ret;
1707
1708 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1709 {
1710 enum node_type onode;
1711 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00001712 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00001713
1714 onode = vty->node;
1715 vty->node = ENABLE_NODE;
1716 /* We can try it on enable node, cos' the vty is authenticated */
1717
1718 shifted_vline = vector_init (vector_count(vline));
1719 /* use memcpy? */
paul55468c82005-03-14 20:19:01 +00001720 for (index = 1; index < vector_active (vline); index++)
paulb92938a2002-12-13 21:20:42 +00001721 {
1722 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1723 }
1724
1725 ret = cmd_describe_command_real (shifted_vline, vty, status);
1726
1727 vector_free(shifted_vline);
1728 vty->node = onode;
1729 return ret;
1730 }
1731
1732
1733 return cmd_describe_command_real (vline, vty, status);
1734}
1735
1736
paul718e3742002-12-13 20:15:29 +00001737/* Check LCD of matched command. */
ajs274a4a42004-12-07 15:39:31 +00001738static int
paul718e3742002-12-13 20:15:29 +00001739cmd_lcd (char **matched)
1740{
1741 int i;
1742 int j;
1743 int lcd = -1;
1744 char *s1, *s2;
1745 char c1, c2;
1746
1747 if (matched[0] == NULL || matched[1] == NULL)
1748 return 0;
1749
1750 for (i = 1; matched[i] != NULL; i++)
1751 {
1752 s1 = matched[i - 1];
1753 s2 = matched[i];
1754
1755 for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
1756 if (c1 != c2)
1757 break;
1758
1759 if (lcd < 0)
1760 lcd = j;
1761 else
1762 {
1763 if (lcd > j)
1764 lcd = j;
1765 }
1766 }
1767 return lcd;
1768}
1769
1770/* Command line completion support. */
ajs274a4a42004-12-07 15:39:31 +00001771static char **
paulb92938a2002-12-13 21:20:42 +00001772cmd_complete_command_real (vector vline, struct vty *vty, int *status)
paul718e3742002-12-13 20:15:29 +00001773{
paulb8961472005-03-14 17:35:52 +00001774 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001775 vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1776#define INIT_MATCHVEC_SIZE 10
1777 vector matchvec;
1778 struct cmd_element *cmd_element;
paulb8961472005-03-14 17:35:52 +00001779 unsigned int index;
paul718e3742002-12-13 20:15:29 +00001780 char **match_str;
1781 struct desc *desc;
1782 vector descvec;
1783 char *command;
1784 int lcd;
1785
paul55468c82005-03-14 20:19:01 +00001786 if (vector_active (vline) == 0)
paulb8961472005-03-14 17:35:52 +00001787 {
Paul Jakmad2519962006-05-12 23:19:37 +00001788 vector_free (cmd_vector);
paulb8961472005-03-14 17:35:52 +00001789 *status = CMD_ERR_NO_MATCH;
1790 return NULL;
1791 }
1792 else
paul55468c82005-03-14 20:19:01 +00001793 index = vector_active (vline) - 1;
paulb8961472005-03-14 17:35:52 +00001794
paul718e3742002-12-13 20:15:29 +00001795 /* First, filter by preceeding command string */
1796 for (i = 0; i < index; i++)
paulb8961472005-03-14 17:35:52 +00001797 if ((command = vector_slot (vline, i)))
paul909a2152005-03-14 17:41:45 +00001798 {
1799 enum match_type match;
1800 int ret;
paul718e3742002-12-13 20:15:29 +00001801
paul909a2152005-03-14 17:41:45 +00001802 /* First try completion match, if there is exactly match return 1 */
1803 match = cmd_filter_by_completion (command, cmd_vector, i);
paul718e3742002-12-13 20:15:29 +00001804
paul909a2152005-03-14 17:41:45 +00001805 /* If there is exact match then filter ambiguous match else check
1806 ambiguousness. */
1807 if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
1808 {
1809 vector_free (cmd_vector);
1810 *status = CMD_ERR_AMBIGUOUS;
1811 return NULL;
1812 }
1813 /*
1814 else if (ret == 2)
1815 {
1816 vector_free (cmd_vector);
1817 *status = CMD_ERR_NO_MATCH;
1818 return NULL;
1819 }
1820 */
1821 }
1822
paul718e3742002-12-13 20:15:29 +00001823 /* Prepare match vector. */
1824 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1825
1826 /* Now we got into completion */
paul55468c82005-03-14 20:19:01 +00001827 for (i = 0; i < vector_active (cmd_vector); i++)
paulb8961472005-03-14 17:35:52 +00001828 if ((cmd_element = vector_slot (cmd_vector, i)))
paul718e3742002-12-13 20:15:29 +00001829 {
hasso8c328f12004-10-05 21:01:23 +00001830 const char *string;
paul718e3742002-12-13 20:15:29 +00001831 vector strvec = cmd_element->strvec;
paul909a2152005-03-14 17:41:45 +00001832
paul718e3742002-12-13 20:15:29 +00001833 /* Check field length */
paul55468c82005-03-14 20:19:01 +00001834 if (index >= vector_active (strvec))
paul718e3742002-12-13 20:15:29 +00001835 vector_slot (cmd_vector, i) = NULL;
paul909a2152005-03-14 17:41:45 +00001836 else
paul718e3742002-12-13 20:15:29 +00001837 {
hasso8c328f12004-10-05 21:01:23 +00001838 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001839
1840 descvec = vector_slot (strvec, index);
paul55468c82005-03-14 20:19:01 +00001841 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001842 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001843 {
paulb8961472005-03-14 17:35:52 +00001844 if ((string =
1845 cmd_entry_function (vector_slot (vline, index),
paul909a2152005-03-14 17:41:45 +00001846 desc->cmd)))
1847 if (cmd_unique_string (matchvec, string))
1848 vector_set (matchvec, XSTRDUP (MTYPE_TMP, string));
1849 }
paul718e3742002-12-13 20:15:29 +00001850 }
1851 }
1852
1853 /* We don't need cmd_vector any more. */
1854 vector_free (cmd_vector);
1855
1856 /* No matched command */
1857 if (vector_slot (matchvec, 0) == NULL)
1858 {
1859 vector_free (matchvec);
1860
1861 /* In case of 'command \t' pattern. Do you need '?' command at
1862 the end of the line. */
1863 if (vector_slot (vline, index) == '\0')
1864 *status = CMD_ERR_NOTHING_TODO;
1865 else
1866 *status = CMD_ERR_NO_MATCH;
1867 return NULL;
1868 }
1869
1870 /* Only one matched */
1871 if (vector_slot (matchvec, 1) == NULL)
1872 {
1873 match_str = (char **) matchvec->index;
1874 vector_only_wrapper_free (matchvec);
1875 *status = CMD_COMPLETE_FULL_MATCH;
1876 return match_str;
1877 }
1878 /* Make it sure last element is NULL. */
1879 vector_set (matchvec, NULL);
1880
1881 /* Check LCD of matched strings. */
1882 if (vector_slot (vline, index) != NULL)
1883 {
1884 lcd = cmd_lcd ((char **) matchvec->index);
1885
1886 if (lcd)
1887 {
1888 int len = strlen (vector_slot (vline, index));
paul909a2152005-03-14 17:41:45 +00001889
paul718e3742002-12-13 20:15:29 +00001890 if (len < lcd)
1891 {
1892 char *lcdstr;
paul909a2152005-03-14 17:41:45 +00001893
paul05865c92005-10-26 05:49:54 +00001894 lcdstr = XMALLOC (MTYPE_STRVEC, lcd + 1);
paul718e3742002-12-13 20:15:29 +00001895 memcpy (lcdstr, matchvec->index[0], lcd);
1896 lcdstr[lcd] = '\0';
1897
1898 /* match_str = (char **) &lcdstr; */
1899
1900 /* Free matchvec. */
paul55468c82005-03-14 20:19:01 +00001901 for (i = 0; i < vector_active (matchvec); i++)
paul718e3742002-12-13 20:15:29 +00001902 {
1903 if (vector_slot (matchvec, i))
paul05865c92005-10-26 05:49:54 +00001904 XFREE (MTYPE_STRVEC, vector_slot (matchvec, i));
paul718e3742002-12-13 20:15:29 +00001905 }
1906 vector_free (matchvec);
1907
paul909a2152005-03-14 17:41:45 +00001908 /* Make new matchvec. */
paul718e3742002-12-13 20:15:29 +00001909 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1910 vector_set (matchvec, lcdstr);
1911 match_str = (char **) matchvec->index;
1912 vector_only_wrapper_free (matchvec);
1913
1914 *status = CMD_COMPLETE_MATCH;
1915 return match_str;
1916 }
1917 }
1918 }
1919
1920 match_str = (char **) matchvec->index;
1921 vector_only_wrapper_free (matchvec);
1922 *status = CMD_COMPLETE_LIST_MATCH;
1923 return match_str;
1924}
1925
paulb92938a2002-12-13 21:20:42 +00001926char **
paul9ab68122003-01-18 01:16:20 +00001927cmd_complete_command (vector vline, struct vty *vty, int *status)
paulb92938a2002-12-13 21:20:42 +00001928{
1929 char **ret;
1930
1931 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1932 {
1933 enum node_type onode;
1934 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00001935 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00001936
1937 onode = vty->node;
1938 vty->node = ENABLE_NODE;
1939 /* We can try it on enable node, cos' the vty is authenticated */
1940
1941 shifted_vline = vector_init (vector_count(vline));
1942 /* use memcpy? */
paul55468c82005-03-14 20:19:01 +00001943 for (index = 1; index < vector_active (vline); index++)
paulb92938a2002-12-13 21:20:42 +00001944 {
1945 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1946 }
1947
1948 ret = cmd_complete_command_real (shifted_vline, vty, status);
1949
1950 vector_free(shifted_vline);
1951 vty->node = onode;
1952 return ret;
1953 }
1954
1955
1956 return cmd_complete_command_real (vline, vty, status);
1957}
1958
1959/* return parent node */
1960/* MUST eventually converge on CONFIG_NODE */
hasso13bfca72005-01-23 21:42:25 +00001961enum node_type
ajs274a4a42004-12-07 15:39:31 +00001962node_parent ( enum node_type node )
paulb92938a2002-12-13 21:20:42 +00001963{
1964 enum node_type ret;
1965
paul9ab68122003-01-18 01:16:20 +00001966 assert (node > CONFIG_NODE);
1967
1968 switch (node)
1969 {
1970 case BGP_VPNV4_NODE:
1971 case BGP_IPV4_NODE:
1972 case BGP_IPV4M_NODE:
1973 case BGP_IPV6_NODE:
paul1e836592005-08-22 22:39:56 +00001974 case BGP_IPV6M_NODE:
paul9ab68122003-01-18 01:16:20 +00001975 ret = BGP_NODE;
1976 break;
1977 case KEYCHAIN_KEY_NODE:
1978 ret = KEYCHAIN_NODE;
1979 break;
1980 default:
1981 ret = CONFIG_NODE;
paulb92938a2002-12-13 21:20:42 +00001982 }
1983
1984 return ret;
1985}
1986
paul718e3742002-12-13 20:15:29 +00001987/* Execute command by argument vline vector. */
ajs274a4a42004-12-07 15:39:31 +00001988static int
paulb8961472005-03-14 17:35:52 +00001989cmd_execute_command_real (vector vline, struct vty *vty,
1990 struct cmd_element **cmd)
paul718e3742002-12-13 20:15:29 +00001991{
hasso8c328f12004-10-05 21:01:23 +00001992 unsigned int i;
1993 unsigned int index;
paul718e3742002-12-13 20:15:29 +00001994 vector cmd_vector;
1995 struct cmd_element *cmd_element;
1996 struct cmd_element *matched_element;
1997 unsigned int matched_count, incomplete_count;
1998 int argc;
paul9035efa2004-10-10 11:56:56 +00001999 const char *argv[CMD_ARGC_MAX];
paul718e3742002-12-13 20:15:29 +00002000 enum match_type match = 0;
2001 int varflag;
2002 char *command;
2003
2004 /* Make copy of command elements. */
2005 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2006
paul55468c82005-03-14 20:19:01 +00002007 for (index = 0; index < vector_active (vline); index++)
paulb8961472005-03-14 17:35:52 +00002008 if ((command = vector_slot (vline, index)))
paul909a2152005-03-14 17:41:45 +00002009 {
2010 int ret;
paul718e3742002-12-13 20:15:29 +00002011
paul909a2152005-03-14 17:41:45 +00002012 match = cmd_filter_by_completion (command, cmd_vector, index);
paul718e3742002-12-13 20:15:29 +00002013
paul909a2152005-03-14 17:41:45 +00002014 if (match == vararg_match)
2015 break;
2016
2017 ret = is_cmd_ambiguous (command, cmd_vector, index, match);
paul718e3742002-12-13 20:15:29 +00002018
paul909a2152005-03-14 17:41:45 +00002019 if (ret == 1)
2020 {
2021 vector_free (cmd_vector);
2022 return CMD_ERR_AMBIGUOUS;
2023 }
2024 else if (ret == 2)
2025 {
2026 vector_free (cmd_vector);
2027 return CMD_ERR_NO_MATCH;
2028 }
2029 }
paul718e3742002-12-13 20:15:29 +00002030
2031 /* Check matched count. */
2032 matched_element = NULL;
2033 matched_count = 0;
2034 incomplete_count = 0;
2035
paul55468c82005-03-14 20:19:01 +00002036 for (i = 0; i < vector_active (cmd_vector); i++)
paulb8961472005-03-14 17:35:52 +00002037 if ((cmd_element = vector_slot (cmd_vector, i)))
paul718e3742002-12-13 20:15:29 +00002038 {
paul718e3742002-12-13 20:15:29 +00002039 if (match == vararg_match || index >= cmd_element->cmdsize)
2040 {
2041 matched_element = cmd_element;
2042#if 0
2043 printf ("DEBUG: %s\n", cmd_element->string);
2044#endif
2045 matched_count++;
2046 }
2047 else
2048 {
2049 incomplete_count++;
2050 }
2051 }
paul909a2152005-03-14 17:41:45 +00002052
paul718e3742002-12-13 20:15:29 +00002053 /* Finish of using cmd_vector. */
2054 vector_free (cmd_vector);
2055
paul909a2152005-03-14 17:41:45 +00002056 /* To execute command, matched_count must be 1. */
2057 if (matched_count == 0)
paul718e3742002-12-13 20:15:29 +00002058 {
2059 if (incomplete_count)
2060 return CMD_ERR_INCOMPLETE;
2061 else
2062 return CMD_ERR_NO_MATCH;
2063 }
2064
paul909a2152005-03-14 17:41:45 +00002065 if (matched_count > 1)
paul718e3742002-12-13 20:15:29 +00002066 return CMD_ERR_AMBIGUOUS;
2067
2068 /* Argument treatment */
2069 varflag = 0;
2070 argc = 0;
2071
paul55468c82005-03-14 20:19:01 +00002072 for (i = 0; i < vector_active (vline); i++)
paul718e3742002-12-13 20:15:29 +00002073 {
2074 if (varflag)
2075 argv[argc++] = vector_slot (vline, i);
2076 else
paul909a2152005-03-14 17:41:45 +00002077 {
paul718e3742002-12-13 20:15:29 +00002078 vector descvec = vector_slot (matched_element->strvec, i);
2079
paul55468c82005-03-14 20:19:01 +00002080 if (vector_active (descvec) == 1)
paul718e3742002-12-13 20:15:29 +00002081 {
2082 struct desc *desc = vector_slot (descvec, 0);
paul718e3742002-12-13 20:15:29 +00002083
hasso8c328f12004-10-05 21:01:23 +00002084 if (CMD_VARARG (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002085 varflag = 1;
2086
hasso8c328f12004-10-05 21:01:23 +00002087 if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002088 argv[argc++] = vector_slot (vline, i);
2089 }
2090 else
2091 argv[argc++] = vector_slot (vline, i);
2092 }
2093
2094 if (argc >= CMD_ARGC_MAX)
2095 return CMD_ERR_EXEED_ARGC_MAX;
2096 }
2097
2098 /* For vtysh execution. */
2099 if (cmd)
2100 *cmd = matched_element;
2101
2102 if (matched_element->daemon)
2103 return CMD_SUCCESS_DAEMON;
2104
2105 /* Execute matched command. */
2106 return (*matched_element->func) (matched_element, vty, argc, argv);
2107}
2108
paulb92938a2002-12-13 21:20:42 +00002109int
hasso87d683b2005-01-16 23:31:54 +00002110cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,
2111 int vtysh) {
paul9ab68122003-01-18 01:16:20 +00002112 int ret, saved_ret, tried = 0;
2113 enum node_type onode, try_node;
2114
2115 onode = try_node = vty->node;
paulb92938a2002-12-13 21:20:42 +00002116
2117 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
2118 {
2119 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00002120 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00002121
2122 vty->node = ENABLE_NODE;
2123 /* We can try it on enable node, cos' the vty is authenticated */
2124
2125 shifted_vline = vector_init (vector_count(vline));
2126 /* use memcpy? */
paul55468c82005-03-14 20:19:01 +00002127 for (index = 1; index < vector_active (vline); index++)
paulb92938a2002-12-13 21:20:42 +00002128 {
2129 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
2130 }
2131
2132 ret = cmd_execute_command_real (shifted_vline, vty, cmd);
2133
2134 vector_free(shifted_vline);
2135 vty->node = onode;
2136 return ret;
2137 }
2138
2139
paul9ab68122003-01-18 01:16:20 +00002140 saved_ret = ret = cmd_execute_command_real (vline, vty, cmd);
paulb92938a2002-12-13 21:20:42 +00002141
hasso87d683b2005-01-16 23:31:54 +00002142 if (vtysh)
2143 return saved_ret;
2144
paulb92938a2002-12-13 21:20:42 +00002145 /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
paul9ab68122003-01-18 01:16:20 +00002146 while ( ret != CMD_SUCCESS && ret != CMD_WARNING
paulb92938a2002-12-13 21:20:42 +00002147 && vty->node > CONFIG_NODE )
2148 {
paul9ab68122003-01-18 01:16:20 +00002149 try_node = node_parent(try_node);
2150 vty->node = try_node;
paulb92938a2002-12-13 21:20:42 +00002151 ret = cmd_execute_command_real (vline, vty, cmd);
paul9ab68122003-01-18 01:16:20 +00002152 tried = 1;
2153 if (ret == CMD_SUCCESS || ret == CMD_WARNING)
paulb92938a2002-12-13 21:20:42 +00002154 {
paul9ab68122003-01-18 01:16:20 +00002155 /* succesfull command, leave the node as is */
paulb92938a2002-12-13 21:20:42 +00002156 return ret;
2157 }
paulb92938a2002-12-13 21:20:42 +00002158 }
paul9ab68122003-01-18 01:16:20 +00002159 /* no command succeeded, reset the vty to the original node and
2160 return the error for this node */
2161 if ( tried )
2162 vty->node = onode;
2163 return saved_ret;
pauleda031f2003-01-18 00:39:19 +00002164}
2165
paul718e3742002-12-13 20:15:29 +00002166/* Execute command by argument readline. */
2167int
paul909a2152005-03-14 17:41:45 +00002168cmd_execute_command_strict (vector vline, struct vty *vty,
paul718e3742002-12-13 20:15:29 +00002169 struct cmd_element **cmd)
2170{
hasso8c328f12004-10-05 21:01:23 +00002171 unsigned int i;
2172 unsigned int index;
paul718e3742002-12-13 20:15:29 +00002173 vector cmd_vector;
2174 struct cmd_element *cmd_element;
2175 struct cmd_element *matched_element;
2176 unsigned int matched_count, incomplete_count;
2177 int argc;
paul9035efa2004-10-10 11:56:56 +00002178 const char *argv[CMD_ARGC_MAX];
paul718e3742002-12-13 20:15:29 +00002179 int varflag;
2180 enum match_type match = 0;
2181 char *command;
2182
2183 /* Make copy of command element */
2184 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2185
paul55468c82005-03-14 20:19:01 +00002186 for (index = 0; index < vector_active (vline); index++)
paulb8961472005-03-14 17:35:52 +00002187 if ((command = vector_slot (vline, index)))
paul909a2152005-03-14 17:41:45 +00002188 {
2189 int ret;
2190
2191 match = cmd_filter_by_string (vector_slot (vline, index),
2192 cmd_vector, index);
paul718e3742002-12-13 20:15:29 +00002193
paul909a2152005-03-14 17:41:45 +00002194 /* If command meets '.VARARG' then finish matching. */
2195 if (match == vararg_match)
2196 break;
2197
2198 ret = is_cmd_ambiguous (command, cmd_vector, index, match);
2199 if (ret == 1)
2200 {
2201 vector_free (cmd_vector);
2202 return CMD_ERR_AMBIGUOUS;
2203 }
2204 if (ret == 2)
2205 {
2206 vector_free (cmd_vector);
2207 return CMD_ERR_NO_MATCH;
2208 }
2209 }
paul718e3742002-12-13 20:15:29 +00002210
2211 /* Check matched count. */
2212 matched_element = NULL;
2213 matched_count = 0;
2214 incomplete_count = 0;
paul55468c82005-03-14 20:19:01 +00002215 for (i = 0; i < vector_active (cmd_vector); i++)
paul909a2152005-03-14 17:41:45 +00002216 if (vector_slot (cmd_vector, i) != NULL)
paul718e3742002-12-13 20:15:29 +00002217 {
paul909a2152005-03-14 17:41:45 +00002218 cmd_element = vector_slot (cmd_vector, i);
paul718e3742002-12-13 20:15:29 +00002219
2220 if (match == vararg_match || index >= cmd_element->cmdsize)
2221 {
2222 matched_element = cmd_element;
2223 matched_count++;
2224 }
2225 else
2226 incomplete_count++;
2227 }
paul909a2152005-03-14 17:41:45 +00002228
paul718e3742002-12-13 20:15:29 +00002229 /* Finish of using cmd_vector. */
2230 vector_free (cmd_vector);
2231
paul909a2152005-03-14 17:41:45 +00002232 /* To execute command, matched_count must be 1. */
2233 if (matched_count == 0)
paul718e3742002-12-13 20:15:29 +00002234 {
2235 if (incomplete_count)
2236 return CMD_ERR_INCOMPLETE;
2237 else
2238 return CMD_ERR_NO_MATCH;
2239 }
2240
paul909a2152005-03-14 17:41:45 +00002241 if (matched_count > 1)
paul718e3742002-12-13 20:15:29 +00002242 return CMD_ERR_AMBIGUOUS;
2243
2244 /* Argument treatment */
2245 varflag = 0;
2246 argc = 0;
2247
paul55468c82005-03-14 20:19:01 +00002248 for (i = 0; i < vector_active (vline); i++)
paul718e3742002-12-13 20:15:29 +00002249 {
2250 if (varflag)
2251 argv[argc++] = vector_slot (vline, i);
2252 else
paul909a2152005-03-14 17:41:45 +00002253 {
paul718e3742002-12-13 20:15:29 +00002254 vector descvec = vector_slot (matched_element->strvec, i);
2255
paul55468c82005-03-14 20:19:01 +00002256 if (vector_active (descvec) == 1)
paul718e3742002-12-13 20:15:29 +00002257 {
2258 struct desc *desc = vector_slot (descvec, 0);
paul718e3742002-12-13 20:15:29 +00002259
hasso8c328f12004-10-05 21:01:23 +00002260 if (CMD_VARARG (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002261 varflag = 1;
paul909a2152005-03-14 17:41:45 +00002262
hasso8c328f12004-10-05 21:01:23 +00002263 if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002264 argv[argc++] = vector_slot (vline, i);
2265 }
2266 else
2267 argv[argc++] = vector_slot (vline, i);
2268 }
2269
2270 if (argc >= CMD_ARGC_MAX)
2271 return CMD_ERR_EXEED_ARGC_MAX;
2272 }
2273
2274 /* For vtysh execution. */
2275 if (cmd)
2276 *cmd = matched_element;
2277
2278 if (matched_element->daemon)
2279 return CMD_SUCCESS_DAEMON;
2280
2281 /* Now execute matched command */
2282 return (*matched_element->func) (matched_element, vty, argc, argv);
2283}
2284
2285/* Configration make from file. */
2286int
2287config_from_file (struct vty *vty, FILE *fp)
2288{
2289 int ret;
2290 vector vline;
2291
2292 while (fgets (vty->buf, VTY_BUFSIZ, fp))
2293 {
2294 vline = cmd_make_strvec (vty->buf);
2295
2296 /* In case of comment line */
2297 if (vline == NULL)
2298 continue;
2299 /* Execute configuration command : this is strict match */
2300 ret = cmd_execute_command_strict (vline, vty, NULL);
2301
2302 /* Try again with setting node to CONFIG_NODE */
paulb92938a2002-12-13 21:20:42 +00002303 while (ret != CMD_SUCCESS && ret != CMD_WARNING
hassoddd85ed2004-10-13 08:18:07 +00002304 && ret != CMD_ERR_NOTHING_TODO && vty->node != CONFIG_NODE)
2305 {
paulb92938a2002-12-13 21:20:42 +00002306 vty->node = node_parent(vty->node);
hassoddd85ed2004-10-13 08:18:07 +00002307 ret = cmd_execute_command_strict (vline, vty, NULL);
2308 }
paul9ab68122003-01-18 01:16:20 +00002309
paul718e3742002-12-13 20:15:29 +00002310 cmd_free_strvec (vline);
2311
hassoddd85ed2004-10-13 08:18:07 +00002312 if (ret != CMD_SUCCESS && ret != CMD_WARNING
2313 && ret != CMD_ERR_NOTHING_TODO)
paul718e3742002-12-13 20:15:29 +00002314 return ret;
2315 }
2316 return CMD_SUCCESS;
2317}
2318
2319/* Configration from terminal */
2320DEFUN (config_terminal,
2321 config_terminal_cmd,
2322 "configure terminal",
2323 "Configuration from vty interface\n"
2324 "Configuration terminal\n")
2325{
2326 if (vty_config_lock (vty))
2327 vty->node = CONFIG_NODE;
2328 else
2329 {
2330 vty_out (vty, "VTY configuration is locked by other VTY%s", VTY_NEWLINE);
2331 return CMD_WARNING;
2332 }
2333 return CMD_SUCCESS;
2334}
2335
2336/* Enable command */
2337DEFUN (enable,
2338 config_enable_cmd,
2339 "enable",
2340 "Turn on privileged mode command\n")
2341{
2342 /* If enable password is NULL, change to ENABLE_NODE */
2343 if ((host.enable == NULL && host.enable_encrypt == NULL) ||
2344 vty->type == VTY_SHELL_SERV)
2345 vty->node = ENABLE_NODE;
2346 else
2347 vty->node = AUTH_ENABLE_NODE;
2348
2349 return CMD_SUCCESS;
2350}
2351
2352/* Disable command */
2353DEFUN (disable,
2354 config_disable_cmd,
2355 "disable",
2356 "Turn off privileged mode command\n")
2357{
2358 if (vty->node == ENABLE_NODE)
2359 vty->node = VIEW_NODE;
2360 return CMD_SUCCESS;
2361}
2362
2363/* Down vty node level. */
2364DEFUN (config_exit,
2365 config_exit_cmd,
2366 "exit",
2367 "Exit current mode and down to previous mode\n")
2368{
2369 switch (vty->node)
2370 {
2371 case VIEW_NODE:
2372 case ENABLE_NODE:
2373 if (vty_shell (vty))
2374 exit (0);
2375 else
2376 vty->status = VTY_CLOSE;
2377 break;
2378 case CONFIG_NODE:
2379 vty->node = ENABLE_NODE;
2380 vty_config_unlock (vty);
2381 break;
2382 case INTERFACE_NODE:
2383 case ZEBRA_NODE:
2384 case BGP_NODE:
2385 case RIP_NODE:
2386 case RIPNG_NODE:
2387 case OSPF_NODE:
2388 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00002389 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00002390 case KEYCHAIN_NODE:
2391 case MASC_NODE:
2392 case RMAP_NODE:
2393 case VTY_NODE:
2394 vty->node = CONFIG_NODE;
2395 break;
2396 case BGP_VPNV4_NODE:
2397 case BGP_IPV4_NODE:
2398 case BGP_IPV4M_NODE:
2399 case BGP_IPV6_NODE:
paul1e836592005-08-22 22:39:56 +00002400 case BGP_IPV6M_NODE:
paul718e3742002-12-13 20:15:29 +00002401 vty->node = BGP_NODE;
2402 break;
2403 case KEYCHAIN_KEY_NODE:
2404 vty->node = KEYCHAIN_NODE;
2405 break;
2406 default:
2407 break;
2408 }
2409 return CMD_SUCCESS;
2410}
2411
2412/* quit is alias of exit. */
2413ALIAS (config_exit,
2414 config_quit_cmd,
2415 "quit",
2416 "Exit current mode and down to previous mode\n")
2417
2418/* End of configuration. */
2419DEFUN (config_end,
2420 config_end_cmd,
2421 "end",
2422 "End current mode and change to enable mode.")
2423{
2424 switch (vty->node)
2425 {
2426 case VIEW_NODE:
2427 case ENABLE_NODE:
2428 /* Nothing to do. */
2429 break;
2430 case CONFIG_NODE:
2431 case INTERFACE_NODE:
2432 case ZEBRA_NODE:
2433 case RIP_NODE:
2434 case RIPNG_NODE:
2435 case BGP_NODE:
2436 case BGP_VPNV4_NODE:
2437 case BGP_IPV4_NODE:
2438 case BGP_IPV4M_NODE:
2439 case BGP_IPV6_NODE:
paul1e836592005-08-22 22:39:56 +00002440 case BGP_IPV6M_NODE:
paul718e3742002-12-13 20:15:29 +00002441 case RMAP_NODE:
2442 case OSPF_NODE:
2443 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00002444 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00002445 case KEYCHAIN_NODE:
2446 case KEYCHAIN_KEY_NODE:
2447 case MASC_NODE:
2448 case VTY_NODE:
2449 vty_config_unlock (vty);
2450 vty->node = ENABLE_NODE;
2451 break;
2452 default:
2453 break;
2454 }
2455 return CMD_SUCCESS;
2456}
2457
2458/* Show version. */
2459DEFUN (show_version,
2460 show_version_cmd,
2461 "show version",
2462 SHOW_STR
2463 "Displays zebra version\n")
2464{
hasso12f6ea22005-03-07 08:35:39 +00002465 vty_out (vty, "Quagga %s (%s).%s", QUAGGA_VERSION, host.name?host.name:"",
2466 VTY_NEWLINE);
hasso6590f2c2004-10-19 20:40:08 +00002467 vty_out (vty, "%s%s", QUAGGA_COPYRIGHT, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00002468
2469 return CMD_SUCCESS;
2470}
2471
2472/* Help display function for all node. */
2473DEFUN (config_help,
2474 config_help_cmd,
2475 "help",
2476 "Description of the interactive help system\n")
2477{
2478 vty_out (vty,
hasso6590f2c2004-10-19 20:40:08 +00002479 "Quagga VTY provides advanced help feature. When you need help,%s\
paul718e3742002-12-13 20:15:29 +00002480anytime at the command line please press '?'.%s\
2481%s\
2482If nothing matches, the help list will be empty and you must backup%s\
2483 until entering a '?' shows the available options.%s\
2484Two styles of help are provided:%s\
24851. Full help is available when you are ready to enter a%s\
2486command argument (e.g. 'show ?') and describes each possible%s\
2487argument.%s\
24882. Partial help is provided when an abbreviated argument is entered%s\
2489 and you want to know what arguments match the input%s\
2490 (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2491 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2492 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
2493 return CMD_SUCCESS;
2494}
2495
2496/* Help display function for all node. */
2497DEFUN (config_list,
2498 config_list_cmd,
2499 "list",
2500 "Print command list\n")
2501{
hasso8c328f12004-10-05 21:01:23 +00002502 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002503 struct cmd_node *cnode = vector_slot (cmdvec, vty->node);
2504 struct cmd_element *cmd;
2505
paul55468c82005-03-14 20:19:01 +00002506 for (i = 0; i < vector_active (cnode->cmd_vector); i++)
paul4275b1d2005-03-09 13:42:23 +00002507 if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL
2508 && !(cmd->attr == CMD_ATTR_DEPRECATED
2509 || cmd->attr == CMD_ATTR_HIDDEN))
paul718e3742002-12-13 20:15:29 +00002510 vty_out (vty, " %s%s", cmd->string,
2511 VTY_NEWLINE);
2512 return CMD_SUCCESS;
2513}
2514
2515/* Write current configuration into file. */
2516DEFUN (config_write_file,
2517 config_write_file_cmd,
2518 "write file",
2519 "Write running configuration to memory, network, or terminal\n"
2520 "Write to configuration file\n")
2521{
hasso8c328f12004-10-05 21:01:23 +00002522 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002523 int fd;
2524 struct cmd_node *node;
2525 char *config_file;
2526 char *config_file_tmp = NULL;
2527 char *config_file_sav = NULL;
paul05865c92005-10-26 05:49:54 +00002528 int ret = CMD_WARNING;
paul718e3742002-12-13 20:15:29 +00002529 struct vty *file_vty;
2530
2531 /* Check and see if we are operating under vtysh configuration */
2532 if (host.config == NULL)
2533 {
2534 vty_out (vty, "Can't save to configuration file, using vtysh.%s",
2535 VTY_NEWLINE);
2536 return CMD_WARNING;
2537 }
2538
2539 /* Get filename. */
2540 config_file = host.config;
2541
paul05865c92005-10-26 05:49:54 +00002542 config_file_sav =
2543 XMALLOC (MTYPE_TMP, strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
paul718e3742002-12-13 20:15:29 +00002544 strcpy (config_file_sav, config_file);
2545 strcat (config_file_sav, CONF_BACKUP_EXT);
2546
2547
paul05865c92005-10-26 05:49:54 +00002548 config_file_tmp = XMALLOC (MTYPE_TMP, strlen (config_file) + 8);
paul718e3742002-12-13 20:15:29 +00002549 sprintf (config_file_tmp, "%s.XXXXXX", config_file);
2550
2551 /* Open file to configuration write. */
2552 fd = mkstemp (config_file_tmp);
2553 if (fd < 0)
2554 {
2555 vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
2556 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002557 goto finished;
paul718e3742002-12-13 20:15:29 +00002558 }
2559
2560 /* Make vty for configuration file. */
2561 file_vty = vty_new ();
2562 file_vty->fd = fd;
2563 file_vty->type = VTY_FILE;
2564
2565 /* Config file header print. */
2566 vty_out (file_vty, "!\n! Zebra configuration saved from vty\n! ");
2567 vty_time_print (file_vty, 1);
2568 vty_out (file_vty, "!\n");
2569
paul55468c82005-03-14 20:19:01 +00002570 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +00002571 if ((node = vector_slot (cmdvec, i)) && node->func)
2572 {
2573 if ((*node->func) (file_vty))
2574 vty_out (file_vty, "!\n");
2575 }
2576 vty_close (file_vty);
2577
2578 if (unlink (config_file_sav) != 0)
2579 if (errno != ENOENT)
2580 {
2581 vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
2582 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002583 goto finished;
paul718e3742002-12-13 20:15:29 +00002584 }
2585 if (link (config_file, config_file_sav) != 0)
2586 {
2587 vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
2588 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002589 goto finished;
paul718e3742002-12-13 20:15:29 +00002590 }
2591 sync ();
2592 if (unlink (config_file) != 0)
2593 {
2594 vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
2595 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002596 goto finished;
paul718e3742002-12-13 20:15:29 +00002597 }
2598 if (link (config_file_tmp, config_file) != 0)
2599 {
2600 vty_out (vty, "Can't save configuration file %s.%s", config_file,
2601 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002602 goto finished;
paul718e3742002-12-13 20:15:29 +00002603 }
paul718e3742002-12-13 20:15:29 +00002604 sync ();
2605
gdtaa593d52003-12-22 20:15:53 +00002606 if (chmod (config_file, CONFIGFILE_MASK) != 0)
2607 {
2608 vty_out (vty, "Can't chmod configuration file %s: %s (%d).%s",
ajs6099b3b2004-11-20 02:06:59 +00002609 config_file, safe_strerror(errno), errno, VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002610 goto finished;
gdtaa593d52003-12-22 20:15:53 +00002611 }
2612
paul718e3742002-12-13 20:15:29 +00002613 vty_out (vty, "Configuration saved to %s%s", config_file,
2614 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002615 ret = CMD_SUCCESS;
2616
2617finished:
2618 unlink (config_file_tmp);
2619 XFREE (MTYPE_TMP, config_file_tmp);
2620 XFREE (MTYPE_TMP, config_file_sav);
2621 return ret;
paul718e3742002-12-13 20:15:29 +00002622}
2623
2624ALIAS (config_write_file,
2625 config_write_cmd,
2626 "write",
2627 "Write running configuration to memory, network, or terminal\n")
2628
2629ALIAS (config_write_file,
2630 config_write_memory_cmd,
2631 "write memory",
2632 "Write running configuration to memory, network, or terminal\n"
2633 "Write configuration to the file (same as write file)\n")
2634
2635ALIAS (config_write_file,
2636 copy_runningconfig_startupconfig_cmd,
2637 "copy running-config startup-config",
2638 "Copy configuration\n"
2639 "Copy running config to... \n"
2640 "Copy running config to startup config (same as write file)\n")
2641
2642/* Write current configuration into the terminal. */
2643DEFUN (config_write_terminal,
2644 config_write_terminal_cmd,
2645 "write terminal",
2646 "Write running configuration to memory, network, or terminal\n"
2647 "Write to terminal\n")
2648{
hasso8c328f12004-10-05 21:01:23 +00002649 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002650 struct cmd_node *node;
2651
2652 if (vty->type == VTY_SHELL_SERV)
2653 {
paul55468c82005-03-14 20:19:01 +00002654 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +00002655 if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
2656 {
2657 if ((*node->func) (vty))
2658 vty_out (vty, "!%s", VTY_NEWLINE);
2659 }
2660 }
2661 else
2662 {
2663 vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
2664 VTY_NEWLINE);
2665 vty_out (vty, "!%s", VTY_NEWLINE);
2666
paul55468c82005-03-14 20:19:01 +00002667 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +00002668 if ((node = vector_slot (cmdvec, i)) && node->func)
2669 {
2670 if ((*node->func) (vty))
2671 vty_out (vty, "!%s", VTY_NEWLINE);
2672 }
2673 vty_out (vty, "end%s",VTY_NEWLINE);
2674 }
2675 return CMD_SUCCESS;
2676}
2677
2678/* Write current configuration into the terminal. */
2679ALIAS (config_write_terminal,
2680 show_running_config_cmd,
2681 "show running-config",
2682 SHOW_STR
2683 "running configuration\n")
2684
2685/* Write startup configuration into the terminal. */
2686DEFUN (show_startup_config,
2687 show_startup_config_cmd,
2688 "show startup-config",
2689 SHOW_STR
2690 "Contentes of startup configuration\n")
2691{
2692 char buf[BUFSIZ];
2693 FILE *confp;
2694
2695 confp = fopen (host.config, "r");
2696 if (confp == NULL)
2697 {
2698 vty_out (vty, "Can't open configuration file [%s]%s",
2699 host.config, VTY_NEWLINE);
2700 return CMD_WARNING;
2701 }
2702
2703 while (fgets (buf, BUFSIZ, confp))
2704 {
2705 char *cp = buf;
2706
2707 while (*cp != '\r' && *cp != '\n' && *cp != '\0')
2708 cp++;
2709 *cp = '\0';
2710
2711 vty_out (vty, "%s%s", buf, VTY_NEWLINE);
2712 }
2713
2714 fclose (confp);
2715
2716 return CMD_SUCCESS;
2717}
2718
2719/* Hostname configuration */
2720DEFUN (config_hostname,
2721 hostname_cmd,
2722 "hostname WORD",
2723 "Set system's network name\n"
2724 "This system's network name\n")
2725{
2726 if (!isalpha((int) *argv[0]))
2727 {
2728 vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
2729 return CMD_WARNING;
2730 }
2731
2732 if (host.name)
paul05865c92005-10-26 05:49:54 +00002733 XFREE (MTYPE_HOST, host.name);
paul718e3742002-12-13 20:15:29 +00002734
paul05865c92005-10-26 05:49:54 +00002735 host.name = XSTRDUP (MTYPE_HOST, argv[0]);
paul718e3742002-12-13 20:15:29 +00002736 return CMD_SUCCESS;
2737}
2738
2739DEFUN (config_no_hostname,
2740 no_hostname_cmd,
2741 "no hostname [HOSTNAME]",
2742 NO_STR
2743 "Reset system's network name\n"
2744 "Host name of this router\n")
2745{
2746 if (host.name)
paul05865c92005-10-26 05:49:54 +00002747 XFREE (MTYPE_HOST, host.name);
paul718e3742002-12-13 20:15:29 +00002748 host.name = NULL;
2749 return CMD_SUCCESS;
2750}
2751
2752/* VTY interface password set. */
2753DEFUN (config_password, password_cmd,
2754 "password (8|) WORD",
2755 "Assign the terminal connection password\n"
2756 "Specifies a HIDDEN password will follow\n"
2757 "dummy string \n"
2758 "The HIDDEN line password string\n")
2759{
2760 /* Argument check. */
2761 if (argc == 0)
2762 {
2763 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2764 return CMD_WARNING;
2765 }
2766
2767 if (argc == 2)
2768 {
2769 if (*argv[0] == '8')
2770 {
2771 if (host.password)
paul05865c92005-10-26 05:49:54 +00002772 XFREE (MTYPE_HOST, host.password);
paul718e3742002-12-13 20:15:29 +00002773 host.password = NULL;
2774 if (host.password_encrypt)
paul05865c92005-10-26 05:49:54 +00002775 XFREE (MTYPE_HOST, host.password_encrypt);
2776 host.password_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
paul718e3742002-12-13 20:15:29 +00002777 return CMD_SUCCESS;
2778 }
2779 else
2780 {
2781 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2782 return CMD_WARNING;
2783 }
2784 }
2785
2786 if (!isalnum ((int) *argv[0]))
2787 {
2788 vty_out (vty,
2789 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2790 return CMD_WARNING;
2791 }
2792
2793 if (host.password)
paul05865c92005-10-26 05:49:54 +00002794 XFREE (MTYPE_HOST, host.password);
paul718e3742002-12-13 20:15:29 +00002795 host.password = NULL;
2796
2797 if (host.encrypt)
2798 {
2799 if (host.password_encrypt)
paul05865c92005-10-26 05:49:54 +00002800 XFREE (MTYPE_HOST, host.password_encrypt);
2801 host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
paul718e3742002-12-13 20:15:29 +00002802 }
2803 else
paul05865c92005-10-26 05:49:54 +00002804 host.password = XSTRDUP (MTYPE_HOST, argv[0]);
paul718e3742002-12-13 20:15:29 +00002805
2806 return CMD_SUCCESS;
2807}
2808
2809ALIAS (config_password, password_text_cmd,
2810 "password LINE",
2811 "Assign the terminal connection password\n"
2812 "The UNENCRYPTED (cleartext) line password\n")
2813
2814/* VTY enable password set. */
2815DEFUN (config_enable_password, enable_password_cmd,
2816 "enable password (8|) WORD",
2817 "Modify enable password parameters\n"
2818 "Assign the privileged level password\n"
2819 "Specifies a HIDDEN password will follow\n"
2820 "dummy string \n"
2821 "The HIDDEN 'enable' password string\n")
2822{
2823 /* Argument check. */
2824 if (argc == 0)
2825 {
2826 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2827 return CMD_WARNING;
2828 }
2829
2830 /* Crypt type is specified. */
2831 if (argc == 2)
2832 {
2833 if (*argv[0] == '8')
2834 {
2835 if (host.enable)
paul05865c92005-10-26 05:49:54 +00002836 XFREE (MTYPE_HOST, host.enable);
paul718e3742002-12-13 20:15:29 +00002837 host.enable = NULL;
2838
2839 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002840 XFREE (MTYPE_HOST, host.enable_encrypt);
2841 host.enable_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
paul718e3742002-12-13 20:15:29 +00002842
2843 return CMD_SUCCESS;
2844 }
2845 else
2846 {
2847 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2848 return CMD_WARNING;
2849 }
2850 }
2851
2852 if (!isalnum ((int) *argv[0]))
2853 {
2854 vty_out (vty,
2855 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2856 return CMD_WARNING;
2857 }
2858
2859 if (host.enable)
paul05865c92005-10-26 05:49:54 +00002860 XFREE (MTYPE_HOST, host.enable);
paul718e3742002-12-13 20:15:29 +00002861 host.enable = NULL;
2862
2863 /* Plain password input. */
2864 if (host.encrypt)
2865 {
2866 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002867 XFREE (MTYPE_HOST, host.enable_encrypt);
2868 host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
paul718e3742002-12-13 20:15:29 +00002869 }
2870 else
paul05865c92005-10-26 05:49:54 +00002871 host.enable = XSTRDUP (MTYPE_HOST, argv[0]);
paul718e3742002-12-13 20:15:29 +00002872
2873 return CMD_SUCCESS;
2874}
2875
2876ALIAS (config_enable_password,
2877 enable_password_text_cmd,
2878 "enable password LINE",
2879 "Modify enable password parameters\n"
2880 "Assign the privileged level password\n"
2881 "The UNENCRYPTED (cleartext) 'enable' password\n")
2882
2883/* VTY enable password delete. */
2884DEFUN (no_config_enable_password, no_enable_password_cmd,
2885 "no enable password",
2886 NO_STR
2887 "Modify enable password parameters\n"
2888 "Assign the privileged level password\n")
2889{
2890 if (host.enable)
paul05865c92005-10-26 05:49:54 +00002891 XFREE (MTYPE_HOST, host.enable);
paul718e3742002-12-13 20:15:29 +00002892 host.enable = NULL;
2893
2894 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002895 XFREE (MTYPE_HOST, host.enable_encrypt);
paul718e3742002-12-13 20:15:29 +00002896 host.enable_encrypt = NULL;
2897
2898 return CMD_SUCCESS;
2899}
2900
2901DEFUN (service_password_encrypt,
2902 service_password_encrypt_cmd,
2903 "service password-encryption",
2904 "Set up miscellaneous service\n"
2905 "Enable encrypted passwords\n")
2906{
2907 if (host.encrypt)
2908 return CMD_SUCCESS;
2909
2910 host.encrypt = 1;
2911
2912 if (host.password)
2913 {
2914 if (host.password_encrypt)
paul05865c92005-10-26 05:49:54 +00002915 XFREE (MTYPE_HOST, host.password_encrypt);
2916 host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.password));
paul718e3742002-12-13 20:15:29 +00002917 }
2918 if (host.enable)
2919 {
2920 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002921 XFREE (MTYPE_HOST, host.enable_encrypt);
2922 host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.enable));
paul718e3742002-12-13 20:15:29 +00002923 }
2924
2925 return CMD_SUCCESS;
2926}
2927
2928DEFUN (no_service_password_encrypt,
2929 no_service_password_encrypt_cmd,
2930 "no service password-encryption",
2931 NO_STR
2932 "Set up miscellaneous service\n"
2933 "Enable encrypted passwords\n")
2934{
2935 if (! host.encrypt)
2936 return CMD_SUCCESS;
2937
2938 host.encrypt = 0;
2939
2940 if (host.password_encrypt)
paul05865c92005-10-26 05:49:54 +00002941 XFREE (MTYPE_HOST, host.password_encrypt);
paul718e3742002-12-13 20:15:29 +00002942 host.password_encrypt = NULL;
2943
2944 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002945 XFREE (MTYPE_HOST, host.enable_encrypt);
paul718e3742002-12-13 20:15:29 +00002946 host.enable_encrypt = NULL;
2947
2948 return CMD_SUCCESS;
2949}
2950
2951DEFUN (config_terminal_length, config_terminal_length_cmd,
2952 "terminal length <0-512>",
2953 "Set terminal line parameters\n"
2954 "Set number of lines on a screen\n"
2955 "Number of lines on screen (0 for no pausing)\n")
2956{
2957 int lines;
2958 char *endptr = NULL;
2959
2960 lines = strtol (argv[0], &endptr, 10);
2961 if (lines < 0 || lines > 512 || *endptr != '\0')
2962 {
2963 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2964 return CMD_WARNING;
2965 }
2966 vty->lines = lines;
2967
2968 return CMD_SUCCESS;
2969}
2970
2971DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
2972 "terminal no length",
2973 "Set terminal line parameters\n"
2974 NO_STR
2975 "Set number of lines on a screen\n")
2976{
2977 vty->lines = -1;
2978 return CMD_SUCCESS;
2979}
2980
2981DEFUN (service_terminal_length, service_terminal_length_cmd,
2982 "service terminal-length <0-512>",
2983 "Set up miscellaneous service\n"
2984 "System wide terminal length configuration\n"
2985 "Number of lines of VTY (0 means no line control)\n")
2986{
2987 int lines;
2988 char *endptr = NULL;
2989
2990 lines = strtol (argv[0], &endptr, 10);
2991 if (lines < 0 || lines > 512 || *endptr != '\0')
2992 {
2993 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2994 return CMD_WARNING;
2995 }
2996 host.lines = lines;
2997
2998 return CMD_SUCCESS;
2999}
3000
3001DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
3002 "no service terminal-length [<0-512>]",
3003 NO_STR
3004 "Set up miscellaneous service\n"
3005 "System wide terminal length configuration\n"
3006 "Number of lines of VTY (0 means no line control)\n")
3007{
3008 host.lines = -1;
3009 return CMD_SUCCESS;
3010}
3011
ajs2885f722004-12-17 23:16:33 +00003012DEFUN_HIDDEN (do_echo,
3013 echo_cmd,
3014 "echo .MESSAGE",
3015 "Echo a message back to the vty\n"
3016 "The message to echo\n")
3017{
3018 char *message;
3019
ajsf6834d42005-01-28 20:28:35 +00003020 vty_out (vty, "%s%s", ((message = argv_concat(argv, argc, 0)) ? message : ""),
3021 VTY_NEWLINE);
3022 if (message)
3023 XFREE(MTYPE_TMP, message);
ajs2885f722004-12-17 23:16:33 +00003024 return CMD_SUCCESS;
3025}
3026
ajs274a4a42004-12-07 15:39:31 +00003027DEFUN (config_logmsg,
3028 config_logmsg_cmd,
3029 "logmsg "LOG_LEVELS" .MESSAGE",
3030 "Send a message to enabled logging destinations\n"
3031 LOG_LEVEL_DESC
3032 "The message to send\n")
3033{
3034 int level;
3035 char *message;
3036
3037 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3038 return CMD_ERR_NO_MATCH;
3039
ajsf6834d42005-01-28 20:28:35 +00003040 zlog(NULL, level, ((message = argv_concat(argv, argc, 1)) ? message : ""));
3041 if (message)
3042 XFREE(MTYPE_TMP, message);
ajs274a4a42004-12-07 15:39:31 +00003043 return CMD_SUCCESS;
3044}
3045
3046DEFUN (show_logging,
3047 show_logging_cmd,
3048 "show logging",
3049 SHOW_STR
3050 "Show current logging configuration\n")
3051{
3052 struct zlog *zl = zlog_default;
3053
3054 vty_out (vty, "Syslog logging: ");
3055 if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED)
3056 vty_out (vty, "disabled");
3057 else
3058 vty_out (vty, "level %s, facility %s, ident %s",
3059 zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]],
3060 facility_name(zl->facility), zl->ident);
3061 vty_out (vty, "%s", VTY_NEWLINE);
3062
3063 vty_out (vty, "Stdout logging: ");
3064 if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED)
3065 vty_out (vty, "disabled");
3066 else
3067 vty_out (vty, "level %s",
3068 zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
3069 vty_out (vty, "%s", VTY_NEWLINE);
3070
3071 vty_out (vty, "Monitor logging: ");
3072 if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
3073 vty_out (vty, "disabled");
3074 else
3075 vty_out (vty, "level %s",
3076 zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
3077 vty_out (vty, "%s", VTY_NEWLINE);
3078
3079 vty_out (vty, "File logging: ");
3080 if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) ||
3081 !zl->fp)
3082 vty_out (vty, "disabled");
3083 else
3084 vty_out (vty, "level %s, filename %s",
3085 zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
3086 zl->filename);
3087 vty_out (vty, "%s", VTY_NEWLINE);
3088
3089 vty_out (vty, "Protocol name: %s%s",
3090 zlog_proto_names[zl->protocol], VTY_NEWLINE);
3091 vty_out (vty, "Record priority: %s%s",
3092 (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE);
3093
3094 return CMD_SUCCESS;
3095}
3096
paul718e3742002-12-13 20:15:29 +00003097DEFUN (config_log_stdout,
3098 config_log_stdout_cmd,
3099 "log stdout",
3100 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003101 "Set stdout logging level\n")
paul718e3742002-12-13 20:15:29 +00003102{
ajs274a4a42004-12-07 15:39:31 +00003103 zlog_set_level (NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl);
3104 return CMD_SUCCESS;
3105}
3106
3107DEFUN (config_log_stdout_level,
3108 config_log_stdout_level_cmd,
3109 "log stdout "LOG_LEVELS,
3110 "Logging control\n"
3111 "Set stdout logging level\n"
3112 LOG_LEVEL_DESC)
3113{
3114 int level;
3115
3116 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3117 return CMD_ERR_NO_MATCH;
3118 zlog_set_level (NULL, ZLOG_DEST_STDOUT, level);
paul718e3742002-12-13 20:15:29 +00003119 return CMD_SUCCESS;
3120}
3121
3122DEFUN (no_config_log_stdout,
3123 no_config_log_stdout_cmd,
ajs274a4a42004-12-07 15:39:31 +00003124 "no log stdout [LEVEL]",
paul718e3742002-12-13 20:15:29 +00003125 NO_STR
3126 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003127 "Cancel logging to stdout\n"
3128 "Logging level\n")
paul718e3742002-12-13 20:15:29 +00003129{
ajs274a4a42004-12-07 15:39:31 +00003130 zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED);
paul718e3742002-12-13 20:15:29 +00003131 return CMD_SUCCESS;
3132}
3133
ajs274a4a42004-12-07 15:39:31 +00003134DEFUN (config_log_monitor,
3135 config_log_monitor_cmd,
3136 "log monitor",
paul718e3742002-12-13 20:15:29 +00003137 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003138 "Set terminal line (monitor) logging level\n")
3139{
3140 zlog_set_level (NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl);
3141 return CMD_SUCCESS;
3142}
3143
3144DEFUN (config_log_monitor_level,
3145 config_log_monitor_level_cmd,
3146 "log monitor "LOG_LEVELS,
3147 "Logging control\n"
3148 "Set terminal line (monitor) logging level\n"
3149 LOG_LEVEL_DESC)
3150{
3151 int level;
3152
3153 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3154 return CMD_ERR_NO_MATCH;
3155 zlog_set_level (NULL, ZLOG_DEST_MONITOR, level);
3156 return CMD_SUCCESS;
3157}
3158
3159DEFUN (no_config_log_monitor,
3160 no_config_log_monitor_cmd,
3161 "no log monitor [LEVEL]",
3162 NO_STR
3163 "Logging control\n"
3164 "Disable terminal line (monitor) logging\n"
3165 "Logging level\n")
3166{
3167 zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
3168 return CMD_SUCCESS;
3169}
3170
3171static int
3172set_log_file(struct vty *vty, const char *fname, int loglevel)
paul718e3742002-12-13 20:15:29 +00003173{
3174 int ret;
paul9035efa2004-10-10 11:56:56 +00003175 char *p = NULL;
3176 const char *fullpath;
3177
paul718e3742002-12-13 20:15:29 +00003178 /* Path detection. */
ajs274a4a42004-12-07 15:39:31 +00003179 if (! IS_DIRECTORY_SEP (*fname))
paul718e3742002-12-13 20:15:29 +00003180 {
paul9035efa2004-10-10 11:56:56 +00003181 char cwd[MAXPATHLEN+1];
3182 cwd[MAXPATHLEN] = '\0';
3183
3184 if (getcwd (cwd, MAXPATHLEN) == NULL)
3185 {
3186 zlog_err ("config_log_file: Unable to alloc mem!");
3187 return CMD_WARNING;
3188 }
3189
ajs274a4a42004-12-07 15:39:31 +00003190 if ( (p = XMALLOC (MTYPE_TMP, strlen (cwd) + strlen (fname) + 2))
paul9035efa2004-10-10 11:56:56 +00003191 == NULL)
3192 {
3193 zlog_err ("config_log_file: Unable to alloc mem!");
3194 return CMD_WARNING;
3195 }
ajs274a4a42004-12-07 15:39:31 +00003196 sprintf (p, "%s/%s", cwd, fname);
paul9035efa2004-10-10 11:56:56 +00003197 fullpath = p;
paul718e3742002-12-13 20:15:29 +00003198 }
3199 else
ajs274a4a42004-12-07 15:39:31 +00003200 fullpath = fname;
paul718e3742002-12-13 20:15:29 +00003201
ajs274a4a42004-12-07 15:39:31 +00003202 ret = zlog_set_file (NULL, fullpath, loglevel);
paul718e3742002-12-13 20:15:29 +00003203
paul9035efa2004-10-10 11:56:56 +00003204 if (p)
3205 XFREE (MTYPE_TMP, p);
3206
paul718e3742002-12-13 20:15:29 +00003207 if (!ret)
3208 {
ajs274a4a42004-12-07 15:39:31 +00003209 vty_out (vty, "can't open logfile %s\n", fname);
paul718e3742002-12-13 20:15:29 +00003210 return CMD_WARNING;
3211 }
3212
3213 if (host.logfile)
paul05865c92005-10-26 05:49:54 +00003214 XFREE (MTYPE_HOST, host.logfile);
paul718e3742002-12-13 20:15:29 +00003215
paul05865c92005-10-26 05:49:54 +00003216 host.logfile = XSTRDUP (MTYPE_HOST, fname);
paul718e3742002-12-13 20:15:29 +00003217
3218 return CMD_SUCCESS;
3219}
3220
ajs274a4a42004-12-07 15:39:31 +00003221DEFUN (config_log_file,
3222 config_log_file_cmd,
3223 "log file FILENAME",
3224 "Logging control\n"
3225 "Logging to file\n"
3226 "Logging filename\n")
3227{
3228 return set_log_file(vty, argv[0], zlog_default->default_lvl);
3229}
3230
3231DEFUN (config_log_file_level,
3232 config_log_file_level_cmd,
3233 "log file FILENAME "LOG_LEVELS,
3234 "Logging control\n"
3235 "Logging to file\n"
3236 "Logging filename\n"
3237 LOG_LEVEL_DESC)
3238{
3239 int level;
3240
3241 if ((level = level_match(argv[1])) == ZLOG_DISABLED)
3242 return CMD_ERR_NO_MATCH;
3243 return set_log_file(vty, argv[0], level);
3244}
3245
paul718e3742002-12-13 20:15:29 +00003246DEFUN (no_config_log_file,
3247 no_config_log_file_cmd,
3248 "no log file [FILENAME]",
3249 NO_STR
3250 "Logging control\n"
3251 "Cancel logging to file\n"
3252 "Logging file name\n")
3253{
3254 zlog_reset_file (NULL);
3255
3256 if (host.logfile)
paul05865c92005-10-26 05:49:54 +00003257 XFREE (MTYPE_HOST, host.logfile);
paul718e3742002-12-13 20:15:29 +00003258
3259 host.logfile = NULL;
3260
3261 return CMD_SUCCESS;
3262}
3263
ajs274a4a42004-12-07 15:39:31 +00003264ALIAS (no_config_log_file,
3265 no_config_log_file_level_cmd,
3266 "no log file FILENAME LEVEL",
3267 NO_STR
3268 "Logging control\n"
3269 "Cancel logging to file\n"
3270 "Logging file name\n"
3271 "Logging level\n")
3272
paul718e3742002-12-13 20:15:29 +00003273DEFUN (config_log_syslog,
3274 config_log_syslog_cmd,
3275 "log syslog",
3276 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003277 "Set syslog logging level\n")
paul718e3742002-12-13 20:15:29 +00003278{
ajs274a4a42004-12-07 15:39:31 +00003279 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
paul12ab19f2003-07-26 06:14:55 +00003280 return CMD_SUCCESS;
3281}
3282
ajs274a4a42004-12-07 15:39:31 +00003283DEFUN (config_log_syslog_level,
3284 config_log_syslog_level_cmd,
3285 "log syslog "LOG_LEVELS,
paul12ab19f2003-07-26 06:14:55 +00003286 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003287 "Set syslog logging level\n"
3288 LOG_LEVEL_DESC)
paul12ab19f2003-07-26 06:14:55 +00003289{
ajs274a4a42004-12-07 15:39:31 +00003290 int level;
paul12ab19f2003-07-26 06:14:55 +00003291
ajs274a4a42004-12-07 15:39:31 +00003292 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3293 return CMD_ERR_NO_MATCH;
3294 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, level);
3295 return CMD_SUCCESS;
3296}
paul12ab19f2003-07-26 06:14:55 +00003297
ajs274a4a42004-12-07 15:39:31 +00003298DEFUN_DEPRECATED (config_log_syslog_facility,
3299 config_log_syslog_facility_cmd,
3300 "log syslog facility "LOG_FACILITIES,
3301 "Logging control\n"
3302 "Logging goes to syslog\n"
3303 "(Deprecated) Facility parameter for syslog messages\n"
3304 LOG_FACILITY_DESC)
3305{
3306 int facility;
paul12ab19f2003-07-26 06:14:55 +00003307
ajs274a4a42004-12-07 15:39:31 +00003308 if ((facility = facility_match(argv[0])) < 0)
3309 return CMD_ERR_NO_MATCH;
3310
3311 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
paul12ab19f2003-07-26 06:14:55 +00003312 zlog_default->facility = facility;
paul718e3742002-12-13 20:15:29 +00003313 return CMD_SUCCESS;
3314}
3315
3316DEFUN (no_config_log_syslog,
3317 no_config_log_syslog_cmd,
ajs274a4a42004-12-07 15:39:31 +00003318 "no log syslog [LEVEL]",
paul718e3742002-12-13 20:15:29 +00003319 NO_STR
3320 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003321 "Cancel logging to syslog\n"
3322 "Logging level\n")
paul718e3742002-12-13 20:15:29 +00003323{
ajs274a4a42004-12-07 15:39:31 +00003324 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
paul718e3742002-12-13 20:15:29 +00003325 return CMD_SUCCESS;
3326}
3327
paul12ab19f2003-07-26 06:14:55 +00003328ALIAS (no_config_log_syslog,
3329 no_config_log_syslog_facility_cmd,
ajs274a4a42004-12-07 15:39:31 +00003330 "no log syslog facility "LOG_FACILITIES,
paul12ab19f2003-07-26 06:14:55 +00003331 NO_STR
3332 "Logging control\n"
3333 "Logging goes to syslog\n"
3334 "Facility parameter for syslog messages\n"
ajs274a4a42004-12-07 15:39:31 +00003335 LOG_FACILITY_DESC)
paul12ab19f2003-07-26 06:14:55 +00003336
ajs274a4a42004-12-07 15:39:31 +00003337DEFUN (config_log_facility,
3338 config_log_facility_cmd,
3339 "log facility "LOG_FACILITIES,
paul718e3742002-12-13 20:15:29 +00003340 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003341 "Facility parameter for syslog messages\n"
3342 LOG_FACILITY_DESC)
paul718e3742002-12-13 20:15:29 +00003343{
ajs274a4a42004-12-07 15:39:31 +00003344 int facility;
3345
3346 if ((facility = facility_match(argv[0])) < 0)
3347 return CMD_ERR_NO_MATCH;
3348 zlog_default->facility = facility;
3349 return CMD_SUCCESS;
paul718e3742002-12-13 20:15:29 +00003350}
3351
ajs274a4a42004-12-07 15:39:31 +00003352DEFUN (no_config_log_facility,
3353 no_config_log_facility_cmd,
3354 "no log facility [FACILITY]",
paul718e3742002-12-13 20:15:29 +00003355 NO_STR
3356 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003357 "Reset syslog facility to default (daemon)\n"
3358 "Syslog facility\n")
paul718e3742002-12-13 20:15:29 +00003359{
ajs274a4a42004-12-07 15:39:31 +00003360 zlog_default->facility = LOG_DAEMON;
3361 return CMD_SUCCESS;
3362}
3363
3364DEFUN_DEPRECATED (config_log_trap,
3365 config_log_trap_cmd,
3366 "log trap "LOG_LEVELS,
3367 "Logging control\n"
3368 "(Deprecated) Set logging level and default for all destinations\n"
3369 LOG_LEVEL_DESC)
3370{
3371 int new_level ;
3372 int i;
3373
3374 if ((new_level = level_match(argv[0])) == ZLOG_DISABLED)
3375 return CMD_ERR_NO_MATCH;
3376
3377 zlog_default->default_lvl = new_level;
3378 for (i = 0; i < ZLOG_NUM_DESTS; i++)
3379 if (zlog_default->maxlvl[i] != ZLOG_DISABLED)
3380 zlog_default->maxlvl[i] = new_level;
3381 return CMD_SUCCESS;
3382}
3383
3384DEFUN_DEPRECATED (no_config_log_trap,
3385 no_config_log_trap_cmd,
3386 "no log trap [LEVEL]",
3387 NO_STR
3388 "Logging control\n"
3389 "Permit all logging information\n"
3390 "Logging level\n")
3391{
3392 zlog_default->default_lvl = LOG_DEBUG;
paul718e3742002-12-13 20:15:29 +00003393 return CMD_SUCCESS;
3394}
3395
3396DEFUN (config_log_record_priority,
3397 config_log_record_priority_cmd,
3398 "log record-priority",
3399 "Logging control\n"
3400 "Log the priority of the message within the message\n")
3401{
3402 zlog_default->record_priority = 1 ;
3403 return CMD_SUCCESS;
3404}
3405
3406DEFUN (no_config_log_record_priority,
3407 no_config_log_record_priority_cmd,
3408 "no log record-priority",
3409 NO_STR
3410 "Logging control\n"
3411 "Do not log the priority of the message within the message\n")
3412{
3413 zlog_default->record_priority = 0 ;
3414 return CMD_SUCCESS;
3415}
3416
paul3b0c5d92005-03-08 10:43:43 +00003417DEFUN (banner_motd_file,
3418 banner_motd_file_cmd,
3419 "banner motd file [FILE]",
3420 "Set banner\n"
3421 "Banner for motd\n"
3422 "Banner from a file\n"
3423 "Filename\n")
3424{
paulb45da6f2005-03-08 15:16:57 +00003425 if (host.motdfile)
paul05865c92005-10-26 05:49:54 +00003426 XFREE (MTYPE_HOST, host.motdfile);
3427 host.motdfile = XSTRDUP (MTYPE_HOST, argv[0]);
paulb45da6f2005-03-08 15:16:57 +00003428
paul3b0c5d92005-03-08 10:43:43 +00003429 return CMD_SUCCESS;
3430}
paul718e3742002-12-13 20:15:29 +00003431
3432DEFUN (banner_motd_default,
3433 banner_motd_default_cmd,
3434 "banner motd default",
3435 "Set banner string\n"
3436 "Strings for motd\n"
3437 "Default string\n")
3438{
3439 host.motd = default_motd;
3440 return CMD_SUCCESS;
3441}
3442
3443DEFUN (no_banner_motd,
3444 no_banner_motd_cmd,
3445 "no banner motd",
3446 NO_STR
3447 "Set banner string\n"
3448 "Strings for motd\n")
3449{
3450 host.motd = NULL;
paul22085182005-03-08 16:00:12 +00003451 if (host.motdfile)
paul05865c92005-10-26 05:49:54 +00003452 XFREE (MTYPE_HOST, host.motdfile);
paul3b0c5d92005-03-08 10:43:43 +00003453 host.motdfile = NULL;
paul718e3742002-12-13 20:15:29 +00003454 return CMD_SUCCESS;
3455}
3456
3457/* Set config filename. Called from vty.c */
3458void
3459host_config_set (char *filename)
3460{
paul05865c92005-10-26 05:49:54 +00003461 host.config = XSTRDUP (MTYPE_HOST, filename);
paul718e3742002-12-13 20:15:29 +00003462}
3463
3464void
3465install_default (enum node_type node)
3466{
3467 install_element (node, &config_exit_cmd);
3468 install_element (node, &config_quit_cmd);
3469 install_element (node, &config_end_cmd);
3470 install_element (node, &config_help_cmd);
3471 install_element (node, &config_list_cmd);
3472
3473 install_element (node, &config_write_terminal_cmd);
3474 install_element (node, &config_write_file_cmd);
3475 install_element (node, &config_write_memory_cmd);
3476 install_element (node, &config_write_cmd);
3477 install_element (node, &show_running_config_cmd);
3478}
3479
3480/* Initialize command interface. Install basic nodes and commands. */
3481void
3482cmd_init (int terminal)
3483{
3484 /* Allocate initial top vector of commands. */
3485 cmdvec = vector_init (VECTOR_MIN_SIZE);
3486
3487 /* Default host value settings. */
3488 host.name = NULL;
3489 host.password = NULL;
3490 host.enable = NULL;
3491 host.logfile = NULL;
3492 host.config = NULL;
3493 host.lines = -1;
3494 host.motd = default_motd;
paul3b0c5d92005-03-08 10:43:43 +00003495 host.motdfile = NULL;
paul718e3742002-12-13 20:15:29 +00003496
3497 /* Install top nodes. */
3498 install_node (&view_node, NULL);
3499 install_node (&enable_node, NULL);
3500 install_node (&auth_node, NULL);
3501 install_node (&auth_enable_node, NULL);
3502 install_node (&config_node, config_write_host);
3503
3504 /* Each node's basic commands. */
3505 install_element (VIEW_NODE, &show_version_cmd);
3506 if (terminal)
3507 {
3508 install_element (VIEW_NODE, &config_list_cmd);
3509 install_element (VIEW_NODE, &config_exit_cmd);
3510 install_element (VIEW_NODE, &config_quit_cmd);
3511 install_element (VIEW_NODE, &config_help_cmd);
3512 install_element (VIEW_NODE, &config_enable_cmd);
3513 install_element (VIEW_NODE, &config_terminal_length_cmd);
3514 install_element (VIEW_NODE, &config_terminal_no_length_cmd);
ajs274a4a42004-12-07 15:39:31 +00003515 install_element (VIEW_NODE, &show_logging_cmd);
ajs2885f722004-12-17 23:16:33 +00003516 install_element (VIEW_NODE, &echo_cmd);
paul718e3742002-12-13 20:15:29 +00003517 }
3518
3519 if (terminal)
3520 {
3521 install_default (ENABLE_NODE);
3522 install_element (ENABLE_NODE, &config_disable_cmd);
3523 install_element (ENABLE_NODE, &config_terminal_cmd);
3524 install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
3525 }
3526 install_element (ENABLE_NODE, &show_startup_config_cmd);
3527 install_element (ENABLE_NODE, &show_version_cmd);
paul718e3742002-12-13 20:15:29 +00003528
3529 if (terminal)
paul718e3742002-12-13 20:15:29 +00003530 {
hassoe7168df2004-10-03 20:11:32 +00003531 install_element (ENABLE_NODE, &config_terminal_length_cmd);
3532 install_element (ENABLE_NODE, &config_terminal_no_length_cmd);
ajs274a4a42004-12-07 15:39:31 +00003533 install_element (ENABLE_NODE, &show_logging_cmd);
ajs2885f722004-12-17 23:16:33 +00003534 install_element (ENABLE_NODE, &echo_cmd);
ajs274a4a42004-12-07 15:39:31 +00003535 install_element (ENABLE_NODE, &config_logmsg_cmd);
hassoe7168df2004-10-03 20:11:32 +00003536
3537 install_default (CONFIG_NODE);
hassoea8e9d92004-10-07 21:32:14 +00003538 }
3539
3540 install_element (CONFIG_NODE, &hostname_cmd);
3541 install_element (CONFIG_NODE, &no_hostname_cmd);
hassoe7168df2004-10-03 20:11:32 +00003542
hassoea8e9d92004-10-07 21:32:14 +00003543 if (terminal)
3544 {
hassoe7168df2004-10-03 20:11:32 +00003545 install_element (CONFIG_NODE, &password_cmd);
3546 install_element (CONFIG_NODE, &password_text_cmd);
3547 install_element (CONFIG_NODE, &enable_password_cmd);
3548 install_element (CONFIG_NODE, &enable_password_text_cmd);
3549 install_element (CONFIG_NODE, &no_enable_password_cmd);
3550
paul718e3742002-12-13 20:15:29 +00003551 install_element (CONFIG_NODE, &config_log_stdout_cmd);
ajs274a4a42004-12-07 15:39:31 +00003552 install_element (CONFIG_NODE, &config_log_stdout_level_cmd);
paul718e3742002-12-13 20:15:29 +00003553 install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
ajs274a4a42004-12-07 15:39:31 +00003554 install_element (CONFIG_NODE, &config_log_monitor_cmd);
3555 install_element (CONFIG_NODE, &config_log_monitor_level_cmd);
3556 install_element (CONFIG_NODE, &no_config_log_monitor_cmd);
paul718e3742002-12-13 20:15:29 +00003557 install_element (CONFIG_NODE, &config_log_file_cmd);
ajs274a4a42004-12-07 15:39:31 +00003558 install_element (CONFIG_NODE, &config_log_file_level_cmd);
paul718e3742002-12-13 20:15:29 +00003559 install_element (CONFIG_NODE, &no_config_log_file_cmd);
ajs274a4a42004-12-07 15:39:31 +00003560 install_element (CONFIG_NODE, &no_config_log_file_level_cmd);
paul718e3742002-12-13 20:15:29 +00003561 install_element (CONFIG_NODE, &config_log_syslog_cmd);
ajs274a4a42004-12-07 15:39:31 +00003562 install_element (CONFIG_NODE, &config_log_syslog_level_cmd);
paul12ab19f2003-07-26 06:14:55 +00003563 install_element (CONFIG_NODE, &config_log_syslog_facility_cmd);
paul718e3742002-12-13 20:15:29 +00003564 install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
paul12ab19f2003-07-26 06:14:55 +00003565 install_element (CONFIG_NODE, &no_config_log_syslog_facility_cmd);
ajs274a4a42004-12-07 15:39:31 +00003566 install_element (CONFIG_NODE, &config_log_facility_cmd);
3567 install_element (CONFIG_NODE, &no_config_log_facility_cmd);
paul718e3742002-12-13 20:15:29 +00003568 install_element (CONFIG_NODE, &config_log_trap_cmd);
3569 install_element (CONFIG_NODE, &no_config_log_trap_cmd);
3570 install_element (CONFIG_NODE, &config_log_record_priority_cmd);
3571 install_element (CONFIG_NODE, &no_config_log_record_priority_cmd);
3572 install_element (CONFIG_NODE, &service_password_encrypt_cmd);
3573 install_element (CONFIG_NODE, &no_service_password_encrypt_cmd);
3574 install_element (CONFIG_NODE, &banner_motd_default_cmd);
paul3b0c5d92005-03-08 10:43:43 +00003575 install_element (CONFIG_NODE, &banner_motd_file_cmd);
paul718e3742002-12-13 20:15:29 +00003576 install_element (CONFIG_NODE, &no_banner_motd_cmd);
3577 install_element (CONFIG_NODE, &service_terminal_length_cmd);
3578 install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
paul718e3742002-12-13 20:15:29 +00003579
paul354d1192005-04-25 16:26:42 +00003580 install_element (VIEW_NODE, &show_thread_cpu_cmd);
3581 install_element (ENABLE_NODE, &show_thread_cpu_cmd);
3582 install_element (VIEW_NODE, &show_work_queues_cmd);
3583 install_element (ENABLE_NODE, &show_work_queues_cmd);
paul9ab68122003-01-18 01:16:20 +00003584 }
paul718e3742002-12-13 20:15:29 +00003585 srand(time(NULL));
3586}