blob: 83b8a9562d2050448e80b23f9b52e5522223ae73 [file] [log] [blame]
ajs274a4a42004-12-07 15:39:31 +00001/*
paul8cc41982005-05-06 21:25:49 +00002 $Id: command.c,v 1.48 2005/05/06 21:25:49 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. */
38vector cmdvec;
39
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;
478
479 cnode = vector_slot (cmdvec, ntype);
480
481 if (cnode == NULL)
482 {
483 fprintf (stderr, "Command node %d doesn't exist, please check it\n",
484 ntype);
485 exit (1);
486 }
487
488 vector_set (cnode->cmd_vector, cmd);
489
490 cmd->strvec = cmd_make_descvec (cmd->string, cmd->doc);
491 cmd->cmdsize = cmd_cmdsize (cmd->strvec);
492}
493
494static unsigned char itoa64[] =
495"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
496
ajs274a4a42004-12-07 15:39:31 +0000497static void
paul718e3742002-12-13 20:15:29 +0000498to64(char *s, long v, int n)
499{
500 while (--n >= 0)
501 {
502 *s++ = itoa64[v&0x3f];
503 v >>= 6;
504 }
505}
506
ajs274a4a42004-12-07 15:39:31 +0000507static char *
508zencrypt (const char *passwd)
paul718e3742002-12-13 20:15:29 +0000509{
510 char salt[6];
511 struct timeval tv;
512 char *crypt (const char *, const char *);
513
514 gettimeofday(&tv,0);
515
516 to64(&salt[0], random(), 3);
517 to64(&salt[3], tv.tv_usec, 3);
518 salt[5] = '\0';
519
520 return crypt (passwd, salt);
521}
522
523/* This function write configuration of this host. */
ajs274a4a42004-12-07 15:39:31 +0000524static int
paul718e3742002-12-13 20:15:29 +0000525config_write_host (struct vty *vty)
526{
527 if (host.name)
528 vty_out (vty, "hostname %s%s", host.name, VTY_NEWLINE);
529
530 if (host.encrypt)
531 {
532 if (host.password_encrypt)
533 vty_out (vty, "password 8 %s%s", host.password_encrypt, VTY_NEWLINE);
534 if (host.enable_encrypt)
535 vty_out (vty, "enable password 8 %s%s", host.enable_encrypt, VTY_NEWLINE);
536 }
537 else
538 {
539 if (host.password)
540 vty_out (vty, "password %s%s", host.password, VTY_NEWLINE);
541 if (host.enable)
542 vty_out (vty, "enable password %s%s", host.enable, VTY_NEWLINE);
543 }
544
ajs274a4a42004-12-07 15:39:31 +0000545 if (zlog_default->default_lvl != LOG_DEBUG)
ajs82146b82004-12-07 17:15:55 +0000546 {
547 vty_out (vty, "! N.B. The 'log trap' command is deprecated.%s",
548 VTY_NEWLINE);
549 vty_out (vty, "log trap %s%s",
550 zlog_priority[zlog_default->default_lvl], VTY_NEWLINE);
551 }
paul718e3742002-12-13 20:15:29 +0000552
ajs274a4a42004-12-07 15:39:31 +0000553 if (host.logfile && (zlog_default->maxlvl[ZLOG_DEST_FILE] != ZLOG_DISABLED))
paul12ab19f2003-07-26 06:14:55 +0000554 {
ajs274a4a42004-12-07 15:39:31 +0000555 vty_out (vty, "log file %s", host.logfile);
556 if (zlog_default->maxlvl[ZLOG_DEST_FILE] != zlog_default->default_lvl)
557 vty_out (vty, " %s",
558 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_FILE]]);
paul12ab19f2003-07-26 06:14:55 +0000559 vty_out (vty, "%s", VTY_NEWLINE);
560 }
ajs274a4a42004-12-07 15:39:31 +0000561
562 if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != ZLOG_DISABLED)
563 {
564 vty_out (vty, "log stdout");
565 if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != zlog_default->default_lvl)
566 vty_out (vty, " %s",
567 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_STDOUT]]);
568 vty_out (vty, "%s", VTY_NEWLINE);
569 }
570
571 if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
572 vty_out(vty,"no log monitor%s",VTY_NEWLINE);
573 else if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] != zlog_default->default_lvl)
574 vty_out(vty,"log monitor %s%s",
575 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_MONITOR]],VTY_NEWLINE);
576
577 if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED)
578 {
579 vty_out (vty, "log syslog");
580 if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != zlog_default->default_lvl)
581 vty_out (vty, " %s",
582 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_SYSLOG]]);
583 vty_out (vty, "%s", VTY_NEWLINE);
584 }
585
586 if (zlog_default->facility != LOG_DAEMON)
587 vty_out (vty, "log facility %s%s",
588 facility_name(zlog_default->facility), VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +0000589
590 if (zlog_default->record_priority == 1)
591 vty_out (vty, "log record-priority%s", VTY_NEWLINE);
592
593 if (host.advanced)
594 vty_out (vty, "service advanced-vty%s", VTY_NEWLINE);
595
596 if (host.encrypt)
597 vty_out (vty, "service password-encryption%s", VTY_NEWLINE);
598
599 if (host.lines >= 0)
600 vty_out (vty, "service terminal-length %d%s", host.lines,
601 VTY_NEWLINE);
602
paul3b0c5d92005-03-08 10:43:43 +0000603 if (host.motdfile)
604 vty_out (vty, "banner motd file %s%s", host.motdfile, VTY_NEWLINE);
605 else if (! host.motd)
paul718e3742002-12-13 20:15:29 +0000606 vty_out (vty, "no banner motd%s", VTY_NEWLINE);
607
608 return 1;
609}
610
611/* Utility function for getting command vector. */
ajs274a4a42004-12-07 15:39:31 +0000612static vector
paul718e3742002-12-13 20:15:29 +0000613cmd_node_vector (vector v, enum node_type ntype)
614{
615 struct cmd_node *cnode = vector_slot (v, ntype);
616 return cnode->cmd_vector;
617}
618
ajs274a4a42004-12-07 15:39:31 +0000619#if 0
620/* Filter command vector by symbol. This function is not actually used;
621 * should it be deleted? */
622static int
paul718e3742002-12-13 20:15:29 +0000623cmd_filter_by_symbol (char *command, char *symbol)
624{
625 int i, lim;
626
627 if (strcmp (symbol, "IPV4_ADDRESS") == 0)
628 {
629 i = 0;
630 lim = strlen (command);
631 while (i < lim)
632 {
633 if (! (isdigit ((int) command[i]) || command[i] == '.' || command[i] == '/'))
634 return 1;
635 i++;
636 }
637 return 0;
638 }
639 if (strcmp (symbol, "STRING") == 0)
640 {
641 i = 0;
642 lim = strlen (command);
643 while (i < lim)
644 {
645 if (! (isalpha ((int) command[i]) || command[i] == '_' || command[i] == '-'))
646 return 1;
647 i++;
648 }
649 return 0;
650 }
651 if (strcmp (symbol, "IFNAME") == 0)
652 {
653 i = 0;
654 lim = strlen (command);
655 while (i < lim)
656 {
657 if (! isalnum ((int) command[i]))
658 return 1;
659 i++;
660 }
661 return 0;
662 }
663 return 0;
664}
ajs274a4a42004-12-07 15:39:31 +0000665#endif
paul718e3742002-12-13 20:15:29 +0000666
667/* Completion match types. */
668enum match_type
669{
670 no_match,
671 extend_match,
672 ipv4_prefix_match,
673 ipv4_match,
674 ipv6_prefix_match,
675 ipv6_match,
676 range_match,
677 vararg_match,
678 partly_match,
679 exact_match
680};
681
ajs274a4a42004-12-07 15:39:31 +0000682static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000683cmd_ipv4_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000684{
hasso8c328f12004-10-05 21:01:23 +0000685 const char *sp;
paul718e3742002-12-13 20:15:29 +0000686 int dots = 0, nums = 0;
687 char buf[4];
688
689 if (str == NULL)
690 return partly_match;
691
692 for (;;)
693 {
694 memset (buf, 0, sizeof (buf));
695 sp = str;
696 while (*str != '\0')
697 {
698 if (*str == '.')
699 {
700 if (dots >= 3)
701 return no_match;
702
703 if (*(str + 1) == '.')
704 return no_match;
705
706 if (*(str + 1) == '\0')
707 return partly_match;
708
709 dots++;
710 break;
711 }
712 if (!isdigit ((int) *str))
713 return no_match;
714
715 str++;
716 }
717
718 if (str - sp > 3)
719 return no_match;
720
721 strncpy (buf, sp, str - sp);
722 if (atoi (buf) > 255)
723 return no_match;
724
725 nums++;
726
727 if (*str == '\0')
728 break;
729
730 str++;
731 }
732
733 if (nums < 4)
734 return partly_match;
735
736 return exact_match;
737}
738
ajs274a4a42004-12-07 15:39:31 +0000739static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000740cmd_ipv4_prefix_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000741{
hasso8c328f12004-10-05 21:01:23 +0000742 const char *sp;
paul718e3742002-12-13 20:15:29 +0000743 int dots = 0;
744 char buf[4];
745
746 if (str == NULL)
747 return partly_match;
748
749 for (;;)
750 {
751 memset (buf, 0, sizeof (buf));
752 sp = str;
753 while (*str != '\0' && *str != '/')
754 {
755 if (*str == '.')
756 {
757 if (dots == 3)
758 return no_match;
759
760 if (*(str + 1) == '.' || *(str + 1) == '/')
761 return no_match;
762
763 if (*(str + 1) == '\0')
764 return partly_match;
765
766 dots++;
767 break;
768 }
769
770 if (!isdigit ((int) *str))
771 return no_match;
772
773 str++;
774 }
775
776 if (str - sp > 3)
777 return no_match;
778
779 strncpy (buf, sp, str - sp);
780 if (atoi (buf) > 255)
781 return no_match;
782
783 if (dots == 3)
784 {
785 if (*str == '/')
786 {
787 if (*(str + 1) == '\0')
788 return partly_match;
789
790 str++;
791 break;
792 }
793 else if (*str == '\0')
794 return partly_match;
795 }
796
797 if (*str == '\0')
798 return partly_match;
799
800 str++;
801 }
802
803 sp = str;
804 while (*str != '\0')
805 {
806 if (!isdigit ((int) *str))
807 return no_match;
808
809 str++;
810 }
811
812 if (atoi (sp) > 32)
813 return no_match;
814
815 return exact_match;
816}
817
818#define IPV6_ADDR_STR "0123456789abcdefABCDEF:.%"
819#define IPV6_PREFIX_STR "0123456789abcdefABCDEF:.%/"
820#define STATE_START 1
821#define STATE_COLON 2
822#define STATE_DOUBLE 3
823#define STATE_ADDR 4
824#define STATE_DOT 5
825#define STATE_SLASH 6
826#define STATE_MASK 7
827
paul22e0a9e2003-07-11 17:55:46 +0000828#ifdef HAVE_IPV6
829
ajs274a4a42004-12-07 15:39:31 +0000830static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000831cmd_ipv6_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000832{
833 int state = STATE_START;
834 int colons = 0, nums = 0, double_colon = 0;
hasso8c328f12004-10-05 21:01:23 +0000835 const char *sp = NULL;
hasso726f9b22003-05-25 21:04:54 +0000836 struct sockaddr_in6 sin6_dummy;
837 int ret;
paul718e3742002-12-13 20:15:29 +0000838
839 if (str == NULL)
840 return partly_match;
841
842 if (strspn (str, IPV6_ADDR_STR) != strlen (str))
843 return no_match;
844
hasso726f9b22003-05-25 21:04:54 +0000845 /* use inet_pton that has a better support,
846 * for example inet_pton can support the automatic addresses:
847 * ::1.2.3.4
848 */
849 ret = inet_pton(AF_INET6, str, &sin6_dummy.sin6_addr);
850
851 if (ret == 1)
852 return exact_match;
853
paul718e3742002-12-13 20:15:29 +0000854 while (*str != '\0')
855 {
856 switch (state)
857 {
858 case STATE_START:
859 if (*str == ':')
860 {
861 if (*(str + 1) != ':' && *(str + 1) != '\0')
862 return no_match;
863 colons--;
864 state = STATE_COLON;
865 }
866 else
867 {
868 sp = str;
869 state = STATE_ADDR;
870 }
871
872 continue;
873 case STATE_COLON:
874 colons++;
875 if (*(str + 1) == ':')
876 state = STATE_DOUBLE;
877 else
878 {
879 sp = str + 1;
880 state = STATE_ADDR;
881 }
882 break;
883 case STATE_DOUBLE:
884 if (double_colon)
885 return no_match;
886
887 if (*(str + 1) == ':')
888 return no_match;
889 else
890 {
891 if (*(str + 1) != '\0')
892 colons++;
893 sp = str + 1;
894 state = STATE_ADDR;
895 }
896
897 double_colon++;
898 nums++;
899 break;
900 case STATE_ADDR:
901 if (*(str + 1) == ':' || *(str + 1) == '\0')
902 {
903 if (str - sp > 3)
904 return no_match;
905
906 nums++;
907 state = STATE_COLON;
908 }
909 if (*(str + 1) == '.')
910 state = STATE_DOT;
911 break;
912 case STATE_DOT:
913 state = STATE_ADDR;
914 break;
915 default:
916 break;
917 }
918
919 if (nums > 8)
920 return no_match;
921
922 if (colons > 7)
923 return no_match;
924
925 str++;
926 }
927
928#if 0
929 if (nums < 11)
930 return partly_match;
931#endif /* 0 */
932
933 return exact_match;
934}
935
ajs274a4a42004-12-07 15:39:31 +0000936static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000937cmd_ipv6_prefix_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000938{
939 int state = STATE_START;
940 int colons = 0, nums = 0, double_colon = 0;
941 int mask;
hasso8c328f12004-10-05 21:01:23 +0000942 const char *sp = NULL;
paul718e3742002-12-13 20:15:29 +0000943 char *endptr = NULL;
944
945 if (str == NULL)
946 return partly_match;
947
948 if (strspn (str, IPV6_PREFIX_STR) != strlen (str))
949 return no_match;
950
951 while (*str != '\0' && state != STATE_MASK)
952 {
953 switch (state)
954 {
955 case STATE_START:
956 if (*str == ':')
957 {
958 if (*(str + 1) != ':' && *(str + 1) != '\0')
959 return no_match;
960 colons--;
961 state = STATE_COLON;
962 }
963 else
964 {
965 sp = str;
966 state = STATE_ADDR;
967 }
968
969 continue;
970 case STATE_COLON:
971 colons++;
972 if (*(str + 1) == '/')
973 return no_match;
974 else if (*(str + 1) == ':')
975 state = STATE_DOUBLE;
976 else
977 {
978 sp = str + 1;
979 state = STATE_ADDR;
980 }
981 break;
982 case STATE_DOUBLE:
983 if (double_colon)
984 return no_match;
985
986 if (*(str + 1) == ':')
987 return no_match;
988 else
989 {
990 if (*(str + 1) != '\0' && *(str + 1) != '/')
991 colons++;
992 sp = str + 1;
993
994 if (*(str + 1) == '/')
995 state = STATE_SLASH;
996 else
997 state = STATE_ADDR;
998 }
999
1000 double_colon++;
1001 nums += 1;
1002 break;
1003 case STATE_ADDR:
1004 if (*(str + 1) == ':' || *(str + 1) == '.'
1005 || *(str + 1) == '\0' || *(str + 1) == '/')
1006 {
1007 if (str - sp > 3)
1008 return no_match;
1009
1010 for (; sp <= str; sp++)
1011 if (*sp == '/')
1012 return no_match;
1013
1014 nums++;
1015
1016 if (*(str + 1) == ':')
1017 state = STATE_COLON;
1018 else if (*(str + 1) == '.')
1019 state = STATE_DOT;
1020 else if (*(str + 1) == '/')
1021 state = STATE_SLASH;
1022 }
1023 break;
1024 case STATE_DOT:
1025 state = STATE_ADDR;
1026 break;
1027 case STATE_SLASH:
1028 if (*(str + 1) == '\0')
1029 return partly_match;
1030
1031 state = STATE_MASK;
1032 break;
1033 default:
1034 break;
1035 }
1036
1037 if (nums > 11)
1038 return no_match;
1039
1040 if (colons > 7)
1041 return no_match;
1042
1043 str++;
1044 }
1045
1046 if (state < STATE_MASK)
1047 return partly_match;
1048
1049 mask = strtol (str, &endptr, 10);
1050 if (*endptr != '\0')
1051 return no_match;
1052
1053 if (mask < 0 || mask > 128)
1054 return no_match;
1055
1056/* I don't know why mask < 13 makes command match partly.
1057 Forgive me to make this comments. I Want to set static default route
1058 because of lack of function to originate default in ospf6d; sorry
1059 yasu
1060 if (mask < 13)
1061 return partly_match;
1062*/
1063
1064 return exact_match;
1065}
1066
paul22e0a9e2003-07-11 17:55:46 +00001067#endif /* HAVE_IPV6 */
1068
paul718e3742002-12-13 20:15:29 +00001069#define DECIMAL_STRLEN_MAX 10
1070
ajs274a4a42004-12-07 15:39:31 +00001071static int
hasso8c328f12004-10-05 21:01:23 +00001072cmd_range_match (const char *range, const char *str)
paul718e3742002-12-13 20:15:29 +00001073{
1074 char *p;
1075 char buf[DECIMAL_STRLEN_MAX + 1];
1076 char *endptr = NULL;
1077 unsigned long min, max, val;
1078
1079 if (str == NULL)
1080 return 1;
1081
1082 val = strtoul (str, &endptr, 10);
1083 if (*endptr != '\0')
1084 return 0;
1085
1086 range++;
1087 p = strchr (range, '-');
1088 if (p == NULL)
1089 return 0;
1090 if (p - range > DECIMAL_STRLEN_MAX)
1091 return 0;
1092 strncpy (buf, range, p - range);
1093 buf[p - range] = '\0';
1094 min = strtoul (buf, &endptr, 10);
1095 if (*endptr != '\0')
1096 return 0;
1097
1098 range = p + 1;
1099 p = strchr (range, '>');
1100 if (p == NULL)
1101 return 0;
1102 if (p - range > DECIMAL_STRLEN_MAX)
1103 return 0;
1104 strncpy (buf, range, p - range);
1105 buf[p - range] = '\0';
1106 max = strtoul (buf, &endptr, 10);
1107 if (*endptr != '\0')
1108 return 0;
1109
1110 if (val < min || val > max)
1111 return 0;
1112
1113 return 1;
1114}
1115
1116/* Make completion match and return match type flag. */
ajs274a4a42004-12-07 15:39:31 +00001117static enum match_type
hasso8c328f12004-10-05 21:01:23 +00001118cmd_filter_by_completion (char *command, vector v, unsigned int index)
paul718e3742002-12-13 20:15:29 +00001119{
hasso8c328f12004-10-05 21:01:23 +00001120 unsigned int i;
1121 const char *str;
paul718e3742002-12-13 20:15:29 +00001122 struct cmd_element *cmd_element;
1123 enum match_type match_type;
1124 vector descvec;
1125 struct desc *desc;
paul909a2152005-03-14 17:41:45 +00001126
paul718e3742002-12-13 20:15:29 +00001127 match_type = no_match;
1128
1129 /* If command and cmd_element string does not match set NULL to vector */
paul55468c82005-03-14 20:19:01 +00001130 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001131 if ((cmd_element = vector_slot (v, i)) != NULL)
1132 {
paul55468c82005-03-14 20:19:01 +00001133 if (index >= vector_active (cmd_element->strvec))
paul718e3742002-12-13 20:15:29 +00001134 vector_slot (v, i) = NULL;
1135 else
1136 {
hasso8c328f12004-10-05 21:01:23 +00001137 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001138 int matched = 0;
1139
1140 descvec = vector_slot (cmd_element->strvec, index);
paul909a2152005-03-14 17:41:45 +00001141
paul55468c82005-03-14 20:19:01 +00001142 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001143 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001144 {
1145 str = desc->cmd;
1146
1147 if (CMD_VARARG (str))
1148 {
1149 if (match_type < vararg_match)
1150 match_type = vararg_match;
1151 matched++;
1152 }
1153 else if (CMD_RANGE (str))
1154 {
1155 if (cmd_range_match (str, command))
1156 {
1157 if (match_type < range_match)
1158 match_type = range_match;
paul718e3742002-12-13 20:15:29 +00001159
paul909a2152005-03-14 17:41:45 +00001160 matched++;
1161 }
1162 }
paul22e0a9e2003-07-11 17:55:46 +00001163#ifdef HAVE_IPV6
paul909a2152005-03-14 17:41:45 +00001164 else if (CMD_IPV6 (str))
1165 {
1166 if (cmd_ipv6_match (command))
1167 {
1168 if (match_type < ipv6_match)
1169 match_type = ipv6_match;
paul718e3742002-12-13 20:15:29 +00001170
paul909a2152005-03-14 17:41:45 +00001171 matched++;
1172 }
1173 }
1174 else if (CMD_IPV6_PREFIX (str))
1175 {
1176 if (cmd_ipv6_prefix_match (command))
1177 {
1178 if (match_type < ipv6_prefix_match)
1179 match_type = ipv6_prefix_match;
paul718e3742002-12-13 20:15:29 +00001180
paul909a2152005-03-14 17:41:45 +00001181 matched++;
1182 }
1183 }
1184#endif /* HAVE_IPV6 */
1185 else if (CMD_IPV4 (str))
1186 {
1187 if (cmd_ipv4_match (command))
1188 {
1189 if (match_type < ipv4_match)
1190 match_type = ipv4_match;
paul718e3742002-12-13 20:15:29 +00001191
paul909a2152005-03-14 17:41:45 +00001192 matched++;
1193 }
1194 }
1195 else if (CMD_IPV4_PREFIX (str))
1196 {
1197 if (cmd_ipv4_prefix_match (command))
1198 {
1199 if (match_type < ipv4_prefix_match)
1200 match_type = ipv4_prefix_match;
1201 matched++;
1202 }
1203 }
1204 else
1205 /* Check is this point's argument optional ? */
1206 if (CMD_OPTION (str) || CMD_VARIABLE (str))
1207 {
1208 if (match_type < extend_match)
1209 match_type = extend_match;
1210 matched++;
1211 }
1212 else if (strncmp (command, str, strlen (command)) == 0)
1213 {
1214 if (strcmp (command, str) == 0)
1215 match_type = exact_match;
1216 else
1217 {
1218 if (match_type < partly_match)
1219 match_type = partly_match;
1220 }
1221 matched++;
1222 }
1223 }
1224 if (!matched)
paul718e3742002-12-13 20:15:29 +00001225 vector_slot (v, i) = NULL;
1226 }
1227 }
1228 return match_type;
1229}
1230
1231/* Filter vector by command character with index. */
ajs274a4a42004-12-07 15:39:31 +00001232static enum match_type
hasso8c328f12004-10-05 21:01:23 +00001233cmd_filter_by_string (char *command, vector v, unsigned int index)
paul718e3742002-12-13 20:15:29 +00001234{
hasso8c328f12004-10-05 21:01:23 +00001235 unsigned int i;
1236 const char *str;
paul718e3742002-12-13 20:15:29 +00001237 struct cmd_element *cmd_element;
1238 enum match_type match_type;
1239 vector descvec;
1240 struct desc *desc;
paul909a2152005-03-14 17:41:45 +00001241
paul718e3742002-12-13 20:15:29 +00001242 match_type = no_match;
1243
1244 /* If command and cmd_element string does not match set NULL to vector */
paul55468c82005-03-14 20:19:01 +00001245 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001246 if ((cmd_element = vector_slot (v, i)) != NULL)
1247 {
1248 /* If given index is bigger than max string vector of command,
paul909a2152005-03-14 17:41:45 +00001249 set NULL */
paul55468c82005-03-14 20:19:01 +00001250 if (index >= vector_active (cmd_element->strvec))
paul718e3742002-12-13 20:15:29 +00001251 vector_slot (v, i) = NULL;
paul909a2152005-03-14 17:41:45 +00001252 else
paul718e3742002-12-13 20:15:29 +00001253 {
hasso8c328f12004-10-05 21:01:23 +00001254 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001255 int matched = 0;
1256
1257 descvec = vector_slot (cmd_element->strvec, index);
1258
paul55468c82005-03-14 20:19:01 +00001259 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001260 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001261 {
1262 str = desc->cmd;
paul718e3742002-12-13 20:15:29 +00001263
paul909a2152005-03-14 17:41:45 +00001264 if (CMD_VARARG (str))
1265 {
1266 if (match_type < vararg_match)
1267 match_type = vararg_match;
1268 matched++;
1269 }
1270 else if (CMD_RANGE (str))
1271 {
1272 if (cmd_range_match (str, command))
1273 {
1274 if (match_type < range_match)
1275 match_type = range_match;
1276 matched++;
1277 }
1278 }
paul22e0a9e2003-07-11 17:55:46 +00001279#ifdef HAVE_IPV6
paul909a2152005-03-14 17:41:45 +00001280 else if (CMD_IPV6 (str))
1281 {
1282 if (cmd_ipv6_match (command) == exact_match)
1283 {
1284 if (match_type < ipv6_match)
1285 match_type = ipv6_match;
1286 matched++;
1287 }
1288 }
1289 else if (CMD_IPV6_PREFIX (str))
1290 {
1291 if (cmd_ipv6_prefix_match (command) == exact_match)
1292 {
1293 if (match_type < ipv6_prefix_match)
1294 match_type = ipv6_prefix_match;
1295 matched++;
1296 }
1297 }
paul22e0a9e2003-07-11 17:55:46 +00001298#endif /* HAVE_IPV6 */
paul909a2152005-03-14 17:41:45 +00001299 else if (CMD_IPV4 (str))
1300 {
1301 if (cmd_ipv4_match (command) == exact_match)
1302 {
1303 if (match_type < ipv4_match)
1304 match_type = ipv4_match;
1305 matched++;
1306 }
1307 }
1308 else if (CMD_IPV4_PREFIX (str))
1309 {
1310 if (cmd_ipv4_prefix_match (command) == exact_match)
1311 {
1312 if (match_type < ipv4_prefix_match)
1313 match_type = ipv4_prefix_match;
1314 matched++;
1315 }
1316 }
1317 else if (CMD_OPTION (str) || CMD_VARIABLE (str))
1318 {
1319 if (match_type < extend_match)
1320 match_type = extend_match;
1321 matched++;
1322 }
1323 else
1324 {
1325 if (strcmp (command, str) == 0)
1326 {
1327 match_type = exact_match;
1328 matched++;
1329 }
1330 }
1331 }
1332 if (!matched)
paul718e3742002-12-13 20:15:29 +00001333 vector_slot (v, i) = NULL;
1334 }
1335 }
1336 return match_type;
1337}
1338
1339/* Check ambiguous match */
ajs274a4a42004-12-07 15:39:31 +00001340static int
paul718e3742002-12-13 20:15:29 +00001341is_cmd_ambiguous (char *command, vector v, int index, enum match_type type)
1342{
hasso8c328f12004-10-05 21:01:23 +00001343 unsigned int i;
1344 unsigned int j;
1345 const char *str = NULL;
paul718e3742002-12-13 20:15:29 +00001346 struct cmd_element *cmd_element;
hasso8c328f12004-10-05 21:01:23 +00001347 const char *matched = NULL;
paul718e3742002-12-13 20:15:29 +00001348 vector descvec;
1349 struct desc *desc;
paul909a2152005-03-14 17:41:45 +00001350
paul55468c82005-03-14 20:19:01 +00001351 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001352 if ((cmd_element = vector_slot (v, i)) != NULL)
1353 {
1354 int match = 0;
1355
1356 descvec = vector_slot (cmd_element->strvec, index);
1357
paul55468c82005-03-14 20:19:01 +00001358 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001359 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001360 {
1361 enum match_type ret;
1362
1363 str = desc->cmd;
paul718e3742002-12-13 20:15:29 +00001364
paul909a2152005-03-14 17:41:45 +00001365 switch (type)
1366 {
1367 case exact_match:
1368 if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
1369 && strcmp (command, str) == 0)
1370 match++;
1371 break;
1372 case partly_match:
1373 if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
1374 && strncmp (command, str, strlen (command)) == 0)
1375 {
1376 if (matched && strcmp (matched, str) != 0)
1377 return 1; /* There is ambiguous match. */
1378 else
1379 matched = str;
1380 match++;
1381 }
1382 break;
1383 case range_match:
1384 if (cmd_range_match (str, command))
1385 {
1386 if (matched && strcmp (matched, str) != 0)
1387 return 1;
1388 else
1389 matched = str;
1390 match++;
1391 }
1392 break;
1393#ifdef HAVE_IPV6
1394 case ipv6_match:
1395 if (CMD_IPV6 (str))
1396 match++;
1397 break;
1398 case ipv6_prefix_match:
1399 if ((ret = cmd_ipv6_prefix_match (command)) != no_match)
1400 {
1401 if (ret == partly_match)
1402 return 2; /* There is incomplete match. */
paul718e3742002-12-13 20:15:29 +00001403
paul909a2152005-03-14 17:41:45 +00001404 match++;
1405 }
1406 break;
1407#endif /* HAVE_IPV6 */
1408 case ipv4_match:
1409 if (CMD_IPV4 (str))
paul718e3742002-12-13 20:15:29 +00001410 match++;
paul909a2152005-03-14 17:41:45 +00001411 break;
1412 case ipv4_prefix_match:
1413 if ((ret = cmd_ipv4_prefix_match (command)) != no_match)
1414 {
1415 if (ret == partly_match)
1416 return 2; /* There is incomplete match. */
paul718e3742002-12-13 20:15:29 +00001417
paul909a2152005-03-14 17:41:45 +00001418 match++;
1419 }
1420 break;
1421 case extend_match:
1422 if (CMD_OPTION (str) || CMD_VARIABLE (str))
paul718e3742002-12-13 20:15:29 +00001423 match++;
paul909a2152005-03-14 17:41:45 +00001424 break;
1425 case no_match:
1426 default:
1427 break;
1428 }
1429 }
1430 if (!match)
paul718e3742002-12-13 20:15:29 +00001431 vector_slot (v, i) = NULL;
1432 }
1433 return 0;
1434}
1435
1436/* If src matches dst return dst string, otherwise return NULL */
ajs274a4a42004-12-07 15:39:31 +00001437static const char *
hasso8c328f12004-10-05 21:01:23 +00001438cmd_entry_function (const char *src, const char *dst)
paul718e3742002-12-13 20:15:29 +00001439{
1440 /* Skip variable arguments. */
1441 if (CMD_OPTION (dst) || CMD_VARIABLE (dst) || CMD_VARARG (dst) ||
1442 CMD_IPV4 (dst) || CMD_IPV4_PREFIX (dst) || CMD_RANGE (dst))
1443 return NULL;
1444
1445 /* In case of 'command \t', given src is NULL string. */
1446 if (src == NULL)
1447 return dst;
1448
1449 /* Matched with input string. */
1450 if (strncmp (src, dst, strlen (src)) == 0)
1451 return dst;
1452
1453 return NULL;
1454}
1455
1456/* If src matches dst return dst string, otherwise return NULL */
1457/* This version will return the dst string always if it is
1458 CMD_VARIABLE for '?' key processing */
ajs274a4a42004-12-07 15:39:31 +00001459static const char *
hasso8c328f12004-10-05 21:01:23 +00001460cmd_entry_function_desc (const char *src, const char *dst)
paul718e3742002-12-13 20:15:29 +00001461{
1462 if (CMD_VARARG (dst))
1463 return dst;
1464
1465 if (CMD_RANGE (dst))
1466 {
1467 if (cmd_range_match (dst, src))
1468 return dst;
1469 else
1470 return NULL;
1471 }
1472
paul22e0a9e2003-07-11 17:55:46 +00001473#ifdef HAVE_IPV6
paul718e3742002-12-13 20:15:29 +00001474 if (CMD_IPV6 (dst))
1475 {
1476 if (cmd_ipv6_match (src))
1477 return dst;
1478 else
1479 return NULL;
1480 }
1481
1482 if (CMD_IPV6_PREFIX (dst))
1483 {
1484 if (cmd_ipv6_prefix_match (src))
1485 return dst;
1486 else
1487 return NULL;
1488 }
paul22e0a9e2003-07-11 17:55:46 +00001489#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +00001490
1491 if (CMD_IPV4 (dst))
1492 {
1493 if (cmd_ipv4_match (src))
1494 return dst;
1495 else
1496 return NULL;
1497 }
1498
1499 if (CMD_IPV4_PREFIX (dst))
1500 {
1501 if (cmd_ipv4_prefix_match (src))
1502 return dst;
1503 else
1504 return NULL;
1505 }
1506
1507 /* Optional or variable commands always match on '?' */
1508 if (CMD_OPTION (dst) || CMD_VARIABLE (dst))
1509 return dst;
1510
1511 /* In case of 'command \t', given src is NULL string. */
1512 if (src == NULL)
1513 return dst;
1514
1515 if (strncmp (src, dst, strlen (src)) == 0)
1516 return dst;
1517 else
1518 return NULL;
1519}
1520
1521/* Check same string element existence. If it isn't there return
1522 1. */
ajs274a4a42004-12-07 15:39:31 +00001523static int
hasso8c328f12004-10-05 21:01:23 +00001524cmd_unique_string (vector v, const char *str)
paul718e3742002-12-13 20:15:29 +00001525{
hasso8c328f12004-10-05 21:01:23 +00001526 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001527 char *match;
1528
paul55468c82005-03-14 20:19:01 +00001529 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001530 if ((match = vector_slot (v, i)) != NULL)
1531 if (strcmp (match, str) == 0)
1532 return 0;
1533 return 1;
1534}
1535
1536/* Compare string to description vector. If there is same string
1537 return 1 else return 0. */
ajs274a4a42004-12-07 15:39:31 +00001538static int
hasso8c328f12004-10-05 21:01:23 +00001539desc_unique_string (vector v, const char *str)
paul718e3742002-12-13 20:15:29 +00001540{
hasso8c328f12004-10-05 21:01:23 +00001541 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001542 struct desc *desc;
1543
paul55468c82005-03-14 20:19:01 +00001544 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001545 if ((desc = vector_slot (v, i)) != NULL)
1546 if (strcmp (desc->cmd, str) == 0)
1547 return 1;
1548 return 0;
1549}
1550
ajs274a4a42004-12-07 15:39:31 +00001551static int
paulb92938a2002-12-13 21:20:42 +00001552cmd_try_do_shortcut (enum node_type node, char* first_word) {
1553 if ( first_word != NULL &&
1554 node != AUTH_NODE &&
1555 node != VIEW_NODE &&
1556 node != AUTH_ENABLE_NODE &&
1557 node != ENABLE_NODE &&
1558 0 == strcmp( "do", first_word ) )
1559 return 1;
1560 return 0;
1561}
1562
paul718e3742002-12-13 20:15:29 +00001563/* '?' describe command support. */
ajs274a4a42004-12-07 15:39:31 +00001564static vector
paulb92938a2002-12-13 21:20:42 +00001565cmd_describe_command_real (vector vline, struct vty *vty, int *status)
paul718e3742002-12-13 20:15:29 +00001566{
paulb8961472005-03-14 17:35:52 +00001567 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001568 vector cmd_vector;
1569#define INIT_MATCHVEC_SIZE 10
1570 vector matchvec;
1571 struct cmd_element *cmd_element;
paulb8961472005-03-14 17:35:52 +00001572 unsigned int index;
paul54aba542003-08-21 20:28:24 +00001573 int ret;
1574 enum match_type match;
1575 char *command;
paul718e3742002-12-13 20:15:29 +00001576 static struct desc desc_cr = { "<cr>", "" };
1577
1578 /* Set index. */
paul55468c82005-03-14 20:19:01 +00001579 if (vector_active (vline) == 0)
paulb8961472005-03-14 17:35:52 +00001580 {
1581 *status = CMD_ERR_NO_MATCH;
1582 return NULL;
1583 }
1584 else
paul55468c82005-03-14 20:19:01 +00001585 index = vector_active (vline) - 1;
paul909a2152005-03-14 17:41:45 +00001586
paul718e3742002-12-13 20:15:29 +00001587 /* Make copy vector of current node's command vector. */
1588 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1589
1590 /* Prepare match vector */
1591 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1592
1593 /* Filter commands. */
paul54aba542003-08-21 20:28:24 +00001594 /* Only words precedes current word will be checked in this loop. */
paul718e3742002-12-13 20:15:29 +00001595 for (i = 0; i < index; i++)
paulb8961472005-03-14 17:35:52 +00001596 if ((command = vector_slot (vline, i)))
paul909a2152005-03-14 17:41:45 +00001597 {
1598 match = cmd_filter_by_completion (command, cmd_vector, i);
1599
1600 if (match == vararg_match)
1601 {
1602 struct cmd_element *cmd_element;
1603 vector descvec;
1604 unsigned int j, k;
paul718e3742002-12-13 20:15:29 +00001605
paul55468c82005-03-14 20:19:01 +00001606 for (j = 0; j < vector_active (cmd_vector); j++)
paulb8961472005-03-14 17:35:52 +00001607 if ((cmd_element = vector_slot (cmd_vector, j)) != NULL
paul55468c82005-03-14 20:19:01 +00001608 && (vector_active (cmd_element->strvec)))
paul909a2152005-03-14 17:41:45 +00001609 {
1610 descvec = vector_slot (cmd_element->strvec,
paul55468c82005-03-14 20:19:01 +00001611 vector_active (cmd_element->strvec) - 1);
1612 for (k = 0; k < vector_active (descvec); k++)
paul909a2152005-03-14 17:41:45 +00001613 {
1614 struct desc *desc = vector_slot (descvec, k);
1615 vector_set (matchvec, desc);
1616 }
1617 }
1618
1619 vector_set (matchvec, &desc_cr);
1620 vector_free (cmd_vector);
paul718e3742002-12-13 20:15:29 +00001621
paul909a2152005-03-14 17:41:45 +00001622 return matchvec;
1623 }
paul718e3742002-12-13 20:15:29 +00001624
paul909a2152005-03-14 17:41:45 +00001625 if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
1626 {
1627 vector_free (cmd_vector);
1628 *status = CMD_ERR_AMBIGUOUS;
1629 return NULL;
1630 }
1631 else if (ret == 2)
1632 {
1633 vector_free (cmd_vector);
1634 *status = CMD_ERR_NO_MATCH;
1635 return NULL;
1636 }
1637 }
paul718e3742002-12-13 20:15:29 +00001638
1639 /* Prepare match vector */
1640 /* matchvec = vector_init (INIT_MATCHVEC_SIZE); */
1641
paul54aba542003-08-21 20:28:24 +00001642 /* Make sure that cmd_vector is filtered based on current word */
1643 command = vector_slot (vline, index);
1644 if (command)
1645 match = cmd_filter_by_completion (command, cmd_vector, index);
1646
paul718e3742002-12-13 20:15:29 +00001647 /* Make description vector. */
paul55468c82005-03-14 20:19:01 +00001648 for (i = 0; i < vector_active (cmd_vector); i++)
paul718e3742002-12-13 20:15:29 +00001649 if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
1650 {
hasso8c328f12004-10-05 21:01:23 +00001651 const char *string = NULL;
paul718e3742002-12-13 20:15:29 +00001652 vector strvec = cmd_element->strvec;
1653
paul55468c82005-03-14 20:19:01 +00001654 /* if command is NULL, index may be equal to vector_active */
1655 if (command && index >= vector_active (strvec))
paul718e3742002-12-13 20:15:29 +00001656 vector_slot (cmd_vector, i) = NULL;
1657 else
1658 {
paul54aba542003-08-21 20:28:24 +00001659 /* Check if command is completed. */
paul55468c82005-03-14 20:19:01 +00001660 if (command == NULL && index == vector_active (strvec))
paul718e3742002-12-13 20:15:29 +00001661 {
1662 string = "<cr>";
paul909a2152005-03-14 17:41:45 +00001663 if (!desc_unique_string (matchvec, string))
paul718e3742002-12-13 20:15:29 +00001664 vector_set (matchvec, &desc_cr);
1665 }
1666 else
1667 {
hasso8c328f12004-10-05 21:01:23 +00001668 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001669 vector descvec = vector_slot (strvec, index);
1670 struct desc *desc;
1671
paul55468c82005-03-14 20:19:01 +00001672 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001673 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001674 {
1675 string = cmd_entry_function_desc (command, desc->cmd);
1676 if (string)
1677 {
1678 /* Uniqueness check */
1679 if (!desc_unique_string (matchvec, string))
1680 vector_set (matchvec, desc);
1681 }
1682 }
paul718e3742002-12-13 20:15:29 +00001683 }
1684 }
1685 }
1686 vector_free (cmd_vector);
1687
1688 if (vector_slot (matchvec, 0) == NULL)
1689 {
1690 vector_free (matchvec);
paul909a2152005-03-14 17:41:45 +00001691 *status = CMD_ERR_NO_MATCH;
paul718e3742002-12-13 20:15:29 +00001692 }
1693 else
1694 *status = CMD_SUCCESS;
1695
1696 return matchvec;
1697}
1698
paulb92938a2002-12-13 21:20:42 +00001699vector
1700cmd_describe_command (vector vline, struct vty *vty, int *status)
1701{
1702 vector ret;
1703
1704 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1705 {
1706 enum node_type onode;
1707 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00001708 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00001709
1710 onode = vty->node;
1711 vty->node = ENABLE_NODE;
1712 /* We can try it on enable node, cos' the vty is authenticated */
1713
1714 shifted_vline = vector_init (vector_count(vline));
1715 /* use memcpy? */
paul55468c82005-03-14 20:19:01 +00001716 for (index = 1; index < vector_active (vline); index++)
paulb92938a2002-12-13 21:20:42 +00001717 {
1718 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1719 }
1720
1721 ret = cmd_describe_command_real (shifted_vline, vty, status);
1722
1723 vector_free(shifted_vline);
1724 vty->node = onode;
1725 return ret;
1726 }
1727
1728
1729 return cmd_describe_command_real (vline, vty, status);
1730}
1731
1732
paul718e3742002-12-13 20:15:29 +00001733/* Check LCD of matched command. */
ajs274a4a42004-12-07 15:39:31 +00001734static int
paul718e3742002-12-13 20:15:29 +00001735cmd_lcd (char **matched)
1736{
1737 int i;
1738 int j;
1739 int lcd = -1;
1740 char *s1, *s2;
1741 char c1, c2;
1742
1743 if (matched[0] == NULL || matched[1] == NULL)
1744 return 0;
1745
1746 for (i = 1; matched[i] != NULL; i++)
1747 {
1748 s1 = matched[i - 1];
1749 s2 = matched[i];
1750
1751 for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
1752 if (c1 != c2)
1753 break;
1754
1755 if (lcd < 0)
1756 lcd = j;
1757 else
1758 {
1759 if (lcd > j)
1760 lcd = j;
1761 }
1762 }
1763 return lcd;
1764}
1765
1766/* Command line completion support. */
ajs274a4a42004-12-07 15:39:31 +00001767static char **
paulb92938a2002-12-13 21:20:42 +00001768cmd_complete_command_real (vector vline, struct vty *vty, int *status)
paul718e3742002-12-13 20:15:29 +00001769{
paulb8961472005-03-14 17:35:52 +00001770 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001771 vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1772#define INIT_MATCHVEC_SIZE 10
1773 vector matchvec;
1774 struct cmd_element *cmd_element;
paulb8961472005-03-14 17:35:52 +00001775 unsigned int index;
paul718e3742002-12-13 20:15:29 +00001776 char **match_str;
1777 struct desc *desc;
1778 vector descvec;
1779 char *command;
1780 int lcd;
1781
paul55468c82005-03-14 20:19:01 +00001782 if (vector_active (vline) == 0)
paulb8961472005-03-14 17:35:52 +00001783 {
1784 *status = CMD_ERR_NO_MATCH;
1785 return NULL;
1786 }
1787 else
paul55468c82005-03-14 20:19:01 +00001788 index = vector_active (vline) - 1;
paulb8961472005-03-14 17:35:52 +00001789
paul718e3742002-12-13 20:15:29 +00001790 /* First, filter by preceeding command string */
1791 for (i = 0; i < index; i++)
paulb8961472005-03-14 17:35:52 +00001792 if ((command = vector_slot (vline, i)))
paul909a2152005-03-14 17:41:45 +00001793 {
1794 enum match_type match;
1795 int ret;
paul718e3742002-12-13 20:15:29 +00001796
paul909a2152005-03-14 17:41:45 +00001797 /* First try completion match, if there is exactly match return 1 */
1798 match = cmd_filter_by_completion (command, cmd_vector, i);
paul718e3742002-12-13 20:15:29 +00001799
paul909a2152005-03-14 17:41:45 +00001800 /* If there is exact match then filter ambiguous match else check
1801 ambiguousness. */
1802 if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
1803 {
1804 vector_free (cmd_vector);
1805 *status = CMD_ERR_AMBIGUOUS;
1806 return NULL;
1807 }
1808 /*
1809 else if (ret == 2)
1810 {
1811 vector_free (cmd_vector);
1812 *status = CMD_ERR_NO_MATCH;
1813 return NULL;
1814 }
1815 */
1816 }
1817
paul718e3742002-12-13 20:15:29 +00001818 /* Prepare match vector. */
1819 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1820
1821 /* Now we got into completion */
paul55468c82005-03-14 20:19:01 +00001822 for (i = 0; i < vector_active (cmd_vector); i++)
paulb8961472005-03-14 17:35:52 +00001823 if ((cmd_element = vector_slot (cmd_vector, i)))
paul718e3742002-12-13 20:15:29 +00001824 {
hasso8c328f12004-10-05 21:01:23 +00001825 const char *string;
paul718e3742002-12-13 20:15:29 +00001826 vector strvec = cmd_element->strvec;
paul909a2152005-03-14 17:41:45 +00001827
paul718e3742002-12-13 20:15:29 +00001828 /* Check field length */
paul55468c82005-03-14 20:19:01 +00001829 if (index >= vector_active (strvec))
paul718e3742002-12-13 20:15:29 +00001830 vector_slot (cmd_vector, i) = NULL;
paul909a2152005-03-14 17:41:45 +00001831 else
paul718e3742002-12-13 20:15:29 +00001832 {
hasso8c328f12004-10-05 21:01:23 +00001833 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001834
1835 descvec = vector_slot (strvec, index);
paul55468c82005-03-14 20:19:01 +00001836 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001837 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001838 {
paulb8961472005-03-14 17:35:52 +00001839 if ((string =
1840 cmd_entry_function (vector_slot (vline, index),
paul909a2152005-03-14 17:41:45 +00001841 desc->cmd)))
1842 if (cmd_unique_string (matchvec, string))
1843 vector_set (matchvec, XSTRDUP (MTYPE_TMP, string));
1844 }
paul718e3742002-12-13 20:15:29 +00001845 }
1846 }
1847
1848 /* We don't need cmd_vector any more. */
1849 vector_free (cmd_vector);
1850
1851 /* No matched command */
1852 if (vector_slot (matchvec, 0) == NULL)
1853 {
1854 vector_free (matchvec);
1855
1856 /* In case of 'command \t' pattern. Do you need '?' command at
1857 the end of the line. */
1858 if (vector_slot (vline, index) == '\0')
1859 *status = CMD_ERR_NOTHING_TODO;
1860 else
1861 *status = CMD_ERR_NO_MATCH;
1862 return NULL;
1863 }
1864
1865 /* Only one matched */
1866 if (vector_slot (matchvec, 1) == NULL)
1867 {
1868 match_str = (char **) matchvec->index;
1869 vector_only_wrapper_free (matchvec);
1870 *status = CMD_COMPLETE_FULL_MATCH;
1871 return match_str;
1872 }
1873 /* Make it sure last element is NULL. */
1874 vector_set (matchvec, NULL);
1875
1876 /* Check LCD of matched strings. */
1877 if (vector_slot (vline, index) != NULL)
1878 {
1879 lcd = cmd_lcd ((char **) matchvec->index);
1880
1881 if (lcd)
1882 {
1883 int len = strlen (vector_slot (vline, index));
paul909a2152005-03-14 17:41:45 +00001884
paul718e3742002-12-13 20:15:29 +00001885 if (len < lcd)
1886 {
1887 char *lcdstr;
paul909a2152005-03-14 17:41:45 +00001888
paul718e3742002-12-13 20:15:29 +00001889 lcdstr = XMALLOC (MTYPE_TMP, lcd + 1);
1890 memcpy (lcdstr, matchvec->index[0], lcd);
1891 lcdstr[lcd] = '\0';
1892
1893 /* match_str = (char **) &lcdstr; */
1894
1895 /* Free matchvec. */
paul55468c82005-03-14 20:19:01 +00001896 for (i = 0; i < vector_active (matchvec); i++)
paul718e3742002-12-13 20:15:29 +00001897 {
1898 if (vector_slot (matchvec, i))
1899 XFREE (MTYPE_TMP, vector_slot (matchvec, i));
1900 }
1901 vector_free (matchvec);
1902
paul909a2152005-03-14 17:41:45 +00001903 /* Make new matchvec. */
paul718e3742002-12-13 20:15:29 +00001904 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1905 vector_set (matchvec, lcdstr);
1906 match_str = (char **) matchvec->index;
1907 vector_only_wrapper_free (matchvec);
1908
1909 *status = CMD_COMPLETE_MATCH;
1910 return match_str;
1911 }
1912 }
1913 }
1914
1915 match_str = (char **) matchvec->index;
1916 vector_only_wrapper_free (matchvec);
1917 *status = CMD_COMPLETE_LIST_MATCH;
1918 return match_str;
1919}
1920
paulb92938a2002-12-13 21:20:42 +00001921char **
paul9ab68122003-01-18 01:16:20 +00001922cmd_complete_command (vector vline, struct vty *vty, int *status)
paulb92938a2002-12-13 21:20:42 +00001923{
1924 char **ret;
1925
1926 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1927 {
1928 enum node_type onode;
1929 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00001930 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00001931
1932 onode = vty->node;
1933 vty->node = ENABLE_NODE;
1934 /* We can try it on enable node, cos' the vty is authenticated */
1935
1936 shifted_vline = vector_init (vector_count(vline));
1937 /* use memcpy? */
paul55468c82005-03-14 20:19:01 +00001938 for (index = 1; index < vector_active (vline); index++)
paulb92938a2002-12-13 21:20:42 +00001939 {
1940 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1941 }
1942
1943 ret = cmd_complete_command_real (shifted_vline, vty, status);
1944
1945 vector_free(shifted_vline);
1946 vty->node = onode;
1947 return ret;
1948 }
1949
1950
1951 return cmd_complete_command_real (vline, vty, status);
1952}
1953
1954/* return parent node */
1955/* MUST eventually converge on CONFIG_NODE */
hasso13bfca72005-01-23 21:42:25 +00001956enum node_type
ajs274a4a42004-12-07 15:39:31 +00001957node_parent ( enum node_type node )
paulb92938a2002-12-13 21:20:42 +00001958{
1959 enum node_type ret;
1960
paul9ab68122003-01-18 01:16:20 +00001961 assert (node > CONFIG_NODE);
1962
1963 switch (node)
1964 {
1965 case BGP_VPNV4_NODE:
1966 case BGP_IPV4_NODE:
1967 case BGP_IPV4M_NODE:
1968 case BGP_IPV6_NODE:
1969 ret = BGP_NODE;
1970 break;
1971 case KEYCHAIN_KEY_NODE:
1972 ret = KEYCHAIN_NODE;
1973 break;
1974 default:
1975 ret = CONFIG_NODE;
paulb92938a2002-12-13 21:20:42 +00001976 }
1977
1978 return ret;
1979}
1980
paul718e3742002-12-13 20:15:29 +00001981/* Execute command by argument vline vector. */
ajs274a4a42004-12-07 15:39:31 +00001982static int
paulb8961472005-03-14 17:35:52 +00001983cmd_execute_command_real (vector vline, struct vty *vty,
1984 struct cmd_element **cmd)
paul718e3742002-12-13 20:15:29 +00001985{
hasso8c328f12004-10-05 21:01:23 +00001986 unsigned int i;
1987 unsigned int index;
paul718e3742002-12-13 20:15:29 +00001988 vector cmd_vector;
1989 struct cmd_element *cmd_element;
1990 struct cmd_element *matched_element;
1991 unsigned int matched_count, incomplete_count;
1992 int argc;
paul9035efa2004-10-10 11:56:56 +00001993 const char *argv[CMD_ARGC_MAX];
paul718e3742002-12-13 20:15:29 +00001994 enum match_type match = 0;
1995 int varflag;
1996 char *command;
1997
1998 /* Make copy of command elements. */
1999 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2000
paul55468c82005-03-14 20:19:01 +00002001 for (index = 0; index < vector_active (vline); index++)
paulb8961472005-03-14 17:35:52 +00002002 if ((command = vector_slot (vline, index)))
paul909a2152005-03-14 17:41:45 +00002003 {
2004 int ret;
paul718e3742002-12-13 20:15:29 +00002005
paul909a2152005-03-14 17:41:45 +00002006 match = cmd_filter_by_completion (command, cmd_vector, index);
paul718e3742002-12-13 20:15:29 +00002007
paul909a2152005-03-14 17:41:45 +00002008 if (match == vararg_match)
2009 break;
2010
2011 ret = is_cmd_ambiguous (command, cmd_vector, index, match);
paul718e3742002-12-13 20:15:29 +00002012
paul909a2152005-03-14 17:41:45 +00002013 if (ret == 1)
2014 {
2015 vector_free (cmd_vector);
2016 return CMD_ERR_AMBIGUOUS;
2017 }
2018 else if (ret == 2)
2019 {
2020 vector_free (cmd_vector);
2021 return CMD_ERR_NO_MATCH;
2022 }
2023 }
paul718e3742002-12-13 20:15:29 +00002024
2025 /* Check matched count. */
2026 matched_element = NULL;
2027 matched_count = 0;
2028 incomplete_count = 0;
2029
paul55468c82005-03-14 20:19:01 +00002030 for (i = 0; i < vector_active (cmd_vector); i++)
paulb8961472005-03-14 17:35:52 +00002031 if ((cmd_element = vector_slot (cmd_vector, i)))
paul718e3742002-12-13 20:15:29 +00002032 {
paul718e3742002-12-13 20:15:29 +00002033 if (match == vararg_match || index >= cmd_element->cmdsize)
2034 {
2035 matched_element = cmd_element;
2036#if 0
2037 printf ("DEBUG: %s\n", cmd_element->string);
2038#endif
2039 matched_count++;
2040 }
2041 else
2042 {
2043 incomplete_count++;
2044 }
2045 }
paul909a2152005-03-14 17:41:45 +00002046
paul718e3742002-12-13 20:15:29 +00002047 /* Finish of using cmd_vector. */
2048 vector_free (cmd_vector);
2049
paul909a2152005-03-14 17:41:45 +00002050 /* To execute command, matched_count must be 1. */
2051 if (matched_count == 0)
paul718e3742002-12-13 20:15:29 +00002052 {
2053 if (incomplete_count)
2054 return CMD_ERR_INCOMPLETE;
2055 else
2056 return CMD_ERR_NO_MATCH;
2057 }
2058
paul909a2152005-03-14 17:41:45 +00002059 if (matched_count > 1)
paul718e3742002-12-13 20:15:29 +00002060 return CMD_ERR_AMBIGUOUS;
2061
2062 /* Argument treatment */
2063 varflag = 0;
2064 argc = 0;
2065
paul55468c82005-03-14 20:19:01 +00002066 for (i = 0; i < vector_active (vline); i++)
paul718e3742002-12-13 20:15:29 +00002067 {
2068 if (varflag)
2069 argv[argc++] = vector_slot (vline, i);
2070 else
paul909a2152005-03-14 17:41:45 +00002071 {
paul718e3742002-12-13 20:15:29 +00002072 vector descvec = vector_slot (matched_element->strvec, i);
2073
paul55468c82005-03-14 20:19:01 +00002074 if (vector_active (descvec) == 1)
paul718e3742002-12-13 20:15:29 +00002075 {
2076 struct desc *desc = vector_slot (descvec, 0);
paul718e3742002-12-13 20:15:29 +00002077
hasso8c328f12004-10-05 21:01:23 +00002078 if (CMD_VARARG (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002079 varflag = 1;
2080
hasso8c328f12004-10-05 21:01:23 +00002081 if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002082 argv[argc++] = vector_slot (vline, i);
2083 }
2084 else
2085 argv[argc++] = vector_slot (vline, i);
2086 }
2087
2088 if (argc >= CMD_ARGC_MAX)
2089 return CMD_ERR_EXEED_ARGC_MAX;
2090 }
2091
2092 /* For vtysh execution. */
2093 if (cmd)
2094 *cmd = matched_element;
2095
2096 if (matched_element->daemon)
2097 return CMD_SUCCESS_DAEMON;
2098
2099 /* Execute matched command. */
2100 return (*matched_element->func) (matched_element, vty, argc, argv);
2101}
2102
paulb92938a2002-12-13 21:20:42 +00002103int
hasso87d683b2005-01-16 23:31:54 +00002104cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,
2105 int vtysh) {
paul9ab68122003-01-18 01:16:20 +00002106 int ret, saved_ret, tried = 0;
2107 enum node_type onode, try_node;
2108
2109 onode = try_node = vty->node;
paulb92938a2002-12-13 21:20:42 +00002110
2111 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
2112 {
2113 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00002114 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00002115
2116 vty->node = ENABLE_NODE;
2117 /* We can try it on enable node, cos' the vty is authenticated */
2118
2119 shifted_vline = vector_init (vector_count(vline));
2120 /* use memcpy? */
paul55468c82005-03-14 20:19:01 +00002121 for (index = 1; index < vector_active (vline); index++)
paulb92938a2002-12-13 21:20:42 +00002122 {
2123 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
2124 }
2125
2126 ret = cmd_execute_command_real (shifted_vline, vty, cmd);
2127
2128 vector_free(shifted_vline);
2129 vty->node = onode;
2130 return ret;
2131 }
2132
2133
paul9ab68122003-01-18 01:16:20 +00002134 saved_ret = ret = cmd_execute_command_real (vline, vty, cmd);
paulb92938a2002-12-13 21:20:42 +00002135
hasso87d683b2005-01-16 23:31:54 +00002136 if (vtysh)
2137 return saved_ret;
2138
paulb92938a2002-12-13 21:20:42 +00002139 /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
paul9ab68122003-01-18 01:16:20 +00002140 while ( ret != CMD_SUCCESS && ret != CMD_WARNING
paulb92938a2002-12-13 21:20:42 +00002141 && vty->node > CONFIG_NODE )
2142 {
paul9ab68122003-01-18 01:16:20 +00002143 try_node = node_parent(try_node);
2144 vty->node = try_node;
paulb92938a2002-12-13 21:20:42 +00002145 ret = cmd_execute_command_real (vline, vty, cmd);
paul9ab68122003-01-18 01:16:20 +00002146 tried = 1;
2147 if (ret == CMD_SUCCESS || ret == CMD_WARNING)
paulb92938a2002-12-13 21:20:42 +00002148 {
paul9ab68122003-01-18 01:16:20 +00002149 /* succesfull command, leave the node as is */
paulb92938a2002-12-13 21:20:42 +00002150 return ret;
2151 }
paulb92938a2002-12-13 21:20:42 +00002152 }
paul9ab68122003-01-18 01:16:20 +00002153 /* no command succeeded, reset the vty to the original node and
2154 return the error for this node */
2155 if ( tried )
2156 vty->node = onode;
2157 return saved_ret;
pauleda031f2003-01-18 00:39:19 +00002158}
2159
paul718e3742002-12-13 20:15:29 +00002160/* Execute command by argument readline. */
2161int
paul909a2152005-03-14 17:41:45 +00002162cmd_execute_command_strict (vector vline, struct vty *vty,
paul718e3742002-12-13 20:15:29 +00002163 struct cmd_element **cmd)
2164{
hasso8c328f12004-10-05 21:01:23 +00002165 unsigned int i;
2166 unsigned int index;
paul718e3742002-12-13 20:15:29 +00002167 vector cmd_vector;
2168 struct cmd_element *cmd_element;
2169 struct cmd_element *matched_element;
2170 unsigned int matched_count, incomplete_count;
2171 int argc;
paul9035efa2004-10-10 11:56:56 +00002172 const char *argv[CMD_ARGC_MAX];
paul718e3742002-12-13 20:15:29 +00002173 int varflag;
2174 enum match_type match = 0;
2175 char *command;
2176
2177 /* Make copy of command element */
2178 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2179
paul55468c82005-03-14 20:19:01 +00002180 for (index = 0; index < vector_active (vline); index++)
paulb8961472005-03-14 17:35:52 +00002181 if ((command = vector_slot (vline, index)))
paul909a2152005-03-14 17:41:45 +00002182 {
2183 int ret;
2184
2185 match = cmd_filter_by_string (vector_slot (vline, index),
2186 cmd_vector, index);
paul718e3742002-12-13 20:15:29 +00002187
paul909a2152005-03-14 17:41:45 +00002188 /* If command meets '.VARARG' then finish matching. */
2189 if (match == vararg_match)
2190 break;
2191
2192 ret = is_cmd_ambiguous (command, cmd_vector, index, match);
2193 if (ret == 1)
2194 {
2195 vector_free (cmd_vector);
2196 return CMD_ERR_AMBIGUOUS;
2197 }
2198 if (ret == 2)
2199 {
2200 vector_free (cmd_vector);
2201 return CMD_ERR_NO_MATCH;
2202 }
2203 }
paul718e3742002-12-13 20:15:29 +00002204
2205 /* Check matched count. */
2206 matched_element = NULL;
2207 matched_count = 0;
2208 incomplete_count = 0;
paul55468c82005-03-14 20:19:01 +00002209 for (i = 0; i < vector_active (cmd_vector); i++)
paul909a2152005-03-14 17:41:45 +00002210 if (vector_slot (cmd_vector, i) != NULL)
paul718e3742002-12-13 20:15:29 +00002211 {
paul909a2152005-03-14 17:41:45 +00002212 cmd_element = vector_slot (cmd_vector, i);
paul718e3742002-12-13 20:15:29 +00002213
2214 if (match == vararg_match || index >= cmd_element->cmdsize)
2215 {
2216 matched_element = cmd_element;
2217 matched_count++;
2218 }
2219 else
2220 incomplete_count++;
2221 }
paul909a2152005-03-14 17:41:45 +00002222
paul718e3742002-12-13 20:15:29 +00002223 /* Finish of using cmd_vector. */
2224 vector_free (cmd_vector);
2225
paul909a2152005-03-14 17:41:45 +00002226 /* To execute command, matched_count must be 1. */
2227 if (matched_count == 0)
paul718e3742002-12-13 20:15:29 +00002228 {
2229 if (incomplete_count)
2230 return CMD_ERR_INCOMPLETE;
2231 else
2232 return CMD_ERR_NO_MATCH;
2233 }
2234
paul909a2152005-03-14 17:41:45 +00002235 if (matched_count > 1)
paul718e3742002-12-13 20:15:29 +00002236 return CMD_ERR_AMBIGUOUS;
2237
2238 /* Argument treatment */
2239 varflag = 0;
2240 argc = 0;
2241
paul55468c82005-03-14 20:19:01 +00002242 for (i = 0; i < vector_active (vline); i++)
paul718e3742002-12-13 20:15:29 +00002243 {
2244 if (varflag)
2245 argv[argc++] = vector_slot (vline, i);
2246 else
paul909a2152005-03-14 17:41:45 +00002247 {
paul718e3742002-12-13 20:15:29 +00002248 vector descvec = vector_slot (matched_element->strvec, i);
2249
paul55468c82005-03-14 20:19:01 +00002250 if (vector_active (descvec) == 1)
paul718e3742002-12-13 20:15:29 +00002251 {
2252 struct desc *desc = vector_slot (descvec, 0);
paul718e3742002-12-13 20:15:29 +00002253
hasso8c328f12004-10-05 21:01:23 +00002254 if (CMD_VARARG (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002255 varflag = 1;
paul909a2152005-03-14 17:41:45 +00002256
hasso8c328f12004-10-05 21:01:23 +00002257 if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002258 argv[argc++] = vector_slot (vline, i);
2259 }
2260 else
2261 argv[argc++] = vector_slot (vline, i);
2262 }
2263
2264 if (argc >= CMD_ARGC_MAX)
2265 return CMD_ERR_EXEED_ARGC_MAX;
2266 }
2267
2268 /* For vtysh execution. */
2269 if (cmd)
2270 *cmd = matched_element;
2271
2272 if (matched_element->daemon)
2273 return CMD_SUCCESS_DAEMON;
2274
2275 /* Now execute matched command */
2276 return (*matched_element->func) (matched_element, vty, argc, argv);
2277}
2278
2279/* Configration make from file. */
2280int
2281config_from_file (struct vty *vty, FILE *fp)
2282{
2283 int ret;
2284 vector vline;
2285
2286 while (fgets (vty->buf, VTY_BUFSIZ, fp))
2287 {
2288 vline = cmd_make_strvec (vty->buf);
2289
2290 /* In case of comment line */
2291 if (vline == NULL)
2292 continue;
2293 /* Execute configuration command : this is strict match */
2294 ret = cmd_execute_command_strict (vline, vty, NULL);
2295
2296 /* Try again with setting node to CONFIG_NODE */
paulb92938a2002-12-13 21:20:42 +00002297 while (ret != CMD_SUCCESS && ret != CMD_WARNING
hassoddd85ed2004-10-13 08:18:07 +00002298 && ret != CMD_ERR_NOTHING_TODO && vty->node != CONFIG_NODE)
2299 {
paulb92938a2002-12-13 21:20:42 +00002300 vty->node = node_parent(vty->node);
hassoddd85ed2004-10-13 08:18:07 +00002301 ret = cmd_execute_command_strict (vline, vty, NULL);
2302 }
paul9ab68122003-01-18 01:16:20 +00002303
paul718e3742002-12-13 20:15:29 +00002304 cmd_free_strvec (vline);
2305
hassoddd85ed2004-10-13 08:18:07 +00002306 if (ret != CMD_SUCCESS && ret != CMD_WARNING
2307 && ret != CMD_ERR_NOTHING_TODO)
paul718e3742002-12-13 20:15:29 +00002308 return ret;
2309 }
2310 return CMD_SUCCESS;
2311}
2312
2313/* Configration from terminal */
2314DEFUN (config_terminal,
2315 config_terminal_cmd,
2316 "configure terminal",
2317 "Configuration from vty interface\n"
2318 "Configuration terminal\n")
2319{
2320 if (vty_config_lock (vty))
2321 vty->node = CONFIG_NODE;
2322 else
2323 {
2324 vty_out (vty, "VTY configuration is locked by other VTY%s", VTY_NEWLINE);
2325 return CMD_WARNING;
2326 }
2327 return CMD_SUCCESS;
2328}
2329
2330/* Enable command */
2331DEFUN (enable,
2332 config_enable_cmd,
2333 "enable",
2334 "Turn on privileged mode command\n")
2335{
2336 /* If enable password is NULL, change to ENABLE_NODE */
2337 if ((host.enable == NULL && host.enable_encrypt == NULL) ||
2338 vty->type == VTY_SHELL_SERV)
2339 vty->node = ENABLE_NODE;
2340 else
2341 vty->node = AUTH_ENABLE_NODE;
2342
2343 return CMD_SUCCESS;
2344}
2345
2346/* Disable command */
2347DEFUN (disable,
2348 config_disable_cmd,
2349 "disable",
2350 "Turn off privileged mode command\n")
2351{
2352 if (vty->node == ENABLE_NODE)
2353 vty->node = VIEW_NODE;
2354 return CMD_SUCCESS;
2355}
2356
2357/* Down vty node level. */
2358DEFUN (config_exit,
2359 config_exit_cmd,
2360 "exit",
2361 "Exit current mode and down to previous mode\n")
2362{
2363 switch (vty->node)
2364 {
2365 case VIEW_NODE:
2366 case ENABLE_NODE:
2367 if (vty_shell (vty))
2368 exit (0);
2369 else
2370 vty->status = VTY_CLOSE;
2371 break;
2372 case CONFIG_NODE:
2373 vty->node = ENABLE_NODE;
2374 vty_config_unlock (vty);
2375 break;
2376 case INTERFACE_NODE:
2377 case ZEBRA_NODE:
2378 case BGP_NODE:
2379 case RIP_NODE:
2380 case RIPNG_NODE:
2381 case OSPF_NODE:
2382 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00002383 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00002384 case KEYCHAIN_NODE:
2385 case MASC_NODE:
2386 case RMAP_NODE:
2387 case VTY_NODE:
2388 vty->node = CONFIG_NODE;
2389 break;
2390 case BGP_VPNV4_NODE:
2391 case BGP_IPV4_NODE:
2392 case BGP_IPV4M_NODE:
2393 case BGP_IPV6_NODE:
2394 vty->node = BGP_NODE;
2395 break;
2396 case KEYCHAIN_KEY_NODE:
2397 vty->node = KEYCHAIN_NODE;
2398 break;
2399 default:
2400 break;
2401 }
2402 return CMD_SUCCESS;
2403}
2404
2405/* quit is alias of exit. */
2406ALIAS (config_exit,
2407 config_quit_cmd,
2408 "quit",
2409 "Exit current mode and down to previous mode\n")
2410
2411/* End of configuration. */
2412DEFUN (config_end,
2413 config_end_cmd,
2414 "end",
2415 "End current mode and change to enable mode.")
2416{
2417 switch (vty->node)
2418 {
2419 case VIEW_NODE:
2420 case ENABLE_NODE:
2421 /* Nothing to do. */
2422 break;
2423 case CONFIG_NODE:
2424 case INTERFACE_NODE:
2425 case ZEBRA_NODE:
2426 case RIP_NODE:
2427 case RIPNG_NODE:
2428 case BGP_NODE:
2429 case BGP_VPNV4_NODE:
2430 case BGP_IPV4_NODE:
2431 case BGP_IPV4M_NODE:
2432 case BGP_IPV6_NODE:
2433 case RMAP_NODE:
2434 case OSPF_NODE:
2435 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00002436 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00002437 case KEYCHAIN_NODE:
2438 case KEYCHAIN_KEY_NODE:
2439 case MASC_NODE:
2440 case VTY_NODE:
2441 vty_config_unlock (vty);
2442 vty->node = ENABLE_NODE;
2443 break;
2444 default:
2445 break;
2446 }
2447 return CMD_SUCCESS;
2448}
2449
2450/* Show version. */
2451DEFUN (show_version,
2452 show_version_cmd,
2453 "show version",
2454 SHOW_STR
2455 "Displays zebra version\n")
2456{
hasso12f6ea22005-03-07 08:35:39 +00002457 vty_out (vty, "Quagga %s (%s).%s", QUAGGA_VERSION, host.name?host.name:"",
2458 VTY_NEWLINE);
hasso6590f2c2004-10-19 20:40:08 +00002459 vty_out (vty, "%s%s", QUAGGA_COPYRIGHT, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00002460
2461 return CMD_SUCCESS;
2462}
2463
2464/* Help display function for all node. */
2465DEFUN (config_help,
2466 config_help_cmd,
2467 "help",
2468 "Description of the interactive help system\n")
2469{
2470 vty_out (vty,
hasso6590f2c2004-10-19 20:40:08 +00002471 "Quagga VTY provides advanced help feature. When you need help,%s\
paul718e3742002-12-13 20:15:29 +00002472anytime at the command line please press '?'.%s\
2473%s\
2474If nothing matches, the help list will be empty and you must backup%s\
2475 until entering a '?' shows the available options.%s\
2476Two styles of help are provided:%s\
24771. Full help is available when you are ready to enter a%s\
2478command argument (e.g. 'show ?') and describes each possible%s\
2479argument.%s\
24802. Partial help is provided when an abbreviated argument is entered%s\
2481 and you want to know what arguments match the input%s\
2482 (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2483 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2484 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
2485 return CMD_SUCCESS;
2486}
2487
2488/* Help display function for all node. */
2489DEFUN (config_list,
2490 config_list_cmd,
2491 "list",
2492 "Print command list\n")
2493{
hasso8c328f12004-10-05 21:01:23 +00002494 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002495 struct cmd_node *cnode = vector_slot (cmdvec, vty->node);
2496 struct cmd_element *cmd;
2497
paul55468c82005-03-14 20:19:01 +00002498 for (i = 0; i < vector_active (cnode->cmd_vector); i++)
paul4275b1d2005-03-09 13:42:23 +00002499 if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL
2500 && !(cmd->attr == CMD_ATTR_DEPRECATED
2501 || cmd->attr == CMD_ATTR_HIDDEN))
paul718e3742002-12-13 20:15:29 +00002502 vty_out (vty, " %s%s", cmd->string,
2503 VTY_NEWLINE);
2504 return CMD_SUCCESS;
2505}
2506
2507/* Write current configuration into file. */
2508DEFUN (config_write_file,
2509 config_write_file_cmd,
2510 "write file",
2511 "Write running configuration to memory, network, or terminal\n"
2512 "Write to configuration file\n")
2513{
hasso8c328f12004-10-05 21:01:23 +00002514 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002515 int fd;
2516 struct cmd_node *node;
2517 char *config_file;
2518 char *config_file_tmp = NULL;
2519 char *config_file_sav = NULL;
2520 struct vty *file_vty;
2521
2522 /* Check and see if we are operating under vtysh configuration */
2523 if (host.config == NULL)
2524 {
2525 vty_out (vty, "Can't save to configuration file, using vtysh.%s",
2526 VTY_NEWLINE);
2527 return CMD_WARNING;
2528 }
2529
2530 /* Get filename. */
2531 config_file = host.config;
2532
2533 config_file_sav = malloc (strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
2534 strcpy (config_file_sav, config_file);
2535 strcat (config_file_sav, CONF_BACKUP_EXT);
2536
2537
2538 config_file_tmp = malloc (strlen (config_file) + 8);
2539 sprintf (config_file_tmp, "%s.XXXXXX", config_file);
2540
2541 /* Open file to configuration write. */
2542 fd = mkstemp (config_file_tmp);
2543 if (fd < 0)
2544 {
2545 vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
2546 VTY_NEWLINE);
2547 free (config_file_tmp);
2548 free (config_file_sav);
2549 return CMD_WARNING;
2550 }
2551
2552 /* Make vty for configuration file. */
2553 file_vty = vty_new ();
2554 file_vty->fd = fd;
2555 file_vty->type = VTY_FILE;
2556
2557 /* Config file header print. */
2558 vty_out (file_vty, "!\n! Zebra configuration saved from vty\n! ");
2559 vty_time_print (file_vty, 1);
2560 vty_out (file_vty, "!\n");
2561
paul55468c82005-03-14 20:19:01 +00002562 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +00002563 if ((node = vector_slot (cmdvec, i)) && node->func)
2564 {
2565 if ((*node->func) (file_vty))
2566 vty_out (file_vty, "!\n");
2567 }
2568 vty_close (file_vty);
2569
2570 if (unlink (config_file_sav) != 0)
2571 if (errno != ENOENT)
2572 {
2573 vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
2574 VTY_NEWLINE);
2575 free (config_file_sav);
2576 free (config_file_tmp);
2577 unlink (config_file_tmp);
2578 return CMD_WARNING;
2579 }
2580 if (link (config_file, config_file_sav) != 0)
2581 {
2582 vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
2583 VTY_NEWLINE);
2584 free (config_file_sav);
2585 free (config_file_tmp);
2586 unlink (config_file_tmp);
2587 return CMD_WARNING;
2588 }
2589 sync ();
2590 if (unlink (config_file) != 0)
2591 {
2592 vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
2593 VTY_NEWLINE);
2594 free (config_file_sav);
2595 free (config_file_tmp);
2596 unlink (config_file_tmp);
2597 return CMD_WARNING;
2598 }
2599 if (link (config_file_tmp, config_file) != 0)
2600 {
2601 vty_out (vty, "Can't save configuration file %s.%s", config_file,
2602 VTY_NEWLINE);
2603 free (config_file_sav);
2604 free (config_file_tmp);
2605 unlink (config_file_tmp);
2606 return CMD_WARNING;
2607 }
2608 unlink (config_file_tmp);
2609 sync ();
2610
2611 free (config_file_sav);
2612 free (config_file_tmp);
gdtaa593d52003-12-22 20:15:53 +00002613
2614 if (chmod (config_file, CONFIGFILE_MASK) != 0)
2615 {
2616 vty_out (vty, "Can't chmod configuration file %s: %s (%d).%s",
ajs6099b3b2004-11-20 02:06:59 +00002617 config_file, safe_strerror(errno), errno, VTY_NEWLINE);
gdtaa593d52003-12-22 20:15:53 +00002618 return CMD_WARNING;
2619 }
2620
paul718e3742002-12-13 20:15:29 +00002621 vty_out (vty, "Configuration saved to %s%s", config_file,
2622 VTY_NEWLINE);
2623 return CMD_SUCCESS;
2624}
2625
2626ALIAS (config_write_file,
2627 config_write_cmd,
2628 "write",
2629 "Write running configuration to memory, network, or terminal\n")
2630
2631ALIAS (config_write_file,
2632 config_write_memory_cmd,
2633 "write memory",
2634 "Write running configuration to memory, network, or terminal\n"
2635 "Write configuration to the file (same as write file)\n")
2636
2637ALIAS (config_write_file,
2638 copy_runningconfig_startupconfig_cmd,
2639 "copy running-config startup-config",
2640 "Copy configuration\n"
2641 "Copy running config to... \n"
2642 "Copy running config to startup config (same as write file)\n")
2643
2644/* Write current configuration into the terminal. */
2645DEFUN (config_write_terminal,
2646 config_write_terminal_cmd,
2647 "write terminal",
2648 "Write running configuration to memory, network, or terminal\n"
2649 "Write to terminal\n")
2650{
hasso8c328f12004-10-05 21:01:23 +00002651 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002652 struct cmd_node *node;
2653
2654 if (vty->type == VTY_SHELL_SERV)
2655 {
paul55468c82005-03-14 20:19:01 +00002656 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +00002657 if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
2658 {
2659 if ((*node->func) (vty))
2660 vty_out (vty, "!%s", VTY_NEWLINE);
2661 }
2662 }
2663 else
2664 {
2665 vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
2666 VTY_NEWLINE);
2667 vty_out (vty, "!%s", VTY_NEWLINE);
2668
paul55468c82005-03-14 20:19:01 +00002669 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +00002670 if ((node = vector_slot (cmdvec, i)) && node->func)
2671 {
2672 if ((*node->func) (vty))
2673 vty_out (vty, "!%s", VTY_NEWLINE);
2674 }
2675 vty_out (vty, "end%s",VTY_NEWLINE);
2676 }
2677 return CMD_SUCCESS;
2678}
2679
2680/* Write current configuration into the terminal. */
2681ALIAS (config_write_terminal,
2682 show_running_config_cmd,
2683 "show running-config",
2684 SHOW_STR
2685 "running configuration\n")
2686
2687/* Write startup configuration into the terminal. */
2688DEFUN (show_startup_config,
2689 show_startup_config_cmd,
2690 "show startup-config",
2691 SHOW_STR
2692 "Contentes of startup configuration\n")
2693{
2694 char buf[BUFSIZ];
2695 FILE *confp;
2696
2697 confp = fopen (host.config, "r");
2698 if (confp == NULL)
2699 {
2700 vty_out (vty, "Can't open configuration file [%s]%s",
2701 host.config, VTY_NEWLINE);
2702 return CMD_WARNING;
2703 }
2704
2705 while (fgets (buf, BUFSIZ, confp))
2706 {
2707 char *cp = buf;
2708
2709 while (*cp != '\r' && *cp != '\n' && *cp != '\0')
2710 cp++;
2711 *cp = '\0';
2712
2713 vty_out (vty, "%s%s", buf, VTY_NEWLINE);
2714 }
2715
2716 fclose (confp);
2717
2718 return CMD_SUCCESS;
2719}
2720
2721/* Hostname configuration */
2722DEFUN (config_hostname,
2723 hostname_cmd,
2724 "hostname WORD",
2725 "Set system's network name\n"
2726 "This system's network name\n")
2727{
2728 if (!isalpha((int) *argv[0]))
2729 {
2730 vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
2731 return CMD_WARNING;
2732 }
2733
2734 if (host.name)
2735 XFREE (0, host.name);
2736
2737 host.name = strdup (argv[0]);
2738 return CMD_SUCCESS;
2739}
2740
2741DEFUN (config_no_hostname,
2742 no_hostname_cmd,
2743 "no hostname [HOSTNAME]",
2744 NO_STR
2745 "Reset system's network name\n"
2746 "Host name of this router\n")
2747{
2748 if (host.name)
2749 XFREE (0, host.name);
2750 host.name = NULL;
2751 return CMD_SUCCESS;
2752}
2753
2754/* VTY interface password set. */
2755DEFUN (config_password, password_cmd,
2756 "password (8|) WORD",
2757 "Assign the terminal connection password\n"
2758 "Specifies a HIDDEN password will follow\n"
2759 "dummy string \n"
2760 "The HIDDEN line password string\n")
2761{
2762 /* Argument check. */
2763 if (argc == 0)
2764 {
2765 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2766 return CMD_WARNING;
2767 }
2768
2769 if (argc == 2)
2770 {
2771 if (*argv[0] == '8')
2772 {
2773 if (host.password)
2774 XFREE (0, host.password);
2775 host.password = NULL;
2776 if (host.password_encrypt)
2777 XFREE (0, host.password_encrypt);
2778 host.password_encrypt = XSTRDUP (0, strdup (argv[1]));
2779 return CMD_SUCCESS;
2780 }
2781 else
2782 {
2783 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2784 return CMD_WARNING;
2785 }
2786 }
2787
2788 if (!isalnum ((int) *argv[0]))
2789 {
2790 vty_out (vty,
2791 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2792 return CMD_WARNING;
2793 }
2794
2795 if (host.password)
2796 XFREE (0, host.password);
2797 host.password = NULL;
2798
2799 if (host.encrypt)
2800 {
2801 if (host.password_encrypt)
2802 XFREE (0, host.password_encrypt);
2803 host.password_encrypt = XSTRDUP (0, zencrypt (argv[0]));
2804 }
2805 else
2806 host.password = XSTRDUP (0, argv[0]);
2807
2808 return CMD_SUCCESS;
2809}
2810
2811ALIAS (config_password, password_text_cmd,
2812 "password LINE",
2813 "Assign the terminal connection password\n"
2814 "The UNENCRYPTED (cleartext) line password\n")
2815
2816/* VTY enable password set. */
2817DEFUN (config_enable_password, enable_password_cmd,
2818 "enable password (8|) WORD",
2819 "Modify enable password parameters\n"
2820 "Assign the privileged level password\n"
2821 "Specifies a HIDDEN password will follow\n"
2822 "dummy string \n"
2823 "The HIDDEN 'enable' password string\n")
2824{
2825 /* Argument check. */
2826 if (argc == 0)
2827 {
2828 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2829 return CMD_WARNING;
2830 }
2831
2832 /* Crypt type is specified. */
2833 if (argc == 2)
2834 {
2835 if (*argv[0] == '8')
2836 {
2837 if (host.enable)
2838 XFREE (0, host.enable);
2839 host.enable = NULL;
2840
2841 if (host.enable_encrypt)
2842 XFREE (0, host.enable_encrypt);
2843 host.enable_encrypt = XSTRDUP (0, argv[1]);
2844
2845 return CMD_SUCCESS;
2846 }
2847 else
2848 {
2849 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2850 return CMD_WARNING;
2851 }
2852 }
2853
2854 if (!isalnum ((int) *argv[0]))
2855 {
2856 vty_out (vty,
2857 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2858 return CMD_WARNING;
2859 }
2860
2861 if (host.enable)
2862 XFREE (0, host.enable);
2863 host.enable = NULL;
2864
2865 /* Plain password input. */
2866 if (host.encrypt)
2867 {
2868 if (host.enable_encrypt)
2869 XFREE (0, host.enable_encrypt);
2870 host.enable_encrypt = XSTRDUP (0, zencrypt (argv[0]));
2871 }
2872 else
2873 host.enable = XSTRDUP (0, argv[0]);
2874
2875 return CMD_SUCCESS;
2876}
2877
2878ALIAS (config_enable_password,
2879 enable_password_text_cmd,
2880 "enable password LINE",
2881 "Modify enable password parameters\n"
2882 "Assign the privileged level password\n"
2883 "The UNENCRYPTED (cleartext) 'enable' password\n")
2884
2885/* VTY enable password delete. */
2886DEFUN (no_config_enable_password, no_enable_password_cmd,
2887 "no enable password",
2888 NO_STR
2889 "Modify enable password parameters\n"
2890 "Assign the privileged level password\n")
2891{
2892 if (host.enable)
2893 XFREE (0, host.enable);
2894 host.enable = NULL;
2895
2896 if (host.enable_encrypt)
2897 XFREE (0, host.enable_encrypt);
2898 host.enable_encrypt = NULL;
2899
2900 return CMD_SUCCESS;
2901}
2902
2903DEFUN (service_password_encrypt,
2904 service_password_encrypt_cmd,
2905 "service password-encryption",
2906 "Set up miscellaneous service\n"
2907 "Enable encrypted passwords\n")
2908{
2909 if (host.encrypt)
2910 return CMD_SUCCESS;
2911
2912 host.encrypt = 1;
2913
2914 if (host.password)
2915 {
2916 if (host.password_encrypt)
2917 XFREE (0, host.password_encrypt);
2918 host.password_encrypt = XSTRDUP (0, zencrypt (host.password));
2919 }
2920 if (host.enable)
2921 {
2922 if (host.enable_encrypt)
2923 XFREE (0, host.enable_encrypt);
2924 host.enable_encrypt = XSTRDUP (0, zencrypt (host.enable));
2925 }
2926
2927 return CMD_SUCCESS;
2928}
2929
2930DEFUN (no_service_password_encrypt,
2931 no_service_password_encrypt_cmd,
2932 "no service password-encryption",
2933 NO_STR
2934 "Set up miscellaneous service\n"
2935 "Enable encrypted passwords\n")
2936{
2937 if (! host.encrypt)
2938 return CMD_SUCCESS;
2939
2940 host.encrypt = 0;
2941
2942 if (host.password_encrypt)
2943 XFREE (0, host.password_encrypt);
2944 host.password_encrypt = NULL;
2945
2946 if (host.enable_encrypt)
2947 XFREE (0, host.enable_encrypt);
2948 host.enable_encrypt = NULL;
2949
2950 return CMD_SUCCESS;
2951}
2952
2953DEFUN (config_terminal_length, config_terminal_length_cmd,
2954 "terminal length <0-512>",
2955 "Set terminal line parameters\n"
2956 "Set number of lines on a screen\n"
2957 "Number of lines on screen (0 for no pausing)\n")
2958{
2959 int lines;
2960 char *endptr = NULL;
2961
2962 lines = strtol (argv[0], &endptr, 10);
2963 if (lines < 0 || lines > 512 || *endptr != '\0')
2964 {
2965 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2966 return CMD_WARNING;
2967 }
2968 vty->lines = lines;
2969
2970 return CMD_SUCCESS;
2971}
2972
2973DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
2974 "terminal no length",
2975 "Set terminal line parameters\n"
2976 NO_STR
2977 "Set number of lines on a screen\n")
2978{
2979 vty->lines = -1;
2980 return CMD_SUCCESS;
2981}
2982
2983DEFUN (service_terminal_length, service_terminal_length_cmd,
2984 "service terminal-length <0-512>",
2985 "Set up miscellaneous service\n"
2986 "System wide terminal length configuration\n"
2987 "Number of lines of VTY (0 means no line control)\n")
2988{
2989 int lines;
2990 char *endptr = NULL;
2991
2992 lines = strtol (argv[0], &endptr, 10);
2993 if (lines < 0 || lines > 512 || *endptr != '\0')
2994 {
2995 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2996 return CMD_WARNING;
2997 }
2998 host.lines = lines;
2999
3000 return CMD_SUCCESS;
3001}
3002
3003DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
3004 "no service terminal-length [<0-512>]",
3005 NO_STR
3006 "Set up miscellaneous service\n"
3007 "System wide terminal length configuration\n"
3008 "Number of lines of VTY (0 means no line control)\n")
3009{
3010 host.lines = -1;
3011 return CMD_SUCCESS;
3012}
3013
ajs2885f722004-12-17 23:16:33 +00003014DEFUN_HIDDEN (do_echo,
3015 echo_cmd,
3016 "echo .MESSAGE",
3017 "Echo a message back to the vty\n"
3018 "The message to echo\n")
3019{
3020 char *message;
3021
ajsf6834d42005-01-28 20:28:35 +00003022 vty_out (vty, "%s%s", ((message = argv_concat(argv, argc, 0)) ? message : ""),
3023 VTY_NEWLINE);
3024 if (message)
3025 XFREE(MTYPE_TMP, message);
ajs2885f722004-12-17 23:16:33 +00003026 return CMD_SUCCESS;
3027}
3028
ajs274a4a42004-12-07 15:39:31 +00003029DEFUN (config_logmsg,
3030 config_logmsg_cmd,
3031 "logmsg "LOG_LEVELS" .MESSAGE",
3032 "Send a message to enabled logging destinations\n"
3033 LOG_LEVEL_DESC
3034 "The message to send\n")
3035{
3036 int level;
3037 char *message;
3038
3039 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3040 return CMD_ERR_NO_MATCH;
3041
ajsf6834d42005-01-28 20:28:35 +00003042 zlog(NULL, level, ((message = argv_concat(argv, argc, 1)) ? message : ""));
3043 if (message)
3044 XFREE(MTYPE_TMP, message);
ajs274a4a42004-12-07 15:39:31 +00003045 return CMD_SUCCESS;
3046}
3047
3048DEFUN (show_logging,
3049 show_logging_cmd,
3050 "show logging",
3051 SHOW_STR
3052 "Show current logging configuration\n")
3053{
3054 struct zlog *zl = zlog_default;
3055
3056 vty_out (vty, "Syslog logging: ");
3057 if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED)
3058 vty_out (vty, "disabled");
3059 else
3060 vty_out (vty, "level %s, facility %s, ident %s",
3061 zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]],
3062 facility_name(zl->facility), zl->ident);
3063 vty_out (vty, "%s", VTY_NEWLINE);
3064
3065 vty_out (vty, "Stdout logging: ");
3066 if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED)
3067 vty_out (vty, "disabled");
3068 else
3069 vty_out (vty, "level %s",
3070 zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
3071 vty_out (vty, "%s", VTY_NEWLINE);
3072
3073 vty_out (vty, "Monitor logging: ");
3074 if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
3075 vty_out (vty, "disabled");
3076 else
3077 vty_out (vty, "level %s",
3078 zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
3079 vty_out (vty, "%s", VTY_NEWLINE);
3080
3081 vty_out (vty, "File logging: ");
3082 if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) ||
3083 !zl->fp)
3084 vty_out (vty, "disabled");
3085 else
3086 vty_out (vty, "level %s, filename %s",
3087 zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
3088 zl->filename);
3089 vty_out (vty, "%s", VTY_NEWLINE);
3090
3091 vty_out (vty, "Protocol name: %s%s",
3092 zlog_proto_names[zl->protocol], VTY_NEWLINE);
3093 vty_out (vty, "Record priority: %s%s",
3094 (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE);
3095
3096 return CMD_SUCCESS;
3097}
3098
paul718e3742002-12-13 20:15:29 +00003099DEFUN (config_log_stdout,
3100 config_log_stdout_cmd,
3101 "log stdout",
3102 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003103 "Set stdout logging level\n")
paul718e3742002-12-13 20:15:29 +00003104{
ajs274a4a42004-12-07 15:39:31 +00003105 zlog_set_level (NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl);
3106 return CMD_SUCCESS;
3107}
3108
3109DEFUN (config_log_stdout_level,
3110 config_log_stdout_level_cmd,
3111 "log stdout "LOG_LEVELS,
3112 "Logging control\n"
3113 "Set stdout logging level\n"
3114 LOG_LEVEL_DESC)
3115{
3116 int level;
3117
3118 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3119 return CMD_ERR_NO_MATCH;
3120 zlog_set_level (NULL, ZLOG_DEST_STDOUT, level);
paul718e3742002-12-13 20:15:29 +00003121 return CMD_SUCCESS;
3122}
3123
3124DEFUN (no_config_log_stdout,
3125 no_config_log_stdout_cmd,
ajs274a4a42004-12-07 15:39:31 +00003126 "no log stdout [LEVEL]",
paul718e3742002-12-13 20:15:29 +00003127 NO_STR
3128 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003129 "Cancel logging to stdout\n"
3130 "Logging level\n")
paul718e3742002-12-13 20:15:29 +00003131{
ajs274a4a42004-12-07 15:39:31 +00003132 zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED);
paul718e3742002-12-13 20:15:29 +00003133 return CMD_SUCCESS;
3134}
3135
ajs274a4a42004-12-07 15:39:31 +00003136DEFUN (config_log_monitor,
3137 config_log_monitor_cmd,
3138 "log monitor",
paul718e3742002-12-13 20:15:29 +00003139 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003140 "Set terminal line (monitor) logging level\n")
3141{
3142 zlog_set_level (NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl);
3143 return CMD_SUCCESS;
3144}
3145
3146DEFUN (config_log_monitor_level,
3147 config_log_monitor_level_cmd,
3148 "log monitor "LOG_LEVELS,
3149 "Logging control\n"
3150 "Set terminal line (monitor) logging level\n"
3151 LOG_LEVEL_DESC)
3152{
3153 int level;
3154
3155 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3156 return CMD_ERR_NO_MATCH;
3157 zlog_set_level (NULL, ZLOG_DEST_MONITOR, level);
3158 return CMD_SUCCESS;
3159}
3160
3161DEFUN (no_config_log_monitor,
3162 no_config_log_monitor_cmd,
3163 "no log monitor [LEVEL]",
3164 NO_STR
3165 "Logging control\n"
3166 "Disable terminal line (monitor) logging\n"
3167 "Logging level\n")
3168{
3169 zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
3170 return CMD_SUCCESS;
3171}
3172
3173static int
3174set_log_file(struct vty *vty, const char *fname, int loglevel)
paul718e3742002-12-13 20:15:29 +00003175{
3176 int ret;
paul9035efa2004-10-10 11:56:56 +00003177 char *p = NULL;
3178 const char *fullpath;
3179
paul718e3742002-12-13 20:15:29 +00003180 /* Path detection. */
ajs274a4a42004-12-07 15:39:31 +00003181 if (! IS_DIRECTORY_SEP (*fname))
paul718e3742002-12-13 20:15:29 +00003182 {
paul9035efa2004-10-10 11:56:56 +00003183 char cwd[MAXPATHLEN+1];
3184 cwd[MAXPATHLEN] = '\0';
3185
3186 if (getcwd (cwd, MAXPATHLEN) == NULL)
3187 {
3188 zlog_err ("config_log_file: Unable to alloc mem!");
3189 return CMD_WARNING;
3190 }
3191
ajs274a4a42004-12-07 15:39:31 +00003192 if ( (p = XMALLOC (MTYPE_TMP, strlen (cwd) + strlen (fname) + 2))
paul9035efa2004-10-10 11:56:56 +00003193 == NULL)
3194 {
3195 zlog_err ("config_log_file: Unable to alloc mem!");
3196 return CMD_WARNING;
3197 }
ajs274a4a42004-12-07 15:39:31 +00003198 sprintf (p, "%s/%s", cwd, fname);
paul9035efa2004-10-10 11:56:56 +00003199 fullpath = p;
paul718e3742002-12-13 20:15:29 +00003200 }
3201 else
ajs274a4a42004-12-07 15:39:31 +00003202 fullpath = fname;
paul718e3742002-12-13 20:15:29 +00003203
ajs274a4a42004-12-07 15:39:31 +00003204 ret = zlog_set_file (NULL, fullpath, loglevel);
paul718e3742002-12-13 20:15:29 +00003205
paul9035efa2004-10-10 11:56:56 +00003206 if (p)
3207 XFREE (MTYPE_TMP, p);
3208
paul718e3742002-12-13 20:15:29 +00003209 if (!ret)
3210 {
ajs274a4a42004-12-07 15:39:31 +00003211 vty_out (vty, "can't open logfile %s\n", fname);
paul718e3742002-12-13 20:15:29 +00003212 return CMD_WARNING;
3213 }
3214
3215 if (host.logfile)
3216 XFREE (MTYPE_TMP, host.logfile);
3217
ajs274a4a42004-12-07 15:39:31 +00003218 host.logfile = XSTRDUP (MTYPE_TMP, fname);
paul718e3742002-12-13 20:15:29 +00003219
3220 return CMD_SUCCESS;
3221}
3222
ajs274a4a42004-12-07 15:39:31 +00003223DEFUN (config_log_file,
3224 config_log_file_cmd,
3225 "log file FILENAME",
3226 "Logging control\n"
3227 "Logging to file\n"
3228 "Logging filename\n")
3229{
3230 return set_log_file(vty, argv[0], zlog_default->default_lvl);
3231}
3232
3233DEFUN (config_log_file_level,
3234 config_log_file_level_cmd,
3235 "log file FILENAME "LOG_LEVELS,
3236 "Logging control\n"
3237 "Logging to file\n"
3238 "Logging filename\n"
3239 LOG_LEVEL_DESC)
3240{
3241 int level;
3242
3243 if ((level = level_match(argv[1])) == ZLOG_DISABLED)
3244 return CMD_ERR_NO_MATCH;
3245 return set_log_file(vty, argv[0], level);
3246}
3247
paul718e3742002-12-13 20:15:29 +00003248DEFUN (no_config_log_file,
3249 no_config_log_file_cmd,
3250 "no log file [FILENAME]",
3251 NO_STR
3252 "Logging control\n"
3253 "Cancel logging to file\n"
3254 "Logging file name\n")
3255{
3256 zlog_reset_file (NULL);
3257
3258 if (host.logfile)
3259 XFREE (MTYPE_TMP, host.logfile);
3260
3261 host.logfile = NULL;
3262
3263 return CMD_SUCCESS;
3264}
3265
ajs274a4a42004-12-07 15:39:31 +00003266ALIAS (no_config_log_file,
3267 no_config_log_file_level_cmd,
3268 "no log file FILENAME LEVEL",
3269 NO_STR
3270 "Logging control\n"
3271 "Cancel logging to file\n"
3272 "Logging file name\n"
3273 "Logging level\n")
3274
paul718e3742002-12-13 20:15:29 +00003275DEFUN (config_log_syslog,
3276 config_log_syslog_cmd,
3277 "log syslog",
3278 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003279 "Set syslog logging level\n")
paul718e3742002-12-13 20:15:29 +00003280{
ajs274a4a42004-12-07 15:39:31 +00003281 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
paul12ab19f2003-07-26 06:14:55 +00003282 return CMD_SUCCESS;
3283}
3284
ajs274a4a42004-12-07 15:39:31 +00003285DEFUN (config_log_syslog_level,
3286 config_log_syslog_level_cmd,
3287 "log syslog "LOG_LEVELS,
paul12ab19f2003-07-26 06:14:55 +00003288 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003289 "Set syslog logging level\n"
3290 LOG_LEVEL_DESC)
paul12ab19f2003-07-26 06:14:55 +00003291{
ajs274a4a42004-12-07 15:39:31 +00003292 int level;
paul12ab19f2003-07-26 06:14:55 +00003293
ajs274a4a42004-12-07 15:39:31 +00003294 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3295 return CMD_ERR_NO_MATCH;
3296 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, level);
3297 return CMD_SUCCESS;
3298}
paul12ab19f2003-07-26 06:14:55 +00003299
ajs274a4a42004-12-07 15:39:31 +00003300DEFUN_DEPRECATED (config_log_syslog_facility,
3301 config_log_syslog_facility_cmd,
3302 "log syslog facility "LOG_FACILITIES,
3303 "Logging control\n"
3304 "Logging goes to syslog\n"
3305 "(Deprecated) Facility parameter for syslog messages\n"
3306 LOG_FACILITY_DESC)
3307{
3308 int facility;
paul12ab19f2003-07-26 06:14:55 +00003309
ajs274a4a42004-12-07 15:39:31 +00003310 if ((facility = facility_match(argv[0])) < 0)
3311 return CMD_ERR_NO_MATCH;
3312
3313 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
paul12ab19f2003-07-26 06:14:55 +00003314 zlog_default->facility = facility;
paul718e3742002-12-13 20:15:29 +00003315 return CMD_SUCCESS;
3316}
3317
3318DEFUN (no_config_log_syslog,
3319 no_config_log_syslog_cmd,
ajs274a4a42004-12-07 15:39:31 +00003320 "no log syslog [LEVEL]",
paul718e3742002-12-13 20:15:29 +00003321 NO_STR
3322 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003323 "Cancel logging to syslog\n"
3324 "Logging level\n")
paul718e3742002-12-13 20:15:29 +00003325{
ajs274a4a42004-12-07 15:39:31 +00003326 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
paul718e3742002-12-13 20:15:29 +00003327 return CMD_SUCCESS;
3328}
3329
paul12ab19f2003-07-26 06:14:55 +00003330ALIAS (no_config_log_syslog,
3331 no_config_log_syslog_facility_cmd,
ajs274a4a42004-12-07 15:39:31 +00003332 "no log syslog facility "LOG_FACILITIES,
paul12ab19f2003-07-26 06:14:55 +00003333 NO_STR
3334 "Logging control\n"
3335 "Logging goes to syslog\n"
3336 "Facility parameter for syslog messages\n"
ajs274a4a42004-12-07 15:39:31 +00003337 LOG_FACILITY_DESC)
paul12ab19f2003-07-26 06:14:55 +00003338
ajs274a4a42004-12-07 15:39:31 +00003339DEFUN (config_log_facility,
3340 config_log_facility_cmd,
3341 "log facility "LOG_FACILITIES,
paul718e3742002-12-13 20:15:29 +00003342 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003343 "Facility parameter for syslog messages\n"
3344 LOG_FACILITY_DESC)
paul718e3742002-12-13 20:15:29 +00003345{
ajs274a4a42004-12-07 15:39:31 +00003346 int facility;
3347
3348 if ((facility = facility_match(argv[0])) < 0)
3349 return CMD_ERR_NO_MATCH;
3350 zlog_default->facility = facility;
3351 return CMD_SUCCESS;
paul718e3742002-12-13 20:15:29 +00003352}
3353
ajs274a4a42004-12-07 15:39:31 +00003354DEFUN (no_config_log_facility,
3355 no_config_log_facility_cmd,
3356 "no log facility [FACILITY]",
paul718e3742002-12-13 20:15:29 +00003357 NO_STR
3358 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003359 "Reset syslog facility to default (daemon)\n"
3360 "Syslog facility\n")
paul718e3742002-12-13 20:15:29 +00003361{
ajs274a4a42004-12-07 15:39:31 +00003362 zlog_default->facility = LOG_DAEMON;
3363 return CMD_SUCCESS;
3364}
3365
3366DEFUN_DEPRECATED (config_log_trap,
3367 config_log_trap_cmd,
3368 "log trap "LOG_LEVELS,
3369 "Logging control\n"
3370 "(Deprecated) Set logging level and default for all destinations\n"
3371 LOG_LEVEL_DESC)
3372{
3373 int new_level ;
3374 int i;
3375
3376 if ((new_level = level_match(argv[0])) == ZLOG_DISABLED)
3377 return CMD_ERR_NO_MATCH;
3378
3379 zlog_default->default_lvl = new_level;
3380 for (i = 0; i < ZLOG_NUM_DESTS; i++)
3381 if (zlog_default->maxlvl[i] != ZLOG_DISABLED)
3382 zlog_default->maxlvl[i] = new_level;
3383 return CMD_SUCCESS;
3384}
3385
3386DEFUN_DEPRECATED (no_config_log_trap,
3387 no_config_log_trap_cmd,
3388 "no log trap [LEVEL]",
3389 NO_STR
3390 "Logging control\n"
3391 "Permit all logging information\n"
3392 "Logging level\n")
3393{
3394 zlog_default->default_lvl = LOG_DEBUG;
paul718e3742002-12-13 20:15:29 +00003395 return CMD_SUCCESS;
3396}
3397
3398DEFUN (config_log_record_priority,
3399 config_log_record_priority_cmd,
3400 "log record-priority",
3401 "Logging control\n"
3402 "Log the priority of the message within the message\n")
3403{
3404 zlog_default->record_priority = 1 ;
3405 return CMD_SUCCESS;
3406}
3407
3408DEFUN (no_config_log_record_priority,
3409 no_config_log_record_priority_cmd,
3410 "no log record-priority",
3411 NO_STR
3412 "Logging control\n"
3413 "Do not log the priority of the message within the message\n")
3414{
3415 zlog_default->record_priority = 0 ;
3416 return CMD_SUCCESS;
3417}
3418
paul3b0c5d92005-03-08 10:43:43 +00003419DEFUN (banner_motd_file,
3420 banner_motd_file_cmd,
3421 "banner motd file [FILE]",
3422 "Set banner\n"
3423 "Banner for motd\n"
3424 "Banner from a file\n"
3425 "Filename\n")
3426{
paulb45da6f2005-03-08 15:16:57 +00003427 if (host.motdfile)
3428 XFREE (MTYPE_TMP, host.motdfile);
3429 host.motdfile = XSTRDUP (MTYPE_TMP, argv[0]);
3430
paul3b0c5d92005-03-08 10:43:43 +00003431 return CMD_SUCCESS;
3432}
paul718e3742002-12-13 20:15:29 +00003433
3434DEFUN (banner_motd_default,
3435 banner_motd_default_cmd,
3436 "banner motd default",
3437 "Set banner string\n"
3438 "Strings for motd\n"
3439 "Default string\n")
3440{
3441 host.motd = default_motd;
3442 return CMD_SUCCESS;
3443}
3444
3445DEFUN (no_banner_motd,
3446 no_banner_motd_cmd,
3447 "no banner motd",
3448 NO_STR
3449 "Set banner string\n"
3450 "Strings for motd\n")
3451{
3452 host.motd = NULL;
paul22085182005-03-08 16:00:12 +00003453 if (host.motdfile)
3454 XFREE (MTYPE_TMP, host.motdfile);
paul3b0c5d92005-03-08 10:43:43 +00003455 host.motdfile = NULL;
paul718e3742002-12-13 20:15:29 +00003456 return CMD_SUCCESS;
3457}
3458
3459/* Set config filename. Called from vty.c */
3460void
3461host_config_set (char *filename)
3462{
3463 host.config = strdup (filename);
3464}
3465
3466void
3467install_default (enum node_type node)
3468{
3469 install_element (node, &config_exit_cmd);
3470 install_element (node, &config_quit_cmd);
3471 install_element (node, &config_end_cmd);
3472 install_element (node, &config_help_cmd);
3473 install_element (node, &config_list_cmd);
3474
3475 install_element (node, &config_write_terminal_cmd);
3476 install_element (node, &config_write_file_cmd);
3477 install_element (node, &config_write_memory_cmd);
3478 install_element (node, &config_write_cmd);
3479 install_element (node, &show_running_config_cmd);
3480}
3481
3482/* Initialize command interface. Install basic nodes and commands. */
3483void
3484cmd_init (int terminal)
3485{
3486 /* Allocate initial top vector of commands. */
3487 cmdvec = vector_init (VECTOR_MIN_SIZE);
3488
3489 /* Default host value settings. */
3490 host.name = NULL;
3491 host.password = NULL;
3492 host.enable = NULL;
3493 host.logfile = NULL;
3494 host.config = NULL;
3495 host.lines = -1;
3496 host.motd = default_motd;
paul3b0c5d92005-03-08 10:43:43 +00003497 host.motdfile = NULL;
paul718e3742002-12-13 20:15:29 +00003498
3499 /* Install top nodes. */
3500 install_node (&view_node, NULL);
3501 install_node (&enable_node, NULL);
3502 install_node (&auth_node, NULL);
3503 install_node (&auth_enable_node, NULL);
3504 install_node (&config_node, config_write_host);
3505
3506 /* Each node's basic commands. */
3507 install_element (VIEW_NODE, &show_version_cmd);
3508 if (terminal)
3509 {
3510 install_element (VIEW_NODE, &config_list_cmd);
3511 install_element (VIEW_NODE, &config_exit_cmd);
3512 install_element (VIEW_NODE, &config_quit_cmd);
3513 install_element (VIEW_NODE, &config_help_cmd);
3514 install_element (VIEW_NODE, &config_enable_cmd);
3515 install_element (VIEW_NODE, &config_terminal_length_cmd);
3516 install_element (VIEW_NODE, &config_terminal_no_length_cmd);
ajs274a4a42004-12-07 15:39:31 +00003517 install_element (VIEW_NODE, &show_logging_cmd);
ajs2885f722004-12-17 23:16:33 +00003518 install_element (VIEW_NODE, &echo_cmd);
paul718e3742002-12-13 20:15:29 +00003519 }
3520
3521 if (terminal)
3522 {
3523 install_default (ENABLE_NODE);
3524 install_element (ENABLE_NODE, &config_disable_cmd);
3525 install_element (ENABLE_NODE, &config_terminal_cmd);
3526 install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
3527 }
3528 install_element (ENABLE_NODE, &show_startup_config_cmd);
3529 install_element (ENABLE_NODE, &show_version_cmd);
paul718e3742002-12-13 20:15:29 +00003530
3531 if (terminal)
paul718e3742002-12-13 20:15:29 +00003532 {
hassoe7168df2004-10-03 20:11:32 +00003533 install_element (ENABLE_NODE, &config_terminal_length_cmd);
3534 install_element (ENABLE_NODE, &config_terminal_no_length_cmd);
ajs274a4a42004-12-07 15:39:31 +00003535 install_element (ENABLE_NODE, &show_logging_cmd);
ajs2885f722004-12-17 23:16:33 +00003536 install_element (ENABLE_NODE, &echo_cmd);
ajs274a4a42004-12-07 15:39:31 +00003537 install_element (ENABLE_NODE, &config_logmsg_cmd);
hassoe7168df2004-10-03 20:11:32 +00003538
3539 install_default (CONFIG_NODE);
hassoea8e9d92004-10-07 21:32:14 +00003540 }
3541
3542 install_element (CONFIG_NODE, &hostname_cmd);
3543 install_element (CONFIG_NODE, &no_hostname_cmd);
hassoe7168df2004-10-03 20:11:32 +00003544
hassoea8e9d92004-10-07 21:32:14 +00003545 if (terminal)
3546 {
hassoe7168df2004-10-03 20:11:32 +00003547 install_element (CONFIG_NODE, &password_cmd);
3548 install_element (CONFIG_NODE, &password_text_cmd);
3549 install_element (CONFIG_NODE, &enable_password_cmd);
3550 install_element (CONFIG_NODE, &enable_password_text_cmd);
3551 install_element (CONFIG_NODE, &no_enable_password_cmd);
3552
paul718e3742002-12-13 20:15:29 +00003553 install_element (CONFIG_NODE, &config_log_stdout_cmd);
ajs274a4a42004-12-07 15:39:31 +00003554 install_element (CONFIG_NODE, &config_log_stdout_level_cmd);
paul718e3742002-12-13 20:15:29 +00003555 install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
ajs274a4a42004-12-07 15:39:31 +00003556 install_element (CONFIG_NODE, &config_log_monitor_cmd);
3557 install_element (CONFIG_NODE, &config_log_monitor_level_cmd);
3558 install_element (CONFIG_NODE, &no_config_log_monitor_cmd);
paul718e3742002-12-13 20:15:29 +00003559 install_element (CONFIG_NODE, &config_log_file_cmd);
ajs274a4a42004-12-07 15:39:31 +00003560 install_element (CONFIG_NODE, &config_log_file_level_cmd);
paul718e3742002-12-13 20:15:29 +00003561 install_element (CONFIG_NODE, &no_config_log_file_cmd);
ajs274a4a42004-12-07 15:39:31 +00003562 install_element (CONFIG_NODE, &no_config_log_file_level_cmd);
paul718e3742002-12-13 20:15:29 +00003563 install_element (CONFIG_NODE, &config_log_syslog_cmd);
ajs274a4a42004-12-07 15:39:31 +00003564 install_element (CONFIG_NODE, &config_log_syslog_level_cmd);
paul12ab19f2003-07-26 06:14:55 +00003565 install_element (CONFIG_NODE, &config_log_syslog_facility_cmd);
paul718e3742002-12-13 20:15:29 +00003566 install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
paul12ab19f2003-07-26 06:14:55 +00003567 install_element (CONFIG_NODE, &no_config_log_syslog_facility_cmd);
ajs274a4a42004-12-07 15:39:31 +00003568 install_element (CONFIG_NODE, &config_log_facility_cmd);
3569 install_element (CONFIG_NODE, &no_config_log_facility_cmd);
paul718e3742002-12-13 20:15:29 +00003570 install_element (CONFIG_NODE, &config_log_trap_cmd);
3571 install_element (CONFIG_NODE, &no_config_log_trap_cmd);
3572 install_element (CONFIG_NODE, &config_log_record_priority_cmd);
3573 install_element (CONFIG_NODE, &no_config_log_record_priority_cmd);
3574 install_element (CONFIG_NODE, &service_password_encrypt_cmd);
3575 install_element (CONFIG_NODE, &no_service_password_encrypt_cmd);
3576 install_element (CONFIG_NODE, &banner_motd_default_cmd);
paul3b0c5d92005-03-08 10:43:43 +00003577 install_element (CONFIG_NODE, &banner_motd_file_cmd);
paul718e3742002-12-13 20:15:29 +00003578 install_element (CONFIG_NODE, &no_banner_motd_cmd);
3579 install_element (CONFIG_NODE, &service_terminal_length_cmd);
3580 install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
paul718e3742002-12-13 20:15:29 +00003581
paul354d1192005-04-25 16:26:42 +00003582 install_element (VIEW_NODE, &show_thread_cpu_cmd);
3583 install_element (ENABLE_NODE, &show_thread_cpu_cmd);
3584 install_element (VIEW_NODE, &show_work_queues_cmd);
3585 install_element (ENABLE_NODE, &show_work_queues_cmd);
paul9ab68122003-01-18 01:16:20 +00003586 }
paul718e3742002-12-13 20:15:29 +00003587 srand(time(NULL));
3588}