blob: 641181038e4afac48e43b45a2431537bc6a582d6 [file] [log] [blame]
ajs274a4a42004-12-07 15:39:31 +00001/*
paul55468c82005-03-14 20:19:01 +00002 $Id: command.c,v 1.46 2005/03/14 20:19:01 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"
paul718e3742002-12-13 20:15:29 +000034
35/* Command vector which includes some level of command lists. Normally
36 each daemon maintains each own cmdvec. */
37vector cmdvec;
38
39/* Host information structure. */
40struct host host;
41
paul718e3742002-12-13 20:15:29 +000042/* Standard command node structures. */
43struct cmd_node auth_node =
44{
45 AUTH_NODE,
46 "Password: ",
47};
48
49struct cmd_node view_node =
50{
51 VIEW_NODE,
52 "%s> ",
53};
54
55struct cmd_node auth_enable_node =
56{
57 AUTH_ENABLE_NODE,
58 "Password: ",
59};
60
61struct cmd_node enable_node =
62{
63 ENABLE_NODE,
64 "%s# ",
65};
66
67struct cmd_node config_node =
68{
69 CONFIG_NODE,
70 "%s(config)# ",
71 1
72};
hasso6590f2c2004-10-19 20:40:08 +000073
74/* Default motd string. */
75const char *default_motd =
76"\r\n\
77Hello, this is " QUAGGA_PROGNAME " (version " QUAGGA_VERSION ").\r\n\
78" QUAGGA_COPYRIGHT "\r\n\
79\r\n";
80
ajs274a4a42004-12-07 15:39:31 +000081
82static struct facility_map {
83 int facility;
84 const char *name;
85 size_t match;
86} syslog_facilities[] =
87 {
88 { LOG_KERN, "kern", 1 },
89 { LOG_USER, "user", 2 },
90 { LOG_MAIL, "mail", 1 },
91 { LOG_DAEMON, "daemon", 1 },
92 { LOG_AUTH, "auth", 1 },
93 { LOG_SYSLOG, "syslog", 1 },
94 { LOG_LPR, "lpr", 2 },
95 { LOG_NEWS, "news", 1 },
96 { LOG_UUCP, "uucp", 2 },
97 { LOG_CRON, "cron", 1 },
98#ifdef LOG_FTP
99 { LOG_FTP, "ftp", 1 },
100#endif
101 { LOG_LOCAL0, "local0", 6 },
102 { LOG_LOCAL1, "local1", 6 },
103 { LOG_LOCAL2, "local2", 6 },
104 { LOG_LOCAL3, "local3", 6 },
105 { LOG_LOCAL4, "local4", 6 },
106 { LOG_LOCAL5, "local5", 6 },
107 { LOG_LOCAL6, "local6", 6 },
108 { LOG_LOCAL7, "local7", 6 },
109 { 0, NULL, 0 },
110 };
111
112static const char *
113facility_name(int facility)
114{
115 struct facility_map *fm;
116
117 for (fm = syslog_facilities; fm->name; fm++)
118 if (fm->facility == facility)
119 return fm->name;
120 return "";
121}
122
123static int
124facility_match(const char *str)
125{
126 struct facility_map *fm;
127
128 for (fm = syslog_facilities; fm->name; fm++)
129 if (!strncmp(str,fm->name,fm->match))
130 return fm->facility;
131 return -1;
132}
133
134static int
135level_match(const char *s)
136{
137 int level ;
138
139 for ( level = 0 ; zlog_priority [level] != NULL ; level ++ )
140 if (!strncmp (s, zlog_priority[level], 2))
141 return level;
142 return ZLOG_DISABLED;
143}
144
ajscb585b62005-01-14 17:09:38 +0000145/* This is called from main when a daemon is invoked with -v or --version. */
hasso6590f2c2004-10-19 20:40:08 +0000146void
147print_version (const char *progname)
148{
ajscb585b62005-01-14 17:09:38 +0000149 printf ("%s version %s\n", progname, QUAGGA_VERSION);
150 printf ("%s\n", QUAGGA_COPYRIGHT);
hasso6590f2c2004-10-19 20:40:08 +0000151}
152
paul718e3742002-12-13 20:15:29 +0000153
154/* Utility function to concatenate argv argument into a single string
155 with inserting ' ' character between each argument. */
156char *
paul42d49862004-10-13 05:22:18 +0000157argv_concat (const char **argv, int argc, int shift)
paul718e3742002-12-13 20:15:29 +0000158{
159 int i;
ajsf6834d42005-01-28 20:28:35 +0000160 size_t len;
paul718e3742002-12-13 20:15:29 +0000161 char *str;
ajsf6834d42005-01-28 20:28:35 +0000162 char *p;
paul718e3742002-12-13 20:15:29 +0000163
ajsf6834d42005-01-28 20:28:35 +0000164 len = 0;
165 for (i = shift; i < argc; i++)
166 len += strlen(argv[i])+1;
167 if (!len)
168 return NULL;
169 p = str = XMALLOC(MTYPE_TMP, len);
paul718e3742002-12-13 20:15:29 +0000170 for (i = shift; i < argc; i++)
171 {
ajsf6834d42005-01-28 20:28:35 +0000172 size_t arglen;
173 memcpy(p, argv[i], (arglen = strlen(argv[i])));
174 p += arglen;
175 *p++ = ' ';
paul718e3742002-12-13 20:15:29 +0000176 }
ajsf6834d42005-01-28 20:28:35 +0000177 *(p-1) = '\0';
paul718e3742002-12-13 20:15:29 +0000178 return str;
179}
180
181/* Install top node of command vector. */
182void
183install_node (struct cmd_node *node,
184 int (*func) (struct vty *))
185{
186 vector_set_index (cmdvec, node->node, node);
187 node->func = func;
188 node->cmd_vector = vector_init (VECTOR_MIN_SIZE);
189}
190
191/* Compare two command's string. Used in sort_node (). */
ajs274a4a42004-12-07 15:39:31 +0000192static int
paul718e3742002-12-13 20:15:29 +0000193cmp_node (const void *p, const void *q)
194{
195 struct cmd_element *a = *(struct cmd_element **)p;
196 struct cmd_element *b = *(struct cmd_element **)q;
197
198 return strcmp (a->string, b->string);
199}
200
ajs274a4a42004-12-07 15:39:31 +0000201static int
paul718e3742002-12-13 20:15:29 +0000202cmp_desc (const void *p, const void *q)
203{
204 struct desc *a = *(struct desc **)p;
205 struct desc *b = *(struct desc **)q;
206
207 return strcmp (a->cmd, b->cmd);
208}
209
210/* Sort each node's command element according to command string. */
211void
212sort_node ()
213{
hasso8c328f12004-10-05 21:01:23 +0000214 unsigned int i, j;
paul718e3742002-12-13 20:15:29 +0000215 struct cmd_node *cnode;
216 vector descvec;
217 struct cmd_element *cmd_element;
218
paul55468c82005-03-14 20:19:01 +0000219 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +0000220 if ((cnode = vector_slot (cmdvec, i)) != NULL)
221 {
222 vector cmd_vector = cnode->cmd_vector;
paul55468c82005-03-14 20:19:01 +0000223 qsort (cmd_vector->index, vector_active (cmd_vector),
paulb8961472005-03-14 17:35:52 +0000224 sizeof (void *), cmp_node);
paul718e3742002-12-13 20:15:29 +0000225
paul55468c82005-03-14 20:19:01 +0000226 for (j = 0; j < vector_active (cmd_vector); j++)
paulb8961472005-03-14 17:35:52 +0000227 if ((cmd_element = vector_slot (cmd_vector, j)) != NULL
paul55468c82005-03-14 20:19:01 +0000228 && vector_active (cmd_element->strvec))
paul718e3742002-12-13 20:15:29 +0000229 {
230 descvec = vector_slot (cmd_element->strvec,
paul55468c82005-03-14 20:19:01 +0000231 vector_active (cmd_element->strvec) - 1);
232 qsort (descvec->index, vector_active (descvec),
paulb8961472005-03-14 17:35:52 +0000233 sizeof (void *), cmp_desc);
paul718e3742002-12-13 20:15:29 +0000234 }
235 }
236}
237
238/* Breaking up string into each command piece. I assume given
239 character is separated by a space character. Return value is a
240 vector which includes char ** data element. */
241vector
hassoea8e9d92004-10-07 21:32:14 +0000242cmd_make_strvec (const char *string)
paul718e3742002-12-13 20:15:29 +0000243{
hassoea8e9d92004-10-07 21:32:14 +0000244 const char *cp, *start;
245 char *token;
paul718e3742002-12-13 20:15:29 +0000246 int strlen;
247 vector strvec;
248
249 if (string == NULL)
250 return NULL;
251
252 cp = string;
253
254 /* Skip white spaces. */
255 while (isspace ((int) *cp) && *cp != '\0')
256 cp++;
257
258 /* Return if there is only white spaces */
259 if (*cp == '\0')
260 return NULL;
261
262 if (*cp == '!' || *cp == '#')
263 return NULL;
264
265 /* Prepare return vector. */
266 strvec = vector_init (VECTOR_MIN_SIZE);
267
268 /* Copy each command piece and set into vector. */
269 while (1)
270 {
271 start = cp;
272 while (!(isspace ((int) *cp) || *cp == '\r' || *cp == '\n') &&
273 *cp != '\0')
274 cp++;
275 strlen = cp - start;
276 token = XMALLOC (MTYPE_STRVEC, strlen + 1);
277 memcpy (token, start, strlen);
278 *(token + strlen) = '\0';
279 vector_set (strvec, token);
280
281 while ((isspace ((int) *cp) || *cp == '\n' || *cp == '\r') &&
282 *cp != '\0')
283 cp++;
284
285 if (*cp == '\0')
286 return strvec;
287 }
288}
289
290/* Free allocated string vector. */
291void
292cmd_free_strvec (vector v)
293{
hasso8c328f12004-10-05 21:01:23 +0000294 unsigned int i;
paul718e3742002-12-13 20:15:29 +0000295 char *cp;
296
297 if (!v)
298 return;
299
paul55468c82005-03-14 20:19:01 +0000300 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +0000301 if ((cp = vector_slot (v, i)) != NULL)
302 XFREE (MTYPE_STRVEC, cp);
303
304 vector_free (v);
305}
306
307/* Fetch next description. Used in cmd_make_descvec(). */
ajs274a4a42004-12-07 15:39:31 +0000308static char *
hasso6ad96ea2004-10-07 19:33:46 +0000309cmd_desc_str (const char **string)
paul718e3742002-12-13 20:15:29 +0000310{
hasso6ad96ea2004-10-07 19:33:46 +0000311 const char *cp, *start;
312 char *token;
paul718e3742002-12-13 20:15:29 +0000313 int strlen;
314
315 cp = *string;
316
317 if (cp == NULL)
318 return NULL;
319
320 /* Skip white spaces. */
321 while (isspace ((int) *cp) && *cp != '\0')
322 cp++;
323
324 /* Return if there is only white spaces */
325 if (*cp == '\0')
326 return NULL;
327
328 start = cp;
329
330 while (!(*cp == '\r' || *cp == '\n') && *cp != '\0')
331 cp++;
332
333 strlen = cp - start;
334 token = XMALLOC (MTYPE_STRVEC, strlen + 1);
335 memcpy (token, start, strlen);
336 *(token + strlen) = '\0';
337
338 *string = cp;
339
340 return token;
341}
342
343/* New string vector. */
ajs274a4a42004-12-07 15:39:31 +0000344static vector
hasso8c328f12004-10-05 21:01:23 +0000345cmd_make_descvec (const char *string, const char *descstr)
paul718e3742002-12-13 20:15:29 +0000346{
347 int multiple = 0;
hasso8c328f12004-10-05 21:01:23 +0000348 const char *sp;
paul718e3742002-12-13 20:15:29 +0000349 char *token;
350 int len;
hasso8c328f12004-10-05 21:01:23 +0000351 const char *cp;
352 const char *dp;
paul718e3742002-12-13 20:15:29 +0000353 vector allvec;
354 vector strvec = NULL;
355 struct desc *desc;
356
357 cp = string;
358 dp = descstr;
359
360 if (cp == NULL)
361 return NULL;
362
363 allvec = vector_init (VECTOR_MIN_SIZE);
364
365 while (1)
366 {
367 while (isspace ((int) *cp) && *cp != '\0')
368 cp++;
369
370 if (*cp == '(')
371 {
372 multiple = 1;
373 cp++;
374 }
375 if (*cp == ')')
376 {
377 multiple = 0;
378 cp++;
379 }
380 if (*cp == '|')
381 {
382 if (! multiple)
383 {
384 fprintf (stderr, "Command parse error!: %s\n", string);
385 exit (1);
386 }
387 cp++;
388 }
389
390 while (isspace ((int) *cp) && *cp != '\0')
391 cp++;
392
393 if (*cp == '(')
394 {
395 multiple = 1;
396 cp++;
397 }
398
399 if (*cp == '\0')
400 return allvec;
401
402 sp = cp;
403
404 while (! (isspace ((int) *cp) || *cp == '\r' || *cp == '\n' || *cp == ')' || *cp == '|') && *cp != '\0')
405 cp++;
406
407 len = cp - sp;
408
409 token = XMALLOC (MTYPE_STRVEC, len + 1);
410 memcpy (token, sp, len);
411 *(token + len) = '\0';
412
413 desc = XCALLOC (MTYPE_DESC, sizeof (struct desc));
414 desc->cmd = token;
415 desc->str = cmd_desc_str (&dp);
416
417 if (multiple)
418 {
419 if (multiple == 1)
420 {
421 strvec = vector_init (VECTOR_MIN_SIZE);
422 vector_set (allvec, strvec);
423 }
424 multiple++;
425 }
426 else
427 {
428 strvec = vector_init (VECTOR_MIN_SIZE);
429 vector_set (allvec, strvec);
430 }
431 vector_set (strvec, desc);
432 }
433}
434
435/* Count mandantory string vector size. This is to determine inputed
436 command has enough command length. */
ajs274a4a42004-12-07 15:39:31 +0000437static int
paul718e3742002-12-13 20:15:29 +0000438cmd_cmdsize (vector strvec)
439{
hasso8c328f12004-10-05 21:01:23 +0000440 unsigned int i;
paul718e3742002-12-13 20:15:29 +0000441 int size = 0;
442 vector descvec;
paulb8961472005-03-14 17:35:52 +0000443 struct desc *desc;
paul718e3742002-12-13 20:15:29 +0000444
paul55468c82005-03-14 20:19:01 +0000445 for (i = 0; i < vector_active (strvec); i++)
paulb8961472005-03-14 17:35:52 +0000446 if ((descvec = vector_slot (strvec, i)) != NULL)
paul718e3742002-12-13 20:15:29 +0000447 {
paul55468c82005-03-14 20:19:01 +0000448 if ((vector_active (descvec)) == 1
paulb8961472005-03-14 17:35:52 +0000449 && (desc = vector_slot (descvec, 0)) != NULL)
paul718e3742002-12-13 20:15:29 +0000450 {
hasso8c328f12004-10-05 21:01:23 +0000451 if (desc->cmd == NULL || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +0000452 return size;
453 else
454 size++;
455 }
456 else
457 size++;
458 }
459 return size;
460}
461
462/* Return prompt character of specified node. */
hasso8c328f12004-10-05 21:01:23 +0000463const char *
paul718e3742002-12-13 20:15:29 +0000464cmd_prompt (enum node_type node)
465{
466 struct cmd_node *cnode;
467
468 cnode = vector_slot (cmdvec, node);
469 return cnode->prompt;
470}
471
472/* Install a command into a node. */
473void
474install_element (enum node_type ntype, struct cmd_element *cmd)
475{
476 struct cmd_node *cnode;
477
478 cnode = vector_slot (cmdvec, ntype);
479
480 if (cnode == NULL)
481 {
482 fprintf (stderr, "Command node %d doesn't exist, please check it\n",
483 ntype);
484 exit (1);
485 }
486
487 vector_set (cnode->cmd_vector, cmd);
488
489 cmd->strvec = cmd_make_descvec (cmd->string, cmd->doc);
490 cmd->cmdsize = cmd_cmdsize (cmd->strvec);
491}
492
493static unsigned char itoa64[] =
494"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
495
ajs274a4a42004-12-07 15:39:31 +0000496static void
paul718e3742002-12-13 20:15:29 +0000497to64(char *s, long v, int n)
498{
499 while (--n >= 0)
500 {
501 *s++ = itoa64[v&0x3f];
502 v >>= 6;
503 }
504}
505
ajs274a4a42004-12-07 15:39:31 +0000506static char *
507zencrypt (const char *passwd)
paul718e3742002-12-13 20:15:29 +0000508{
509 char salt[6];
510 struct timeval tv;
511 char *crypt (const char *, const char *);
512
513 gettimeofday(&tv,0);
514
515 to64(&salt[0], random(), 3);
516 to64(&salt[3], tv.tv_usec, 3);
517 salt[5] = '\0';
518
519 return crypt (passwd, salt);
520}
521
522/* This function write configuration of this host. */
ajs274a4a42004-12-07 15:39:31 +0000523static int
paul718e3742002-12-13 20:15:29 +0000524config_write_host (struct vty *vty)
525{
526 if (host.name)
527 vty_out (vty, "hostname %s%s", host.name, VTY_NEWLINE);
528
529 if (host.encrypt)
530 {
531 if (host.password_encrypt)
532 vty_out (vty, "password 8 %s%s", host.password_encrypt, VTY_NEWLINE);
533 if (host.enable_encrypt)
534 vty_out (vty, "enable password 8 %s%s", host.enable_encrypt, VTY_NEWLINE);
535 }
536 else
537 {
538 if (host.password)
539 vty_out (vty, "password %s%s", host.password, VTY_NEWLINE);
540 if (host.enable)
541 vty_out (vty, "enable password %s%s", host.enable, VTY_NEWLINE);
542 }
543
ajs274a4a42004-12-07 15:39:31 +0000544 if (zlog_default->default_lvl != LOG_DEBUG)
ajs82146b82004-12-07 17:15:55 +0000545 {
546 vty_out (vty, "! N.B. The 'log trap' command is deprecated.%s",
547 VTY_NEWLINE);
548 vty_out (vty, "log trap %s%s",
549 zlog_priority[zlog_default->default_lvl], VTY_NEWLINE);
550 }
paul718e3742002-12-13 20:15:29 +0000551
ajs274a4a42004-12-07 15:39:31 +0000552 if (host.logfile && (zlog_default->maxlvl[ZLOG_DEST_FILE] != ZLOG_DISABLED))
paul12ab19f2003-07-26 06:14:55 +0000553 {
ajs274a4a42004-12-07 15:39:31 +0000554 vty_out (vty, "log file %s", host.logfile);
555 if (zlog_default->maxlvl[ZLOG_DEST_FILE] != zlog_default->default_lvl)
556 vty_out (vty, " %s",
557 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_FILE]]);
paul12ab19f2003-07-26 06:14:55 +0000558 vty_out (vty, "%s", VTY_NEWLINE);
559 }
ajs274a4a42004-12-07 15:39:31 +0000560
561 if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != ZLOG_DISABLED)
562 {
563 vty_out (vty, "log stdout");
564 if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != zlog_default->default_lvl)
565 vty_out (vty, " %s",
566 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_STDOUT]]);
567 vty_out (vty, "%s", VTY_NEWLINE);
568 }
569
570 if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
571 vty_out(vty,"no log monitor%s",VTY_NEWLINE);
572 else if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] != zlog_default->default_lvl)
573 vty_out(vty,"log monitor %s%s",
574 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_MONITOR]],VTY_NEWLINE);
575
576 if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED)
577 {
578 vty_out (vty, "log syslog");
579 if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != zlog_default->default_lvl)
580 vty_out (vty, " %s",
581 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_SYSLOG]]);
582 vty_out (vty, "%s", VTY_NEWLINE);
583 }
584
585 if (zlog_default->facility != LOG_DAEMON)
586 vty_out (vty, "log facility %s%s",
587 facility_name(zlog_default->facility), VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +0000588
589 if (zlog_default->record_priority == 1)
590 vty_out (vty, "log record-priority%s", VTY_NEWLINE);
591
592 if (host.advanced)
593 vty_out (vty, "service advanced-vty%s", VTY_NEWLINE);
594
595 if (host.encrypt)
596 vty_out (vty, "service password-encryption%s", VTY_NEWLINE);
597
598 if (host.lines >= 0)
599 vty_out (vty, "service terminal-length %d%s", host.lines,
600 VTY_NEWLINE);
601
paul3b0c5d92005-03-08 10:43:43 +0000602 if (host.motdfile)
603 vty_out (vty, "banner motd file %s%s", host.motdfile, VTY_NEWLINE);
604 else if (! host.motd)
paul718e3742002-12-13 20:15:29 +0000605 vty_out (vty, "no banner motd%s", VTY_NEWLINE);
606
607 return 1;
608}
609
610/* Utility function for getting command vector. */
ajs274a4a42004-12-07 15:39:31 +0000611static vector
paul718e3742002-12-13 20:15:29 +0000612cmd_node_vector (vector v, enum node_type ntype)
613{
614 struct cmd_node *cnode = vector_slot (v, ntype);
615 return cnode->cmd_vector;
616}
617
ajs274a4a42004-12-07 15:39:31 +0000618#if 0
619/* Filter command vector by symbol. This function is not actually used;
620 * should it be deleted? */
621static int
paul718e3742002-12-13 20:15:29 +0000622cmd_filter_by_symbol (char *command, char *symbol)
623{
624 int i, lim;
625
626 if (strcmp (symbol, "IPV4_ADDRESS") == 0)
627 {
628 i = 0;
629 lim = strlen (command);
630 while (i < lim)
631 {
632 if (! (isdigit ((int) command[i]) || command[i] == '.' || command[i] == '/'))
633 return 1;
634 i++;
635 }
636 return 0;
637 }
638 if (strcmp (symbol, "STRING") == 0)
639 {
640 i = 0;
641 lim = strlen (command);
642 while (i < lim)
643 {
644 if (! (isalpha ((int) command[i]) || command[i] == '_' || command[i] == '-'))
645 return 1;
646 i++;
647 }
648 return 0;
649 }
650 if (strcmp (symbol, "IFNAME") == 0)
651 {
652 i = 0;
653 lim = strlen (command);
654 while (i < lim)
655 {
656 if (! isalnum ((int) command[i]))
657 return 1;
658 i++;
659 }
660 return 0;
661 }
662 return 0;
663}
ajs274a4a42004-12-07 15:39:31 +0000664#endif
paul718e3742002-12-13 20:15:29 +0000665
666/* Completion match types. */
667enum match_type
668{
669 no_match,
670 extend_match,
671 ipv4_prefix_match,
672 ipv4_match,
673 ipv6_prefix_match,
674 ipv6_match,
675 range_match,
676 vararg_match,
677 partly_match,
678 exact_match
679};
680
ajs274a4a42004-12-07 15:39:31 +0000681static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000682cmd_ipv4_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000683{
hasso8c328f12004-10-05 21:01:23 +0000684 const char *sp;
paul718e3742002-12-13 20:15:29 +0000685 int dots = 0, nums = 0;
686 char buf[4];
687
688 if (str == NULL)
689 return partly_match;
690
691 for (;;)
692 {
693 memset (buf, 0, sizeof (buf));
694 sp = str;
695 while (*str != '\0')
696 {
697 if (*str == '.')
698 {
699 if (dots >= 3)
700 return no_match;
701
702 if (*(str + 1) == '.')
703 return no_match;
704
705 if (*(str + 1) == '\0')
706 return partly_match;
707
708 dots++;
709 break;
710 }
711 if (!isdigit ((int) *str))
712 return no_match;
713
714 str++;
715 }
716
717 if (str - sp > 3)
718 return no_match;
719
720 strncpy (buf, sp, str - sp);
721 if (atoi (buf) > 255)
722 return no_match;
723
724 nums++;
725
726 if (*str == '\0')
727 break;
728
729 str++;
730 }
731
732 if (nums < 4)
733 return partly_match;
734
735 return exact_match;
736}
737
ajs274a4a42004-12-07 15:39:31 +0000738static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000739cmd_ipv4_prefix_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000740{
hasso8c328f12004-10-05 21:01:23 +0000741 const char *sp;
paul718e3742002-12-13 20:15:29 +0000742 int dots = 0;
743 char buf[4];
744
745 if (str == NULL)
746 return partly_match;
747
748 for (;;)
749 {
750 memset (buf, 0, sizeof (buf));
751 sp = str;
752 while (*str != '\0' && *str != '/')
753 {
754 if (*str == '.')
755 {
756 if (dots == 3)
757 return no_match;
758
759 if (*(str + 1) == '.' || *(str + 1) == '/')
760 return no_match;
761
762 if (*(str + 1) == '\0')
763 return partly_match;
764
765 dots++;
766 break;
767 }
768
769 if (!isdigit ((int) *str))
770 return no_match;
771
772 str++;
773 }
774
775 if (str - sp > 3)
776 return no_match;
777
778 strncpy (buf, sp, str - sp);
779 if (atoi (buf) > 255)
780 return no_match;
781
782 if (dots == 3)
783 {
784 if (*str == '/')
785 {
786 if (*(str + 1) == '\0')
787 return partly_match;
788
789 str++;
790 break;
791 }
792 else if (*str == '\0')
793 return partly_match;
794 }
795
796 if (*str == '\0')
797 return partly_match;
798
799 str++;
800 }
801
802 sp = str;
803 while (*str != '\0')
804 {
805 if (!isdigit ((int) *str))
806 return no_match;
807
808 str++;
809 }
810
811 if (atoi (sp) > 32)
812 return no_match;
813
814 return exact_match;
815}
816
817#define IPV6_ADDR_STR "0123456789abcdefABCDEF:.%"
818#define IPV6_PREFIX_STR "0123456789abcdefABCDEF:.%/"
819#define STATE_START 1
820#define STATE_COLON 2
821#define STATE_DOUBLE 3
822#define STATE_ADDR 4
823#define STATE_DOT 5
824#define STATE_SLASH 6
825#define STATE_MASK 7
826
paul22e0a9e2003-07-11 17:55:46 +0000827#ifdef HAVE_IPV6
828
ajs274a4a42004-12-07 15:39:31 +0000829static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000830cmd_ipv6_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000831{
832 int state = STATE_START;
833 int colons = 0, nums = 0, double_colon = 0;
hasso8c328f12004-10-05 21:01:23 +0000834 const char *sp = NULL;
hasso726f9b22003-05-25 21:04:54 +0000835 struct sockaddr_in6 sin6_dummy;
836 int ret;
paul718e3742002-12-13 20:15:29 +0000837
838 if (str == NULL)
839 return partly_match;
840
841 if (strspn (str, IPV6_ADDR_STR) != strlen (str))
842 return no_match;
843
hasso726f9b22003-05-25 21:04:54 +0000844 /* use inet_pton that has a better support,
845 * for example inet_pton can support the automatic addresses:
846 * ::1.2.3.4
847 */
848 ret = inet_pton(AF_INET6, str, &sin6_dummy.sin6_addr);
849
850 if (ret == 1)
851 return exact_match;
852
paul718e3742002-12-13 20:15:29 +0000853 while (*str != '\0')
854 {
855 switch (state)
856 {
857 case STATE_START:
858 if (*str == ':')
859 {
860 if (*(str + 1) != ':' && *(str + 1) != '\0')
861 return no_match;
862 colons--;
863 state = STATE_COLON;
864 }
865 else
866 {
867 sp = str;
868 state = STATE_ADDR;
869 }
870
871 continue;
872 case STATE_COLON:
873 colons++;
874 if (*(str + 1) == ':')
875 state = STATE_DOUBLE;
876 else
877 {
878 sp = str + 1;
879 state = STATE_ADDR;
880 }
881 break;
882 case STATE_DOUBLE:
883 if (double_colon)
884 return no_match;
885
886 if (*(str + 1) == ':')
887 return no_match;
888 else
889 {
890 if (*(str + 1) != '\0')
891 colons++;
892 sp = str + 1;
893 state = STATE_ADDR;
894 }
895
896 double_colon++;
897 nums++;
898 break;
899 case STATE_ADDR:
900 if (*(str + 1) == ':' || *(str + 1) == '\0')
901 {
902 if (str - sp > 3)
903 return no_match;
904
905 nums++;
906 state = STATE_COLON;
907 }
908 if (*(str + 1) == '.')
909 state = STATE_DOT;
910 break;
911 case STATE_DOT:
912 state = STATE_ADDR;
913 break;
914 default:
915 break;
916 }
917
918 if (nums > 8)
919 return no_match;
920
921 if (colons > 7)
922 return no_match;
923
924 str++;
925 }
926
927#if 0
928 if (nums < 11)
929 return partly_match;
930#endif /* 0 */
931
932 return exact_match;
933}
934
ajs274a4a42004-12-07 15:39:31 +0000935static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000936cmd_ipv6_prefix_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000937{
938 int state = STATE_START;
939 int colons = 0, nums = 0, double_colon = 0;
940 int mask;
hasso8c328f12004-10-05 21:01:23 +0000941 const char *sp = NULL;
paul718e3742002-12-13 20:15:29 +0000942 char *endptr = NULL;
943
944 if (str == NULL)
945 return partly_match;
946
947 if (strspn (str, IPV6_PREFIX_STR) != strlen (str))
948 return no_match;
949
950 while (*str != '\0' && state != STATE_MASK)
951 {
952 switch (state)
953 {
954 case STATE_START:
955 if (*str == ':')
956 {
957 if (*(str + 1) != ':' && *(str + 1) != '\0')
958 return no_match;
959 colons--;
960 state = STATE_COLON;
961 }
962 else
963 {
964 sp = str;
965 state = STATE_ADDR;
966 }
967
968 continue;
969 case STATE_COLON:
970 colons++;
971 if (*(str + 1) == '/')
972 return no_match;
973 else if (*(str + 1) == ':')
974 state = STATE_DOUBLE;
975 else
976 {
977 sp = str + 1;
978 state = STATE_ADDR;
979 }
980 break;
981 case STATE_DOUBLE:
982 if (double_colon)
983 return no_match;
984
985 if (*(str + 1) == ':')
986 return no_match;
987 else
988 {
989 if (*(str + 1) != '\0' && *(str + 1) != '/')
990 colons++;
991 sp = str + 1;
992
993 if (*(str + 1) == '/')
994 state = STATE_SLASH;
995 else
996 state = STATE_ADDR;
997 }
998
999 double_colon++;
1000 nums += 1;
1001 break;
1002 case STATE_ADDR:
1003 if (*(str + 1) == ':' || *(str + 1) == '.'
1004 || *(str + 1) == '\0' || *(str + 1) == '/')
1005 {
1006 if (str - sp > 3)
1007 return no_match;
1008
1009 for (; sp <= str; sp++)
1010 if (*sp == '/')
1011 return no_match;
1012
1013 nums++;
1014
1015 if (*(str + 1) == ':')
1016 state = STATE_COLON;
1017 else if (*(str + 1) == '.')
1018 state = STATE_DOT;
1019 else if (*(str + 1) == '/')
1020 state = STATE_SLASH;
1021 }
1022 break;
1023 case STATE_DOT:
1024 state = STATE_ADDR;
1025 break;
1026 case STATE_SLASH:
1027 if (*(str + 1) == '\0')
1028 return partly_match;
1029
1030 state = STATE_MASK;
1031 break;
1032 default:
1033 break;
1034 }
1035
1036 if (nums > 11)
1037 return no_match;
1038
1039 if (colons > 7)
1040 return no_match;
1041
1042 str++;
1043 }
1044
1045 if (state < STATE_MASK)
1046 return partly_match;
1047
1048 mask = strtol (str, &endptr, 10);
1049 if (*endptr != '\0')
1050 return no_match;
1051
1052 if (mask < 0 || mask > 128)
1053 return no_match;
1054
1055/* I don't know why mask < 13 makes command match partly.
1056 Forgive me to make this comments. I Want to set static default route
1057 because of lack of function to originate default in ospf6d; sorry
1058 yasu
1059 if (mask < 13)
1060 return partly_match;
1061*/
1062
1063 return exact_match;
1064}
1065
paul22e0a9e2003-07-11 17:55:46 +00001066#endif /* HAVE_IPV6 */
1067
paul718e3742002-12-13 20:15:29 +00001068#define DECIMAL_STRLEN_MAX 10
1069
ajs274a4a42004-12-07 15:39:31 +00001070static int
hasso8c328f12004-10-05 21:01:23 +00001071cmd_range_match (const char *range, const char *str)
paul718e3742002-12-13 20:15:29 +00001072{
1073 char *p;
1074 char buf[DECIMAL_STRLEN_MAX + 1];
1075 char *endptr = NULL;
1076 unsigned long min, max, val;
1077
1078 if (str == NULL)
1079 return 1;
1080
1081 val = strtoul (str, &endptr, 10);
1082 if (*endptr != '\0')
1083 return 0;
1084
1085 range++;
1086 p = strchr (range, '-');
1087 if (p == NULL)
1088 return 0;
1089 if (p - range > DECIMAL_STRLEN_MAX)
1090 return 0;
1091 strncpy (buf, range, p - range);
1092 buf[p - range] = '\0';
1093 min = strtoul (buf, &endptr, 10);
1094 if (*endptr != '\0')
1095 return 0;
1096
1097 range = p + 1;
1098 p = strchr (range, '>');
1099 if (p == NULL)
1100 return 0;
1101 if (p - range > DECIMAL_STRLEN_MAX)
1102 return 0;
1103 strncpy (buf, range, p - range);
1104 buf[p - range] = '\0';
1105 max = strtoul (buf, &endptr, 10);
1106 if (*endptr != '\0')
1107 return 0;
1108
1109 if (val < min || val > max)
1110 return 0;
1111
1112 return 1;
1113}
1114
1115/* Make completion match and return match type flag. */
ajs274a4a42004-12-07 15:39:31 +00001116static enum match_type
hasso8c328f12004-10-05 21:01:23 +00001117cmd_filter_by_completion (char *command, vector v, unsigned int index)
paul718e3742002-12-13 20:15:29 +00001118{
hasso8c328f12004-10-05 21:01:23 +00001119 unsigned int i;
1120 const char *str;
paul718e3742002-12-13 20:15:29 +00001121 struct cmd_element *cmd_element;
1122 enum match_type match_type;
1123 vector descvec;
1124 struct desc *desc;
paul909a2152005-03-14 17:41:45 +00001125
paul718e3742002-12-13 20:15:29 +00001126 match_type = no_match;
1127
1128 /* If command and cmd_element string does not match set NULL to vector */
paul55468c82005-03-14 20:19:01 +00001129 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001130 if ((cmd_element = vector_slot (v, i)) != NULL)
1131 {
paul55468c82005-03-14 20:19:01 +00001132 if (index >= vector_active (cmd_element->strvec))
paul718e3742002-12-13 20:15:29 +00001133 vector_slot (v, i) = NULL;
1134 else
1135 {
hasso8c328f12004-10-05 21:01:23 +00001136 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001137 int matched = 0;
1138
1139 descvec = vector_slot (cmd_element->strvec, index);
paul909a2152005-03-14 17:41:45 +00001140
paul55468c82005-03-14 20:19:01 +00001141 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001142 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001143 {
1144 str = desc->cmd;
1145
1146 if (CMD_VARARG (str))
1147 {
1148 if (match_type < vararg_match)
1149 match_type = vararg_match;
1150 matched++;
1151 }
1152 else if (CMD_RANGE (str))
1153 {
1154 if (cmd_range_match (str, command))
1155 {
1156 if (match_type < range_match)
1157 match_type = range_match;
paul718e3742002-12-13 20:15:29 +00001158
paul909a2152005-03-14 17:41:45 +00001159 matched++;
1160 }
1161 }
paul22e0a9e2003-07-11 17:55:46 +00001162#ifdef HAVE_IPV6
paul909a2152005-03-14 17:41:45 +00001163 else if (CMD_IPV6 (str))
1164 {
1165 if (cmd_ipv6_match (command))
1166 {
1167 if (match_type < ipv6_match)
1168 match_type = ipv6_match;
paul718e3742002-12-13 20:15:29 +00001169
paul909a2152005-03-14 17:41:45 +00001170 matched++;
1171 }
1172 }
1173 else if (CMD_IPV6_PREFIX (str))
1174 {
1175 if (cmd_ipv6_prefix_match (command))
1176 {
1177 if (match_type < ipv6_prefix_match)
1178 match_type = ipv6_prefix_match;
paul718e3742002-12-13 20:15:29 +00001179
paul909a2152005-03-14 17:41:45 +00001180 matched++;
1181 }
1182 }
1183#endif /* HAVE_IPV6 */
1184 else if (CMD_IPV4 (str))
1185 {
1186 if (cmd_ipv4_match (command))
1187 {
1188 if (match_type < ipv4_match)
1189 match_type = ipv4_match;
paul718e3742002-12-13 20:15:29 +00001190
paul909a2152005-03-14 17:41:45 +00001191 matched++;
1192 }
1193 }
1194 else if (CMD_IPV4_PREFIX (str))
1195 {
1196 if (cmd_ipv4_prefix_match (command))
1197 {
1198 if (match_type < ipv4_prefix_match)
1199 match_type = ipv4_prefix_match;
1200 matched++;
1201 }
1202 }
1203 else
1204 /* Check is this point's argument optional ? */
1205 if (CMD_OPTION (str) || CMD_VARIABLE (str))
1206 {
1207 if (match_type < extend_match)
1208 match_type = extend_match;
1209 matched++;
1210 }
1211 else if (strncmp (command, str, strlen (command)) == 0)
1212 {
1213 if (strcmp (command, str) == 0)
1214 match_type = exact_match;
1215 else
1216 {
1217 if (match_type < partly_match)
1218 match_type = partly_match;
1219 }
1220 matched++;
1221 }
1222 }
1223 if (!matched)
paul718e3742002-12-13 20:15:29 +00001224 vector_slot (v, i) = NULL;
1225 }
1226 }
1227 return match_type;
1228}
1229
1230/* Filter vector by command character with index. */
ajs274a4a42004-12-07 15:39:31 +00001231static enum match_type
hasso8c328f12004-10-05 21:01:23 +00001232cmd_filter_by_string (char *command, vector v, unsigned int index)
paul718e3742002-12-13 20:15:29 +00001233{
hasso8c328f12004-10-05 21:01:23 +00001234 unsigned int i;
1235 const char *str;
paul718e3742002-12-13 20:15:29 +00001236 struct cmd_element *cmd_element;
1237 enum match_type match_type;
1238 vector descvec;
1239 struct desc *desc;
paul909a2152005-03-14 17:41:45 +00001240
paul718e3742002-12-13 20:15:29 +00001241 match_type = no_match;
1242
1243 /* If command and cmd_element string does not match set NULL to vector */
paul55468c82005-03-14 20:19:01 +00001244 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001245 if ((cmd_element = vector_slot (v, i)) != NULL)
1246 {
1247 /* If given index is bigger than max string vector of command,
paul909a2152005-03-14 17:41:45 +00001248 set NULL */
paul55468c82005-03-14 20:19:01 +00001249 if (index >= vector_active (cmd_element->strvec))
paul718e3742002-12-13 20:15:29 +00001250 vector_slot (v, i) = NULL;
paul909a2152005-03-14 17:41:45 +00001251 else
paul718e3742002-12-13 20:15:29 +00001252 {
hasso8c328f12004-10-05 21:01:23 +00001253 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001254 int matched = 0;
1255
1256 descvec = vector_slot (cmd_element->strvec, index);
1257
paul55468c82005-03-14 20:19:01 +00001258 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001259 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001260 {
1261 str = desc->cmd;
paul718e3742002-12-13 20:15:29 +00001262
paul909a2152005-03-14 17:41:45 +00001263 if (CMD_VARARG (str))
1264 {
1265 if (match_type < vararg_match)
1266 match_type = vararg_match;
1267 matched++;
1268 }
1269 else if (CMD_RANGE (str))
1270 {
1271 if (cmd_range_match (str, command))
1272 {
1273 if (match_type < range_match)
1274 match_type = range_match;
1275 matched++;
1276 }
1277 }
paul22e0a9e2003-07-11 17:55:46 +00001278#ifdef HAVE_IPV6
paul909a2152005-03-14 17:41:45 +00001279 else if (CMD_IPV6 (str))
1280 {
1281 if (cmd_ipv6_match (command) == exact_match)
1282 {
1283 if (match_type < ipv6_match)
1284 match_type = ipv6_match;
1285 matched++;
1286 }
1287 }
1288 else if (CMD_IPV6_PREFIX (str))
1289 {
1290 if (cmd_ipv6_prefix_match (command) == exact_match)
1291 {
1292 if (match_type < ipv6_prefix_match)
1293 match_type = ipv6_prefix_match;
1294 matched++;
1295 }
1296 }
paul22e0a9e2003-07-11 17:55:46 +00001297#endif /* HAVE_IPV6 */
paul909a2152005-03-14 17:41:45 +00001298 else if (CMD_IPV4 (str))
1299 {
1300 if (cmd_ipv4_match (command) == exact_match)
1301 {
1302 if (match_type < ipv4_match)
1303 match_type = ipv4_match;
1304 matched++;
1305 }
1306 }
1307 else if (CMD_IPV4_PREFIX (str))
1308 {
1309 if (cmd_ipv4_prefix_match (command) == exact_match)
1310 {
1311 if (match_type < ipv4_prefix_match)
1312 match_type = ipv4_prefix_match;
1313 matched++;
1314 }
1315 }
1316 else if (CMD_OPTION (str) || CMD_VARIABLE (str))
1317 {
1318 if (match_type < extend_match)
1319 match_type = extend_match;
1320 matched++;
1321 }
1322 else
1323 {
1324 if (strcmp (command, str) == 0)
1325 {
1326 match_type = exact_match;
1327 matched++;
1328 }
1329 }
1330 }
1331 if (!matched)
paul718e3742002-12-13 20:15:29 +00001332 vector_slot (v, i) = NULL;
1333 }
1334 }
1335 return match_type;
1336}
1337
1338/* Check ambiguous match */
ajs274a4a42004-12-07 15:39:31 +00001339static int
paul718e3742002-12-13 20:15:29 +00001340is_cmd_ambiguous (char *command, vector v, int index, enum match_type type)
1341{
hasso8c328f12004-10-05 21:01:23 +00001342 unsigned int i;
1343 unsigned int j;
1344 const char *str = NULL;
paul718e3742002-12-13 20:15:29 +00001345 struct cmd_element *cmd_element;
hasso8c328f12004-10-05 21:01:23 +00001346 const char *matched = NULL;
paul718e3742002-12-13 20:15:29 +00001347 vector descvec;
1348 struct desc *desc;
paul909a2152005-03-14 17:41:45 +00001349
paul55468c82005-03-14 20:19:01 +00001350 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001351 if ((cmd_element = vector_slot (v, i)) != NULL)
1352 {
1353 int match = 0;
1354
1355 descvec = vector_slot (cmd_element->strvec, index);
1356
paul55468c82005-03-14 20:19:01 +00001357 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001358 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001359 {
1360 enum match_type ret;
1361
1362 str = desc->cmd;
paul718e3742002-12-13 20:15:29 +00001363
paul909a2152005-03-14 17:41:45 +00001364 switch (type)
1365 {
1366 case exact_match:
1367 if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
1368 && strcmp (command, str) == 0)
1369 match++;
1370 break;
1371 case partly_match:
1372 if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
1373 && strncmp (command, str, strlen (command)) == 0)
1374 {
1375 if (matched && strcmp (matched, str) != 0)
1376 return 1; /* There is ambiguous match. */
1377 else
1378 matched = str;
1379 match++;
1380 }
1381 break;
1382 case range_match:
1383 if (cmd_range_match (str, command))
1384 {
1385 if (matched && strcmp (matched, str) != 0)
1386 return 1;
1387 else
1388 matched = str;
1389 match++;
1390 }
1391 break;
1392#ifdef HAVE_IPV6
1393 case ipv6_match:
1394 if (CMD_IPV6 (str))
1395 match++;
1396 break;
1397 case ipv6_prefix_match:
1398 if ((ret = cmd_ipv6_prefix_match (command)) != no_match)
1399 {
1400 if (ret == partly_match)
1401 return 2; /* There is incomplete match. */
paul718e3742002-12-13 20:15:29 +00001402
paul909a2152005-03-14 17:41:45 +00001403 match++;
1404 }
1405 break;
1406#endif /* HAVE_IPV6 */
1407 case ipv4_match:
1408 if (CMD_IPV4 (str))
paul718e3742002-12-13 20:15:29 +00001409 match++;
paul909a2152005-03-14 17:41:45 +00001410 break;
1411 case ipv4_prefix_match:
1412 if ((ret = cmd_ipv4_prefix_match (command)) != no_match)
1413 {
1414 if (ret == partly_match)
1415 return 2; /* There is incomplete match. */
paul718e3742002-12-13 20:15:29 +00001416
paul909a2152005-03-14 17:41:45 +00001417 match++;
1418 }
1419 break;
1420 case extend_match:
1421 if (CMD_OPTION (str) || CMD_VARIABLE (str))
paul718e3742002-12-13 20:15:29 +00001422 match++;
paul909a2152005-03-14 17:41:45 +00001423 break;
1424 case no_match:
1425 default:
1426 break;
1427 }
1428 }
1429 if (!match)
paul718e3742002-12-13 20:15:29 +00001430 vector_slot (v, i) = NULL;
1431 }
1432 return 0;
1433}
1434
1435/* If src matches dst return dst string, otherwise return NULL */
ajs274a4a42004-12-07 15:39:31 +00001436static const char *
hasso8c328f12004-10-05 21:01:23 +00001437cmd_entry_function (const char *src, const char *dst)
paul718e3742002-12-13 20:15:29 +00001438{
1439 /* Skip variable arguments. */
1440 if (CMD_OPTION (dst) || CMD_VARIABLE (dst) || CMD_VARARG (dst) ||
1441 CMD_IPV4 (dst) || CMD_IPV4_PREFIX (dst) || CMD_RANGE (dst))
1442 return NULL;
1443
1444 /* In case of 'command \t', given src is NULL string. */
1445 if (src == NULL)
1446 return dst;
1447
1448 /* Matched with input string. */
1449 if (strncmp (src, dst, strlen (src)) == 0)
1450 return dst;
1451
1452 return NULL;
1453}
1454
1455/* If src matches dst return dst string, otherwise return NULL */
1456/* This version will return the dst string always if it is
1457 CMD_VARIABLE for '?' key processing */
ajs274a4a42004-12-07 15:39:31 +00001458static const char *
hasso8c328f12004-10-05 21:01:23 +00001459cmd_entry_function_desc (const char *src, const char *dst)
paul718e3742002-12-13 20:15:29 +00001460{
1461 if (CMD_VARARG (dst))
1462 return dst;
1463
1464 if (CMD_RANGE (dst))
1465 {
1466 if (cmd_range_match (dst, src))
1467 return dst;
1468 else
1469 return NULL;
1470 }
1471
paul22e0a9e2003-07-11 17:55:46 +00001472#ifdef HAVE_IPV6
paul718e3742002-12-13 20:15:29 +00001473 if (CMD_IPV6 (dst))
1474 {
1475 if (cmd_ipv6_match (src))
1476 return dst;
1477 else
1478 return NULL;
1479 }
1480
1481 if (CMD_IPV6_PREFIX (dst))
1482 {
1483 if (cmd_ipv6_prefix_match (src))
1484 return dst;
1485 else
1486 return NULL;
1487 }
paul22e0a9e2003-07-11 17:55:46 +00001488#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +00001489
1490 if (CMD_IPV4 (dst))
1491 {
1492 if (cmd_ipv4_match (src))
1493 return dst;
1494 else
1495 return NULL;
1496 }
1497
1498 if (CMD_IPV4_PREFIX (dst))
1499 {
1500 if (cmd_ipv4_prefix_match (src))
1501 return dst;
1502 else
1503 return NULL;
1504 }
1505
1506 /* Optional or variable commands always match on '?' */
1507 if (CMD_OPTION (dst) || CMD_VARIABLE (dst))
1508 return dst;
1509
1510 /* In case of 'command \t', given src is NULL string. */
1511 if (src == NULL)
1512 return dst;
1513
1514 if (strncmp (src, dst, strlen (src)) == 0)
1515 return dst;
1516 else
1517 return NULL;
1518}
1519
1520/* Check same string element existence. If it isn't there return
1521 1. */
ajs274a4a42004-12-07 15:39:31 +00001522static int
hasso8c328f12004-10-05 21:01:23 +00001523cmd_unique_string (vector v, const char *str)
paul718e3742002-12-13 20:15:29 +00001524{
hasso8c328f12004-10-05 21:01:23 +00001525 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001526 char *match;
1527
paul55468c82005-03-14 20:19:01 +00001528 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001529 if ((match = vector_slot (v, i)) != NULL)
1530 if (strcmp (match, str) == 0)
1531 return 0;
1532 return 1;
1533}
1534
1535/* Compare string to description vector. If there is same string
1536 return 1 else return 0. */
ajs274a4a42004-12-07 15:39:31 +00001537static int
hasso8c328f12004-10-05 21:01:23 +00001538desc_unique_string (vector v, const char *str)
paul718e3742002-12-13 20:15:29 +00001539{
hasso8c328f12004-10-05 21:01:23 +00001540 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001541 struct desc *desc;
1542
paul55468c82005-03-14 20:19:01 +00001543 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001544 if ((desc = vector_slot (v, i)) != NULL)
1545 if (strcmp (desc->cmd, str) == 0)
1546 return 1;
1547 return 0;
1548}
1549
ajs274a4a42004-12-07 15:39:31 +00001550static int
paulb92938a2002-12-13 21:20:42 +00001551cmd_try_do_shortcut (enum node_type node, char* first_word) {
1552 if ( first_word != NULL &&
1553 node != AUTH_NODE &&
1554 node != VIEW_NODE &&
1555 node != AUTH_ENABLE_NODE &&
1556 node != ENABLE_NODE &&
1557 0 == strcmp( "do", first_word ) )
1558 return 1;
1559 return 0;
1560}
1561
paul718e3742002-12-13 20:15:29 +00001562/* '?' describe command support. */
ajs274a4a42004-12-07 15:39:31 +00001563static vector
paulb92938a2002-12-13 21:20:42 +00001564cmd_describe_command_real (vector vline, struct vty *vty, int *status)
paul718e3742002-12-13 20:15:29 +00001565{
paulb8961472005-03-14 17:35:52 +00001566 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001567 vector cmd_vector;
1568#define INIT_MATCHVEC_SIZE 10
1569 vector matchvec;
1570 struct cmd_element *cmd_element;
paulb8961472005-03-14 17:35:52 +00001571 unsigned int index;
paul54aba542003-08-21 20:28:24 +00001572 int ret;
1573 enum match_type match;
1574 char *command;
paul718e3742002-12-13 20:15:29 +00001575 static struct desc desc_cr = { "<cr>", "" };
1576
1577 /* Set index. */
paul55468c82005-03-14 20:19:01 +00001578 if (vector_active (vline) == 0)
paulb8961472005-03-14 17:35:52 +00001579 {
1580 *status = CMD_ERR_NO_MATCH;
1581 return NULL;
1582 }
1583 else
paul55468c82005-03-14 20:19:01 +00001584 index = vector_active (vline) - 1;
paul909a2152005-03-14 17:41:45 +00001585
paul718e3742002-12-13 20:15:29 +00001586 /* Make copy vector of current node's command vector. */
1587 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1588
1589 /* Prepare match vector */
1590 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1591
1592 /* Filter commands. */
paul54aba542003-08-21 20:28:24 +00001593 /* Only words precedes current word will be checked in this loop. */
paul718e3742002-12-13 20:15:29 +00001594 for (i = 0; i < index; i++)
paulb8961472005-03-14 17:35:52 +00001595 if ((command = vector_slot (vline, i)))
paul909a2152005-03-14 17:41:45 +00001596 {
1597 match = cmd_filter_by_completion (command, cmd_vector, i);
1598
1599 if (match == vararg_match)
1600 {
1601 struct cmd_element *cmd_element;
1602 vector descvec;
1603 unsigned int j, k;
paul718e3742002-12-13 20:15:29 +00001604
paul55468c82005-03-14 20:19:01 +00001605 for (j = 0; j < vector_active (cmd_vector); j++)
paulb8961472005-03-14 17:35:52 +00001606 if ((cmd_element = vector_slot (cmd_vector, j)) != NULL
paul55468c82005-03-14 20:19:01 +00001607 && (vector_active (cmd_element->strvec)))
paul909a2152005-03-14 17:41:45 +00001608 {
1609 descvec = vector_slot (cmd_element->strvec,
paul55468c82005-03-14 20:19:01 +00001610 vector_active (cmd_element->strvec) - 1);
1611 for (k = 0; k < vector_active (descvec); k++)
paul909a2152005-03-14 17:41:45 +00001612 {
1613 struct desc *desc = vector_slot (descvec, k);
1614 vector_set (matchvec, desc);
1615 }
1616 }
1617
1618 vector_set (matchvec, &desc_cr);
1619 vector_free (cmd_vector);
paul718e3742002-12-13 20:15:29 +00001620
paul909a2152005-03-14 17:41:45 +00001621 return matchvec;
1622 }
paul718e3742002-12-13 20:15:29 +00001623
paul909a2152005-03-14 17:41:45 +00001624 if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
1625 {
1626 vector_free (cmd_vector);
1627 *status = CMD_ERR_AMBIGUOUS;
1628 return NULL;
1629 }
1630 else if (ret == 2)
1631 {
1632 vector_free (cmd_vector);
1633 *status = CMD_ERR_NO_MATCH;
1634 return NULL;
1635 }
1636 }
paul718e3742002-12-13 20:15:29 +00001637
1638 /* Prepare match vector */
1639 /* matchvec = vector_init (INIT_MATCHVEC_SIZE); */
1640
paul54aba542003-08-21 20:28:24 +00001641 /* Make sure that cmd_vector is filtered based on current word */
1642 command = vector_slot (vline, index);
1643 if (command)
1644 match = cmd_filter_by_completion (command, cmd_vector, index);
1645
paul718e3742002-12-13 20:15:29 +00001646 /* Make description vector. */
paul55468c82005-03-14 20:19:01 +00001647 for (i = 0; i < vector_active (cmd_vector); i++)
paul718e3742002-12-13 20:15:29 +00001648 if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
1649 {
hasso8c328f12004-10-05 21:01:23 +00001650 const char *string = NULL;
paul718e3742002-12-13 20:15:29 +00001651 vector strvec = cmd_element->strvec;
1652
paul55468c82005-03-14 20:19:01 +00001653 /* if command is NULL, index may be equal to vector_active */
1654 if (command && index >= vector_active (strvec))
paul718e3742002-12-13 20:15:29 +00001655 vector_slot (cmd_vector, i) = NULL;
1656 else
1657 {
paul54aba542003-08-21 20:28:24 +00001658 /* Check if command is completed. */
paul55468c82005-03-14 20:19:01 +00001659 if (command == NULL && index == vector_active (strvec))
paul718e3742002-12-13 20:15:29 +00001660 {
1661 string = "<cr>";
paul909a2152005-03-14 17:41:45 +00001662 if (!desc_unique_string (matchvec, string))
paul718e3742002-12-13 20:15:29 +00001663 vector_set (matchvec, &desc_cr);
1664 }
1665 else
1666 {
hasso8c328f12004-10-05 21:01:23 +00001667 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001668 vector descvec = vector_slot (strvec, index);
1669 struct desc *desc;
1670
paul55468c82005-03-14 20:19:01 +00001671 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001672 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001673 {
1674 string = cmd_entry_function_desc (command, desc->cmd);
1675 if (string)
1676 {
1677 /* Uniqueness check */
1678 if (!desc_unique_string (matchvec, string))
1679 vector_set (matchvec, desc);
1680 }
1681 }
paul718e3742002-12-13 20:15:29 +00001682 }
1683 }
1684 }
1685 vector_free (cmd_vector);
1686
1687 if (vector_slot (matchvec, 0) == NULL)
1688 {
1689 vector_free (matchvec);
paul909a2152005-03-14 17:41:45 +00001690 *status = CMD_ERR_NO_MATCH;
paul718e3742002-12-13 20:15:29 +00001691 }
1692 else
1693 *status = CMD_SUCCESS;
1694
1695 return matchvec;
1696}
1697
paulb92938a2002-12-13 21:20:42 +00001698vector
1699cmd_describe_command (vector vline, struct vty *vty, int *status)
1700{
1701 vector ret;
1702
1703 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1704 {
1705 enum node_type onode;
1706 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00001707 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00001708
1709 onode = vty->node;
1710 vty->node = ENABLE_NODE;
1711 /* We can try it on enable node, cos' the vty is authenticated */
1712
1713 shifted_vline = vector_init (vector_count(vline));
1714 /* use memcpy? */
paul55468c82005-03-14 20:19:01 +00001715 for (index = 1; index < vector_active (vline); index++)
paulb92938a2002-12-13 21:20:42 +00001716 {
1717 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1718 }
1719
1720 ret = cmd_describe_command_real (shifted_vline, vty, status);
1721
1722 vector_free(shifted_vline);
1723 vty->node = onode;
1724 return ret;
1725 }
1726
1727
1728 return cmd_describe_command_real (vline, vty, status);
1729}
1730
1731
paul718e3742002-12-13 20:15:29 +00001732/* Check LCD of matched command. */
ajs274a4a42004-12-07 15:39:31 +00001733static int
paul718e3742002-12-13 20:15:29 +00001734cmd_lcd (char **matched)
1735{
1736 int i;
1737 int j;
1738 int lcd = -1;
1739 char *s1, *s2;
1740 char c1, c2;
1741
1742 if (matched[0] == NULL || matched[1] == NULL)
1743 return 0;
1744
1745 for (i = 1; matched[i] != NULL; i++)
1746 {
1747 s1 = matched[i - 1];
1748 s2 = matched[i];
1749
1750 for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
1751 if (c1 != c2)
1752 break;
1753
1754 if (lcd < 0)
1755 lcd = j;
1756 else
1757 {
1758 if (lcd > j)
1759 lcd = j;
1760 }
1761 }
1762 return lcd;
1763}
1764
1765/* Command line completion support. */
ajs274a4a42004-12-07 15:39:31 +00001766static char **
paulb92938a2002-12-13 21:20:42 +00001767cmd_complete_command_real (vector vline, struct vty *vty, int *status)
paul718e3742002-12-13 20:15:29 +00001768{
paulb8961472005-03-14 17:35:52 +00001769 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001770 vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1771#define INIT_MATCHVEC_SIZE 10
1772 vector matchvec;
1773 struct cmd_element *cmd_element;
paulb8961472005-03-14 17:35:52 +00001774 unsigned int index;
paul718e3742002-12-13 20:15:29 +00001775 char **match_str;
1776 struct desc *desc;
1777 vector descvec;
1778 char *command;
1779 int lcd;
1780
paul55468c82005-03-14 20:19:01 +00001781 if (vector_active (vline) == 0)
paulb8961472005-03-14 17:35:52 +00001782 {
1783 *status = CMD_ERR_NO_MATCH;
1784 return NULL;
1785 }
1786 else
paul55468c82005-03-14 20:19:01 +00001787 index = vector_active (vline) - 1;
paulb8961472005-03-14 17:35:52 +00001788
paul718e3742002-12-13 20:15:29 +00001789 /* First, filter by preceeding command string */
1790 for (i = 0; i < index; i++)
paulb8961472005-03-14 17:35:52 +00001791 if ((command = vector_slot (vline, i)))
paul909a2152005-03-14 17:41:45 +00001792 {
1793 enum match_type match;
1794 int ret;
paul718e3742002-12-13 20:15:29 +00001795
paul909a2152005-03-14 17:41:45 +00001796 /* First try completion match, if there is exactly match return 1 */
1797 match = cmd_filter_by_completion (command, cmd_vector, i);
paul718e3742002-12-13 20:15:29 +00001798
paul909a2152005-03-14 17:41:45 +00001799 /* If there is exact match then filter ambiguous match else check
1800 ambiguousness. */
1801 if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
1802 {
1803 vector_free (cmd_vector);
1804 *status = CMD_ERR_AMBIGUOUS;
1805 return NULL;
1806 }
1807 /*
1808 else if (ret == 2)
1809 {
1810 vector_free (cmd_vector);
1811 *status = CMD_ERR_NO_MATCH;
1812 return NULL;
1813 }
1814 */
1815 }
1816
paul718e3742002-12-13 20:15:29 +00001817 /* Prepare match vector. */
1818 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1819
1820 /* Now we got into completion */
paul55468c82005-03-14 20:19:01 +00001821 for (i = 0; i < vector_active (cmd_vector); i++)
paulb8961472005-03-14 17:35:52 +00001822 if ((cmd_element = vector_slot (cmd_vector, i)))
paul718e3742002-12-13 20:15:29 +00001823 {
hasso8c328f12004-10-05 21:01:23 +00001824 const char *string;
paul718e3742002-12-13 20:15:29 +00001825 vector strvec = cmd_element->strvec;
paul909a2152005-03-14 17:41:45 +00001826
paul718e3742002-12-13 20:15:29 +00001827 /* Check field length */
paul55468c82005-03-14 20:19:01 +00001828 if (index >= vector_active (strvec))
paul718e3742002-12-13 20:15:29 +00001829 vector_slot (cmd_vector, i) = NULL;
paul909a2152005-03-14 17:41:45 +00001830 else
paul718e3742002-12-13 20:15:29 +00001831 {
hasso8c328f12004-10-05 21:01:23 +00001832 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001833
1834 descvec = vector_slot (strvec, index);
paul55468c82005-03-14 20:19:01 +00001835 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001836 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001837 {
paulb8961472005-03-14 17:35:52 +00001838 if ((string =
1839 cmd_entry_function (vector_slot (vline, index),
paul909a2152005-03-14 17:41:45 +00001840 desc->cmd)))
1841 if (cmd_unique_string (matchvec, string))
1842 vector_set (matchvec, XSTRDUP (MTYPE_TMP, string));
1843 }
paul718e3742002-12-13 20:15:29 +00001844 }
1845 }
1846
1847 /* We don't need cmd_vector any more. */
1848 vector_free (cmd_vector);
1849
1850 /* No matched command */
1851 if (vector_slot (matchvec, 0) == NULL)
1852 {
1853 vector_free (matchvec);
1854
1855 /* In case of 'command \t' pattern. Do you need '?' command at
1856 the end of the line. */
1857 if (vector_slot (vline, index) == '\0')
1858 *status = CMD_ERR_NOTHING_TODO;
1859 else
1860 *status = CMD_ERR_NO_MATCH;
1861 return NULL;
1862 }
1863
1864 /* Only one matched */
1865 if (vector_slot (matchvec, 1) == NULL)
1866 {
1867 match_str = (char **) matchvec->index;
1868 vector_only_wrapper_free (matchvec);
1869 *status = CMD_COMPLETE_FULL_MATCH;
1870 return match_str;
1871 }
1872 /* Make it sure last element is NULL. */
1873 vector_set (matchvec, NULL);
1874
1875 /* Check LCD of matched strings. */
1876 if (vector_slot (vline, index) != NULL)
1877 {
1878 lcd = cmd_lcd ((char **) matchvec->index);
1879
1880 if (lcd)
1881 {
1882 int len = strlen (vector_slot (vline, index));
paul909a2152005-03-14 17:41:45 +00001883
paul718e3742002-12-13 20:15:29 +00001884 if (len < lcd)
1885 {
1886 char *lcdstr;
paul909a2152005-03-14 17:41:45 +00001887
paul718e3742002-12-13 20:15:29 +00001888 lcdstr = XMALLOC (MTYPE_TMP, lcd + 1);
1889 memcpy (lcdstr, matchvec->index[0], lcd);
1890 lcdstr[lcd] = '\0';
1891
1892 /* match_str = (char **) &lcdstr; */
1893
1894 /* Free matchvec. */
paul55468c82005-03-14 20:19:01 +00001895 for (i = 0; i < vector_active (matchvec); i++)
paul718e3742002-12-13 20:15:29 +00001896 {
1897 if (vector_slot (matchvec, i))
1898 XFREE (MTYPE_TMP, vector_slot (matchvec, i));
1899 }
1900 vector_free (matchvec);
1901
paul909a2152005-03-14 17:41:45 +00001902 /* Make new matchvec. */
paul718e3742002-12-13 20:15:29 +00001903 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1904 vector_set (matchvec, lcdstr);
1905 match_str = (char **) matchvec->index;
1906 vector_only_wrapper_free (matchvec);
1907
1908 *status = CMD_COMPLETE_MATCH;
1909 return match_str;
1910 }
1911 }
1912 }
1913
1914 match_str = (char **) matchvec->index;
1915 vector_only_wrapper_free (matchvec);
1916 *status = CMD_COMPLETE_LIST_MATCH;
1917 return match_str;
1918}
1919
paulb92938a2002-12-13 21:20:42 +00001920char **
paul9ab68122003-01-18 01:16:20 +00001921cmd_complete_command (vector vline, struct vty *vty, int *status)
paulb92938a2002-12-13 21:20:42 +00001922{
1923 char **ret;
1924
1925 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1926 {
1927 enum node_type onode;
1928 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00001929 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00001930
1931 onode = vty->node;
1932 vty->node = ENABLE_NODE;
1933 /* We can try it on enable node, cos' the vty is authenticated */
1934
1935 shifted_vline = vector_init (vector_count(vline));
1936 /* use memcpy? */
paul55468c82005-03-14 20:19:01 +00001937 for (index = 1; index < vector_active (vline); index++)
paulb92938a2002-12-13 21:20:42 +00001938 {
1939 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1940 }
1941
1942 ret = cmd_complete_command_real (shifted_vline, vty, status);
1943
1944 vector_free(shifted_vline);
1945 vty->node = onode;
1946 return ret;
1947 }
1948
1949
1950 return cmd_complete_command_real (vline, vty, status);
1951}
1952
1953/* return parent node */
1954/* MUST eventually converge on CONFIG_NODE */
hasso13bfca72005-01-23 21:42:25 +00001955enum node_type
ajs274a4a42004-12-07 15:39:31 +00001956node_parent ( enum node_type node )
paulb92938a2002-12-13 21:20:42 +00001957{
1958 enum node_type ret;
1959
paul9ab68122003-01-18 01:16:20 +00001960 assert (node > CONFIG_NODE);
1961
1962 switch (node)
1963 {
1964 case BGP_VPNV4_NODE:
1965 case BGP_IPV4_NODE:
1966 case BGP_IPV4M_NODE:
1967 case BGP_IPV6_NODE:
1968 ret = BGP_NODE;
1969 break;
1970 case KEYCHAIN_KEY_NODE:
1971 ret = KEYCHAIN_NODE;
1972 break;
1973 default:
1974 ret = CONFIG_NODE;
paulb92938a2002-12-13 21:20:42 +00001975 }
1976
1977 return ret;
1978}
1979
paul718e3742002-12-13 20:15:29 +00001980/* Execute command by argument vline vector. */
ajs274a4a42004-12-07 15:39:31 +00001981static int
paulb8961472005-03-14 17:35:52 +00001982cmd_execute_command_real (vector vline, struct vty *vty,
1983 struct cmd_element **cmd)
paul718e3742002-12-13 20:15:29 +00001984{
hasso8c328f12004-10-05 21:01:23 +00001985 unsigned int i;
1986 unsigned int index;
paul718e3742002-12-13 20:15:29 +00001987 vector cmd_vector;
1988 struct cmd_element *cmd_element;
1989 struct cmd_element *matched_element;
1990 unsigned int matched_count, incomplete_count;
1991 int argc;
paul9035efa2004-10-10 11:56:56 +00001992 const char *argv[CMD_ARGC_MAX];
paul718e3742002-12-13 20:15:29 +00001993 enum match_type match = 0;
1994 int varflag;
1995 char *command;
1996
1997 /* Make copy of command elements. */
1998 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1999
paul55468c82005-03-14 20:19:01 +00002000 for (index = 0; index < vector_active (vline); index++)
paulb8961472005-03-14 17:35:52 +00002001 if ((command = vector_slot (vline, index)))
paul909a2152005-03-14 17:41:45 +00002002 {
2003 int ret;
paul718e3742002-12-13 20:15:29 +00002004
paul909a2152005-03-14 17:41:45 +00002005 match = cmd_filter_by_completion (command, cmd_vector, index);
paul718e3742002-12-13 20:15:29 +00002006
paul909a2152005-03-14 17:41:45 +00002007 if (match == vararg_match)
2008 break;
2009
2010 ret = is_cmd_ambiguous (command, cmd_vector, index, match);
paul718e3742002-12-13 20:15:29 +00002011
paul909a2152005-03-14 17:41:45 +00002012 if (ret == 1)
2013 {
2014 vector_free (cmd_vector);
2015 return CMD_ERR_AMBIGUOUS;
2016 }
2017 else if (ret == 2)
2018 {
2019 vector_free (cmd_vector);
2020 return CMD_ERR_NO_MATCH;
2021 }
2022 }
paul718e3742002-12-13 20:15:29 +00002023
2024 /* Check matched count. */
2025 matched_element = NULL;
2026 matched_count = 0;
2027 incomplete_count = 0;
2028
paul55468c82005-03-14 20:19:01 +00002029 for (i = 0; i < vector_active (cmd_vector); i++)
paulb8961472005-03-14 17:35:52 +00002030 if ((cmd_element = vector_slot (cmd_vector, i)))
paul718e3742002-12-13 20:15:29 +00002031 {
paul718e3742002-12-13 20:15:29 +00002032 if (match == vararg_match || index >= cmd_element->cmdsize)
2033 {
2034 matched_element = cmd_element;
2035#if 0
2036 printf ("DEBUG: %s\n", cmd_element->string);
2037#endif
2038 matched_count++;
2039 }
2040 else
2041 {
2042 incomplete_count++;
2043 }
2044 }
paul909a2152005-03-14 17:41:45 +00002045
paul718e3742002-12-13 20:15:29 +00002046 /* Finish of using cmd_vector. */
2047 vector_free (cmd_vector);
2048
paul909a2152005-03-14 17:41:45 +00002049 /* To execute command, matched_count must be 1. */
2050 if (matched_count == 0)
paul718e3742002-12-13 20:15:29 +00002051 {
2052 if (incomplete_count)
2053 return CMD_ERR_INCOMPLETE;
2054 else
2055 return CMD_ERR_NO_MATCH;
2056 }
2057
paul909a2152005-03-14 17:41:45 +00002058 if (matched_count > 1)
paul718e3742002-12-13 20:15:29 +00002059 return CMD_ERR_AMBIGUOUS;
2060
2061 /* Argument treatment */
2062 varflag = 0;
2063 argc = 0;
2064
paul55468c82005-03-14 20:19:01 +00002065 for (i = 0; i < vector_active (vline); i++)
paul718e3742002-12-13 20:15:29 +00002066 {
2067 if (varflag)
2068 argv[argc++] = vector_slot (vline, i);
2069 else
paul909a2152005-03-14 17:41:45 +00002070 {
paul718e3742002-12-13 20:15:29 +00002071 vector descvec = vector_slot (matched_element->strvec, i);
2072
paul55468c82005-03-14 20:19:01 +00002073 if (vector_active (descvec) == 1)
paul718e3742002-12-13 20:15:29 +00002074 {
2075 struct desc *desc = vector_slot (descvec, 0);
paul718e3742002-12-13 20:15:29 +00002076
hasso8c328f12004-10-05 21:01:23 +00002077 if (CMD_VARARG (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002078 varflag = 1;
2079
hasso8c328f12004-10-05 21:01:23 +00002080 if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002081 argv[argc++] = vector_slot (vline, i);
2082 }
2083 else
2084 argv[argc++] = vector_slot (vline, i);
2085 }
2086
2087 if (argc >= CMD_ARGC_MAX)
2088 return CMD_ERR_EXEED_ARGC_MAX;
2089 }
2090
2091 /* For vtysh execution. */
2092 if (cmd)
2093 *cmd = matched_element;
2094
2095 if (matched_element->daemon)
2096 return CMD_SUCCESS_DAEMON;
2097
2098 /* Execute matched command. */
2099 return (*matched_element->func) (matched_element, vty, argc, argv);
2100}
2101
paulb92938a2002-12-13 21:20:42 +00002102int
hasso87d683b2005-01-16 23:31:54 +00002103cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,
2104 int vtysh) {
paul9ab68122003-01-18 01:16:20 +00002105 int ret, saved_ret, tried = 0;
2106 enum node_type onode, try_node;
2107
2108 onode = try_node = vty->node;
paulb92938a2002-12-13 21:20:42 +00002109
2110 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
2111 {
2112 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00002113 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00002114
2115 vty->node = ENABLE_NODE;
2116 /* We can try it on enable node, cos' the vty is authenticated */
2117
2118 shifted_vline = vector_init (vector_count(vline));
2119 /* use memcpy? */
paul55468c82005-03-14 20:19:01 +00002120 for (index = 1; index < vector_active (vline); index++)
paulb92938a2002-12-13 21:20:42 +00002121 {
2122 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
2123 }
2124
2125 ret = cmd_execute_command_real (shifted_vline, vty, cmd);
2126
2127 vector_free(shifted_vline);
2128 vty->node = onode;
2129 return ret;
2130 }
2131
2132
paul9ab68122003-01-18 01:16:20 +00002133 saved_ret = ret = cmd_execute_command_real (vline, vty, cmd);
paulb92938a2002-12-13 21:20:42 +00002134
hasso87d683b2005-01-16 23:31:54 +00002135 if (vtysh)
2136 return saved_ret;
2137
paulb92938a2002-12-13 21:20:42 +00002138 /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
paul9ab68122003-01-18 01:16:20 +00002139 while ( ret != CMD_SUCCESS && ret != CMD_WARNING
paulb92938a2002-12-13 21:20:42 +00002140 && vty->node > CONFIG_NODE )
2141 {
paul9ab68122003-01-18 01:16:20 +00002142 try_node = node_parent(try_node);
2143 vty->node = try_node;
paulb92938a2002-12-13 21:20:42 +00002144 ret = cmd_execute_command_real (vline, vty, cmd);
paul9ab68122003-01-18 01:16:20 +00002145 tried = 1;
2146 if (ret == CMD_SUCCESS || ret == CMD_WARNING)
paulb92938a2002-12-13 21:20:42 +00002147 {
paul9ab68122003-01-18 01:16:20 +00002148 /* succesfull command, leave the node as is */
paulb92938a2002-12-13 21:20:42 +00002149 return ret;
2150 }
paulb92938a2002-12-13 21:20:42 +00002151 }
paul9ab68122003-01-18 01:16:20 +00002152 /* no command succeeded, reset the vty to the original node and
2153 return the error for this node */
2154 if ( tried )
2155 vty->node = onode;
2156 return saved_ret;
pauleda031f2003-01-18 00:39:19 +00002157}
2158
paul718e3742002-12-13 20:15:29 +00002159/* Execute command by argument readline. */
2160int
paul909a2152005-03-14 17:41:45 +00002161cmd_execute_command_strict (vector vline, struct vty *vty,
paul718e3742002-12-13 20:15:29 +00002162 struct cmd_element **cmd)
2163{
hasso8c328f12004-10-05 21:01:23 +00002164 unsigned int i;
2165 unsigned int index;
paul718e3742002-12-13 20:15:29 +00002166 vector cmd_vector;
2167 struct cmd_element *cmd_element;
2168 struct cmd_element *matched_element;
2169 unsigned int matched_count, incomplete_count;
2170 int argc;
paul9035efa2004-10-10 11:56:56 +00002171 const char *argv[CMD_ARGC_MAX];
paul718e3742002-12-13 20:15:29 +00002172 int varflag;
2173 enum match_type match = 0;
2174 char *command;
2175
2176 /* Make copy of command element */
2177 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2178
paul55468c82005-03-14 20:19:01 +00002179 for (index = 0; index < vector_active (vline); index++)
paulb8961472005-03-14 17:35:52 +00002180 if ((command = vector_slot (vline, index)))
paul909a2152005-03-14 17:41:45 +00002181 {
2182 int ret;
2183
2184 match = cmd_filter_by_string (vector_slot (vline, index),
2185 cmd_vector, index);
paul718e3742002-12-13 20:15:29 +00002186
paul909a2152005-03-14 17:41:45 +00002187 /* If command meets '.VARARG' then finish matching. */
2188 if (match == vararg_match)
2189 break;
2190
2191 ret = is_cmd_ambiguous (command, cmd_vector, index, match);
2192 if (ret == 1)
2193 {
2194 vector_free (cmd_vector);
2195 return CMD_ERR_AMBIGUOUS;
2196 }
2197 if (ret == 2)
2198 {
2199 vector_free (cmd_vector);
2200 return CMD_ERR_NO_MATCH;
2201 }
2202 }
paul718e3742002-12-13 20:15:29 +00002203
2204 /* Check matched count. */
2205 matched_element = NULL;
2206 matched_count = 0;
2207 incomplete_count = 0;
paul55468c82005-03-14 20:19:01 +00002208 for (i = 0; i < vector_active (cmd_vector); i++)
paul909a2152005-03-14 17:41:45 +00002209 if (vector_slot (cmd_vector, i) != NULL)
paul718e3742002-12-13 20:15:29 +00002210 {
paul909a2152005-03-14 17:41:45 +00002211 cmd_element = vector_slot (cmd_vector, i);
paul718e3742002-12-13 20:15:29 +00002212
2213 if (match == vararg_match || index >= cmd_element->cmdsize)
2214 {
2215 matched_element = cmd_element;
2216 matched_count++;
2217 }
2218 else
2219 incomplete_count++;
2220 }
paul909a2152005-03-14 17:41:45 +00002221
paul718e3742002-12-13 20:15:29 +00002222 /* Finish of using cmd_vector. */
2223 vector_free (cmd_vector);
2224
paul909a2152005-03-14 17:41:45 +00002225 /* To execute command, matched_count must be 1. */
2226 if (matched_count == 0)
paul718e3742002-12-13 20:15:29 +00002227 {
2228 if (incomplete_count)
2229 return CMD_ERR_INCOMPLETE;
2230 else
2231 return CMD_ERR_NO_MATCH;
2232 }
2233
paul909a2152005-03-14 17:41:45 +00002234 if (matched_count > 1)
paul718e3742002-12-13 20:15:29 +00002235 return CMD_ERR_AMBIGUOUS;
2236
2237 /* Argument treatment */
2238 varflag = 0;
2239 argc = 0;
2240
paul55468c82005-03-14 20:19:01 +00002241 for (i = 0; i < vector_active (vline); i++)
paul718e3742002-12-13 20:15:29 +00002242 {
2243 if (varflag)
2244 argv[argc++] = vector_slot (vline, i);
2245 else
paul909a2152005-03-14 17:41:45 +00002246 {
paul718e3742002-12-13 20:15:29 +00002247 vector descvec = vector_slot (matched_element->strvec, i);
2248
paul55468c82005-03-14 20:19:01 +00002249 if (vector_active (descvec) == 1)
paul718e3742002-12-13 20:15:29 +00002250 {
2251 struct desc *desc = vector_slot (descvec, 0);
paul718e3742002-12-13 20:15:29 +00002252
hasso8c328f12004-10-05 21:01:23 +00002253 if (CMD_VARARG (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002254 varflag = 1;
paul909a2152005-03-14 17:41:45 +00002255
hasso8c328f12004-10-05 21:01:23 +00002256 if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002257 argv[argc++] = vector_slot (vline, i);
2258 }
2259 else
2260 argv[argc++] = vector_slot (vline, i);
2261 }
2262
2263 if (argc >= CMD_ARGC_MAX)
2264 return CMD_ERR_EXEED_ARGC_MAX;
2265 }
2266
2267 /* For vtysh execution. */
2268 if (cmd)
2269 *cmd = matched_element;
2270
2271 if (matched_element->daemon)
2272 return CMD_SUCCESS_DAEMON;
2273
2274 /* Now execute matched command */
2275 return (*matched_element->func) (matched_element, vty, argc, argv);
2276}
2277
2278/* Configration make from file. */
2279int
2280config_from_file (struct vty *vty, FILE *fp)
2281{
2282 int ret;
2283 vector vline;
2284
2285 while (fgets (vty->buf, VTY_BUFSIZ, fp))
2286 {
2287 vline = cmd_make_strvec (vty->buf);
2288
2289 /* In case of comment line */
2290 if (vline == NULL)
2291 continue;
2292 /* Execute configuration command : this is strict match */
2293 ret = cmd_execute_command_strict (vline, vty, NULL);
2294
2295 /* Try again with setting node to CONFIG_NODE */
paulb92938a2002-12-13 21:20:42 +00002296 while (ret != CMD_SUCCESS && ret != CMD_WARNING
hassoddd85ed2004-10-13 08:18:07 +00002297 && ret != CMD_ERR_NOTHING_TODO && vty->node != CONFIG_NODE)
2298 {
paulb92938a2002-12-13 21:20:42 +00002299 vty->node = node_parent(vty->node);
hassoddd85ed2004-10-13 08:18:07 +00002300 ret = cmd_execute_command_strict (vline, vty, NULL);
2301 }
paul9ab68122003-01-18 01:16:20 +00002302
paul718e3742002-12-13 20:15:29 +00002303 cmd_free_strvec (vline);
2304
hassoddd85ed2004-10-13 08:18:07 +00002305 if (ret != CMD_SUCCESS && ret != CMD_WARNING
2306 && ret != CMD_ERR_NOTHING_TODO)
paul718e3742002-12-13 20:15:29 +00002307 return ret;
2308 }
2309 return CMD_SUCCESS;
2310}
2311
2312/* Configration from terminal */
2313DEFUN (config_terminal,
2314 config_terminal_cmd,
2315 "configure terminal",
2316 "Configuration from vty interface\n"
2317 "Configuration terminal\n")
2318{
2319 if (vty_config_lock (vty))
2320 vty->node = CONFIG_NODE;
2321 else
2322 {
2323 vty_out (vty, "VTY configuration is locked by other VTY%s", VTY_NEWLINE);
2324 return CMD_WARNING;
2325 }
2326 return CMD_SUCCESS;
2327}
2328
2329/* Enable command */
2330DEFUN (enable,
2331 config_enable_cmd,
2332 "enable",
2333 "Turn on privileged mode command\n")
2334{
2335 /* If enable password is NULL, change to ENABLE_NODE */
2336 if ((host.enable == NULL && host.enable_encrypt == NULL) ||
2337 vty->type == VTY_SHELL_SERV)
2338 vty->node = ENABLE_NODE;
2339 else
2340 vty->node = AUTH_ENABLE_NODE;
2341
2342 return CMD_SUCCESS;
2343}
2344
2345/* Disable command */
2346DEFUN (disable,
2347 config_disable_cmd,
2348 "disable",
2349 "Turn off privileged mode command\n")
2350{
2351 if (vty->node == ENABLE_NODE)
2352 vty->node = VIEW_NODE;
2353 return CMD_SUCCESS;
2354}
2355
2356/* Down vty node level. */
2357DEFUN (config_exit,
2358 config_exit_cmd,
2359 "exit",
2360 "Exit current mode and down to previous mode\n")
2361{
2362 switch (vty->node)
2363 {
2364 case VIEW_NODE:
2365 case ENABLE_NODE:
2366 if (vty_shell (vty))
2367 exit (0);
2368 else
2369 vty->status = VTY_CLOSE;
2370 break;
2371 case CONFIG_NODE:
2372 vty->node = ENABLE_NODE;
2373 vty_config_unlock (vty);
2374 break;
2375 case INTERFACE_NODE:
2376 case ZEBRA_NODE:
2377 case BGP_NODE:
2378 case RIP_NODE:
2379 case RIPNG_NODE:
2380 case OSPF_NODE:
2381 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00002382 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00002383 case KEYCHAIN_NODE:
2384 case MASC_NODE:
2385 case RMAP_NODE:
2386 case VTY_NODE:
2387 vty->node = CONFIG_NODE;
2388 break;
2389 case BGP_VPNV4_NODE:
2390 case BGP_IPV4_NODE:
2391 case BGP_IPV4M_NODE:
2392 case BGP_IPV6_NODE:
2393 vty->node = BGP_NODE;
2394 break;
2395 case KEYCHAIN_KEY_NODE:
2396 vty->node = KEYCHAIN_NODE;
2397 break;
2398 default:
2399 break;
2400 }
2401 return CMD_SUCCESS;
2402}
2403
2404/* quit is alias of exit. */
2405ALIAS (config_exit,
2406 config_quit_cmd,
2407 "quit",
2408 "Exit current mode and down to previous mode\n")
2409
2410/* End of configuration. */
2411DEFUN (config_end,
2412 config_end_cmd,
2413 "end",
2414 "End current mode and change to enable mode.")
2415{
2416 switch (vty->node)
2417 {
2418 case VIEW_NODE:
2419 case ENABLE_NODE:
2420 /* Nothing to do. */
2421 break;
2422 case CONFIG_NODE:
2423 case INTERFACE_NODE:
2424 case ZEBRA_NODE:
2425 case RIP_NODE:
2426 case RIPNG_NODE:
2427 case BGP_NODE:
2428 case BGP_VPNV4_NODE:
2429 case BGP_IPV4_NODE:
2430 case BGP_IPV4M_NODE:
2431 case BGP_IPV6_NODE:
2432 case RMAP_NODE:
2433 case OSPF_NODE:
2434 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00002435 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00002436 case KEYCHAIN_NODE:
2437 case KEYCHAIN_KEY_NODE:
2438 case MASC_NODE:
2439 case VTY_NODE:
2440 vty_config_unlock (vty);
2441 vty->node = ENABLE_NODE;
2442 break;
2443 default:
2444 break;
2445 }
2446 return CMD_SUCCESS;
2447}
2448
2449/* Show version. */
2450DEFUN (show_version,
2451 show_version_cmd,
2452 "show version",
2453 SHOW_STR
2454 "Displays zebra version\n")
2455{
hasso12f6ea22005-03-07 08:35:39 +00002456 vty_out (vty, "Quagga %s (%s).%s", QUAGGA_VERSION, host.name?host.name:"",
2457 VTY_NEWLINE);
hasso6590f2c2004-10-19 20:40:08 +00002458 vty_out (vty, "%s%s", QUAGGA_COPYRIGHT, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00002459
2460 return CMD_SUCCESS;
2461}
2462
2463/* Help display function for all node. */
2464DEFUN (config_help,
2465 config_help_cmd,
2466 "help",
2467 "Description of the interactive help system\n")
2468{
2469 vty_out (vty,
hasso6590f2c2004-10-19 20:40:08 +00002470 "Quagga VTY provides advanced help feature. When you need help,%s\
paul718e3742002-12-13 20:15:29 +00002471anytime at the command line please press '?'.%s\
2472%s\
2473If nothing matches, the help list will be empty and you must backup%s\
2474 until entering a '?' shows the available options.%s\
2475Two styles of help are provided:%s\
24761. Full help is available when you are ready to enter a%s\
2477command argument (e.g. 'show ?') and describes each possible%s\
2478argument.%s\
24792. Partial help is provided when an abbreviated argument is entered%s\
2480 and you want to know what arguments match the input%s\
2481 (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2482 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2483 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
2484 return CMD_SUCCESS;
2485}
2486
2487/* Help display function for all node. */
2488DEFUN (config_list,
2489 config_list_cmd,
2490 "list",
2491 "Print command list\n")
2492{
hasso8c328f12004-10-05 21:01:23 +00002493 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002494 struct cmd_node *cnode = vector_slot (cmdvec, vty->node);
2495 struct cmd_element *cmd;
2496
paul55468c82005-03-14 20:19:01 +00002497 for (i = 0; i < vector_active (cnode->cmd_vector); i++)
paul4275b1d2005-03-09 13:42:23 +00002498 if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL
2499 && !(cmd->attr == CMD_ATTR_DEPRECATED
2500 || cmd->attr == CMD_ATTR_HIDDEN))
paul718e3742002-12-13 20:15:29 +00002501 vty_out (vty, " %s%s", cmd->string,
2502 VTY_NEWLINE);
2503 return CMD_SUCCESS;
2504}
2505
2506/* Write current configuration into file. */
2507DEFUN (config_write_file,
2508 config_write_file_cmd,
2509 "write file",
2510 "Write running configuration to memory, network, or terminal\n"
2511 "Write to configuration file\n")
2512{
hasso8c328f12004-10-05 21:01:23 +00002513 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002514 int fd;
2515 struct cmd_node *node;
2516 char *config_file;
2517 char *config_file_tmp = NULL;
2518 char *config_file_sav = NULL;
2519 struct vty *file_vty;
2520
2521 /* Check and see if we are operating under vtysh configuration */
2522 if (host.config == NULL)
2523 {
2524 vty_out (vty, "Can't save to configuration file, using vtysh.%s",
2525 VTY_NEWLINE);
2526 return CMD_WARNING;
2527 }
2528
2529 /* Get filename. */
2530 config_file = host.config;
2531
2532 config_file_sav = malloc (strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
2533 strcpy (config_file_sav, config_file);
2534 strcat (config_file_sav, CONF_BACKUP_EXT);
2535
2536
2537 config_file_tmp = malloc (strlen (config_file) + 8);
2538 sprintf (config_file_tmp, "%s.XXXXXX", config_file);
2539
2540 /* Open file to configuration write. */
2541 fd = mkstemp (config_file_tmp);
2542 if (fd < 0)
2543 {
2544 vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
2545 VTY_NEWLINE);
2546 free (config_file_tmp);
2547 free (config_file_sav);
2548 return CMD_WARNING;
2549 }
2550
2551 /* Make vty for configuration file. */
2552 file_vty = vty_new ();
2553 file_vty->fd = fd;
2554 file_vty->type = VTY_FILE;
2555
2556 /* Config file header print. */
2557 vty_out (file_vty, "!\n! Zebra configuration saved from vty\n! ");
2558 vty_time_print (file_vty, 1);
2559 vty_out (file_vty, "!\n");
2560
paul55468c82005-03-14 20:19:01 +00002561 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +00002562 if ((node = vector_slot (cmdvec, i)) && node->func)
2563 {
2564 if ((*node->func) (file_vty))
2565 vty_out (file_vty, "!\n");
2566 }
2567 vty_close (file_vty);
2568
2569 if (unlink (config_file_sav) != 0)
2570 if (errno != ENOENT)
2571 {
2572 vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
2573 VTY_NEWLINE);
2574 free (config_file_sav);
2575 free (config_file_tmp);
2576 unlink (config_file_tmp);
2577 return CMD_WARNING;
2578 }
2579 if (link (config_file, config_file_sav) != 0)
2580 {
2581 vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
2582 VTY_NEWLINE);
2583 free (config_file_sav);
2584 free (config_file_tmp);
2585 unlink (config_file_tmp);
2586 return CMD_WARNING;
2587 }
2588 sync ();
2589 if (unlink (config_file) != 0)
2590 {
2591 vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
2592 VTY_NEWLINE);
2593 free (config_file_sav);
2594 free (config_file_tmp);
2595 unlink (config_file_tmp);
2596 return CMD_WARNING;
2597 }
2598 if (link (config_file_tmp, config_file) != 0)
2599 {
2600 vty_out (vty, "Can't save configuration file %s.%s", config_file,
2601 VTY_NEWLINE);
2602 free (config_file_sav);
2603 free (config_file_tmp);
2604 unlink (config_file_tmp);
2605 return CMD_WARNING;
2606 }
2607 unlink (config_file_tmp);
2608 sync ();
2609
2610 free (config_file_sav);
2611 free (config_file_tmp);
gdtaa593d52003-12-22 20:15:53 +00002612
2613 if (chmod (config_file, CONFIGFILE_MASK) != 0)
2614 {
2615 vty_out (vty, "Can't chmod configuration file %s: %s (%d).%s",
ajs6099b3b2004-11-20 02:06:59 +00002616 config_file, safe_strerror(errno), errno, VTY_NEWLINE);
gdtaa593d52003-12-22 20:15:53 +00002617 return CMD_WARNING;
2618 }
2619
paul718e3742002-12-13 20:15:29 +00002620 vty_out (vty, "Configuration saved to %s%s", config_file,
2621 VTY_NEWLINE);
2622 return CMD_SUCCESS;
2623}
2624
2625ALIAS (config_write_file,
2626 config_write_cmd,
2627 "write",
2628 "Write running configuration to memory, network, or terminal\n")
2629
2630ALIAS (config_write_file,
2631 config_write_memory_cmd,
2632 "write memory",
2633 "Write running configuration to memory, network, or terminal\n"
2634 "Write configuration to the file (same as write file)\n")
2635
2636ALIAS (config_write_file,
2637 copy_runningconfig_startupconfig_cmd,
2638 "copy running-config startup-config",
2639 "Copy configuration\n"
2640 "Copy running config to... \n"
2641 "Copy running config to startup config (same as write file)\n")
2642
2643/* Write current configuration into the terminal. */
2644DEFUN (config_write_terminal,
2645 config_write_terminal_cmd,
2646 "write terminal",
2647 "Write running configuration to memory, network, or terminal\n"
2648 "Write to terminal\n")
2649{
hasso8c328f12004-10-05 21:01:23 +00002650 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002651 struct cmd_node *node;
2652
2653 if (vty->type == VTY_SHELL_SERV)
2654 {
paul55468c82005-03-14 20:19:01 +00002655 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +00002656 if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
2657 {
2658 if ((*node->func) (vty))
2659 vty_out (vty, "!%s", VTY_NEWLINE);
2660 }
2661 }
2662 else
2663 {
2664 vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
2665 VTY_NEWLINE);
2666 vty_out (vty, "!%s", VTY_NEWLINE);
2667
paul55468c82005-03-14 20:19:01 +00002668 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +00002669 if ((node = vector_slot (cmdvec, i)) && node->func)
2670 {
2671 if ((*node->func) (vty))
2672 vty_out (vty, "!%s", VTY_NEWLINE);
2673 }
2674 vty_out (vty, "end%s",VTY_NEWLINE);
2675 }
2676 return CMD_SUCCESS;
2677}
2678
2679/* Write current configuration into the terminal. */
2680ALIAS (config_write_terminal,
2681 show_running_config_cmd,
2682 "show running-config",
2683 SHOW_STR
2684 "running configuration\n")
2685
2686/* Write startup configuration into the terminal. */
2687DEFUN (show_startup_config,
2688 show_startup_config_cmd,
2689 "show startup-config",
2690 SHOW_STR
2691 "Contentes of startup configuration\n")
2692{
2693 char buf[BUFSIZ];
2694 FILE *confp;
2695
2696 confp = fopen (host.config, "r");
2697 if (confp == NULL)
2698 {
2699 vty_out (vty, "Can't open configuration file [%s]%s",
2700 host.config, VTY_NEWLINE);
2701 return CMD_WARNING;
2702 }
2703
2704 while (fgets (buf, BUFSIZ, confp))
2705 {
2706 char *cp = buf;
2707
2708 while (*cp != '\r' && *cp != '\n' && *cp != '\0')
2709 cp++;
2710 *cp = '\0';
2711
2712 vty_out (vty, "%s%s", buf, VTY_NEWLINE);
2713 }
2714
2715 fclose (confp);
2716
2717 return CMD_SUCCESS;
2718}
2719
2720/* Hostname configuration */
2721DEFUN (config_hostname,
2722 hostname_cmd,
2723 "hostname WORD",
2724 "Set system's network name\n"
2725 "This system's network name\n")
2726{
2727 if (!isalpha((int) *argv[0]))
2728 {
2729 vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
2730 return CMD_WARNING;
2731 }
2732
2733 if (host.name)
2734 XFREE (0, host.name);
2735
2736 host.name = strdup (argv[0]);
2737 return CMD_SUCCESS;
2738}
2739
2740DEFUN (config_no_hostname,
2741 no_hostname_cmd,
2742 "no hostname [HOSTNAME]",
2743 NO_STR
2744 "Reset system's network name\n"
2745 "Host name of this router\n")
2746{
2747 if (host.name)
2748 XFREE (0, host.name);
2749 host.name = NULL;
2750 return CMD_SUCCESS;
2751}
2752
2753/* VTY interface password set. */
2754DEFUN (config_password, password_cmd,
2755 "password (8|) WORD",
2756 "Assign the terminal connection password\n"
2757 "Specifies a HIDDEN password will follow\n"
2758 "dummy string \n"
2759 "The HIDDEN line password string\n")
2760{
2761 /* Argument check. */
2762 if (argc == 0)
2763 {
2764 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2765 return CMD_WARNING;
2766 }
2767
2768 if (argc == 2)
2769 {
2770 if (*argv[0] == '8')
2771 {
2772 if (host.password)
2773 XFREE (0, host.password);
2774 host.password = NULL;
2775 if (host.password_encrypt)
2776 XFREE (0, host.password_encrypt);
2777 host.password_encrypt = XSTRDUP (0, strdup (argv[1]));
2778 return CMD_SUCCESS;
2779 }
2780 else
2781 {
2782 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2783 return CMD_WARNING;
2784 }
2785 }
2786
2787 if (!isalnum ((int) *argv[0]))
2788 {
2789 vty_out (vty,
2790 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2791 return CMD_WARNING;
2792 }
2793
2794 if (host.password)
2795 XFREE (0, host.password);
2796 host.password = NULL;
2797
2798 if (host.encrypt)
2799 {
2800 if (host.password_encrypt)
2801 XFREE (0, host.password_encrypt);
2802 host.password_encrypt = XSTRDUP (0, zencrypt (argv[0]));
2803 }
2804 else
2805 host.password = XSTRDUP (0, argv[0]);
2806
2807 return CMD_SUCCESS;
2808}
2809
2810ALIAS (config_password, password_text_cmd,
2811 "password LINE",
2812 "Assign the terminal connection password\n"
2813 "The UNENCRYPTED (cleartext) line password\n")
2814
2815/* VTY enable password set. */
2816DEFUN (config_enable_password, enable_password_cmd,
2817 "enable password (8|) WORD",
2818 "Modify enable password parameters\n"
2819 "Assign the privileged level password\n"
2820 "Specifies a HIDDEN password will follow\n"
2821 "dummy string \n"
2822 "The HIDDEN 'enable' password string\n")
2823{
2824 /* Argument check. */
2825 if (argc == 0)
2826 {
2827 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2828 return CMD_WARNING;
2829 }
2830
2831 /* Crypt type is specified. */
2832 if (argc == 2)
2833 {
2834 if (*argv[0] == '8')
2835 {
2836 if (host.enable)
2837 XFREE (0, host.enable);
2838 host.enable = NULL;
2839
2840 if (host.enable_encrypt)
2841 XFREE (0, host.enable_encrypt);
2842 host.enable_encrypt = XSTRDUP (0, argv[1]);
2843
2844 return CMD_SUCCESS;
2845 }
2846 else
2847 {
2848 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2849 return CMD_WARNING;
2850 }
2851 }
2852
2853 if (!isalnum ((int) *argv[0]))
2854 {
2855 vty_out (vty,
2856 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2857 return CMD_WARNING;
2858 }
2859
2860 if (host.enable)
2861 XFREE (0, host.enable);
2862 host.enable = NULL;
2863
2864 /* Plain password input. */
2865 if (host.encrypt)
2866 {
2867 if (host.enable_encrypt)
2868 XFREE (0, host.enable_encrypt);
2869 host.enable_encrypt = XSTRDUP (0, zencrypt (argv[0]));
2870 }
2871 else
2872 host.enable = XSTRDUP (0, argv[0]);
2873
2874 return CMD_SUCCESS;
2875}
2876
2877ALIAS (config_enable_password,
2878 enable_password_text_cmd,
2879 "enable password LINE",
2880 "Modify enable password parameters\n"
2881 "Assign the privileged level password\n"
2882 "The UNENCRYPTED (cleartext) 'enable' password\n")
2883
2884/* VTY enable password delete. */
2885DEFUN (no_config_enable_password, no_enable_password_cmd,
2886 "no enable password",
2887 NO_STR
2888 "Modify enable password parameters\n"
2889 "Assign the privileged level password\n")
2890{
2891 if (host.enable)
2892 XFREE (0, host.enable);
2893 host.enable = NULL;
2894
2895 if (host.enable_encrypt)
2896 XFREE (0, host.enable_encrypt);
2897 host.enable_encrypt = NULL;
2898
2899 return CMD_SUCCESS;
2900}
2901
2902DEFUN (service_password_encrypt,
2903 service_password_encrypt_cmd,
2904 "service password-encryption",
2905 "Set up miscellaneous service\n"
2906 "Enable encrypted passwords\n")
2907{
2908 if (host.encrypt)
2909 return CMD_SUCCESS;
2910
2911 host.encrypt = 1;
2912
2913 if (host.password)
2914 {
2915 if (host.password_encrypt)
2916 XFREE (0, host.password_encrypt);
2917 host.password_encrypt = XSTRDUP (0, zencrypt (host.password));
2918 }
2919 if (host.enable)
2920 {
2921 if (host.enable_encrypt)
2922 XFREE (0, host.enable_encrypt);
2923 host.enable_encrypt = XSTRDUP (0, zencrypt (host.enable));
2924 }
2925
2926 return CMD_SUCCESS;
2927}
2928
2929DEFUN (no_service_password_encrypt,
2930 no_service_password_encrypt_cmd,
2931 "no service password-encryption",
2932 NO_STR
2933 "Set up miscellaneous service\n"
2934 "Enable encrypted passwords\n")
2935{
2936 if (! host.encrypt)
2937 return CMD_SUCCESS;
2938
2939 host.encrypt = 0;
2940
2941 if (host.password_encrypt)
2942 XFREE (0, host.password_encrypt);
2943 host.password_encrypt = NULL;
2944
2945 if (host.enable_encrypt)
2946 XFREE (0, host.enable_encrypt);
2947 host.enable_encrypt = NULL;
2948
2949 return CMD_SUCCESS;
2950}
2951
2952DEFUN (config_terminal_length, config_terminal_length_cmd,
2953 "terminal length <0-512>",
2954 "Set terminal line parameters\n"
2955 "Set number of lines on a screen\n"
2956 "Number of lines on screen (0 for no pausing)\n")
2957{
2958 int lines;
2959 char *endptr = NULL;
2960
2961 lines = strtol (argv[0], &endptr, 10);
2962 if (lines < 0 || lines > 512 || *endptr != '\0')
2963 {
2964 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2965 return CMD_WARNING;
2966 }
2967 vty->lines = lines;
2968
2969 return CMD_SUCCESS;
2970}
2971
2972DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
2973 "terminal no length",
2974 "Set terminal line parameters\n"
2975 NO_STR
2976 "Set number of lines on a screen\n")
2977{
2978 vty->lines = -1;
2979 return CMD_SUCCESS;
2980}
2981
2982DEFUN (service_terminal_length, service_terminal_length_cmd,
2983 "service terminal-length <0-512>",
2984 "Set up miscellaneous service\n"
2985 "System wide terminal length configuration\n"
2986 "Number of lines of VTY (0 means no line control)\n")
2987{
2988 int lines;
2989 char *endptr = NULL;
2990
2991 lines = strtol (argv[0], &endptr, 10);
2992 if (lines < 0 || lines > 512 || *endptr != '\0')
2993 {
2994 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2995 return CMD_WARNING;
2996 }
2997 host.lines = lines;
2998
2999 return CMD_SUCCESS;
3000}
3001
3002DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
3003 "no service terminal-length [<0-512>]",
3004 NO_STR
3005 "Set up miscellaneous service\n"
3006 "System wide terminal length configuration\n"
3007 "Number of lines of VTY (0 means no line control)\n")
3008{
3009 host.lines = -1;
3010 return CMD_SUCCESS;
3011}
3012
ajs2885f722004-12-17 23:16:33 +00003013DEFUN_HIDDEN (do_echo,
3014 echo_cmd,
3015 "echo .MESSAGE",
3016 "Echo a message back to the vty\n"
3017 "The message to echo\n")
3018{
3019 char *message;
3020
ajsf6834d42005-01-28 20:28:35 +00003021 vty_out (vty, "%s%s", ((message = argv_concat(argv, argc, 0)) ? message : ""),
3022 VTY_NEWLINE);
3023 if (message)
3024 XFREE(MTYPE_TMP, message);
ajs2885f722004-12-17 23:16:33 +00003025 return CMD_SUCCESS;
3026}
3027
ajs274a4a42004-12-07 15:39:31 +00003028DEFUN (config_logmsg,
3029 config_logmsg_cmd,
3030 "logmsg "LOG_LEVELS" .MESSAGE",
3031 "Send a message to enabled logging destinations\n"
3032 LOG_LEVEL_DESC
3033 "The message to send\n")
3034{
3035 int level;
3036 char *message;
3037
3038 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3039 return CMD_ERR_NO_MATCH;
3040
ajsf6834d42005-01-28 20:28:35 +00003041 zlog(NULL, level, ((message = argv_concat(argv, argc, 1)) ? message : ""));
3042 if (message)
3043 XFREE(MTYPE_TMP, message);
ajs274a4a42004-12-07 15:39:31 +00003044 return CMD_SUCCESS;
3045}
3046
3047DEFUN (show_logging,
3048 show_logging_cmd,
3049 "show logging",
3050 SHOW_STR
3051 "Show current logging configuration\n")
3052{
3053 struct zlog *zl = zlog_default;
3054
3055 vty_out (vty, "Syslog logging: ");
3056 if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED)
3057 vty_out (vty, "disabled");
3058 else
3059 vty_out (vty, "level %s, facility %s, ident %s",
3060 zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]],
3061 facility_name(zl->facility), zl->ident);
3062 vty_out (vty, "%s", VTY_NEWLINE);
3063
3064 vty_out (vty, "Stdout logging: ");
3065 if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED)
3066 vty_out (vty, "disabled");
3067 else
3068 vty_out (vty, "level %s",
3069 zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
3070 vty_out (vty, "%s", VTY_NEWLINE);
3071
3072 vty_out (vty, "Monitor logging: ");
3073 if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
3074 vty_out (vty, "disabled");
3075 else
3076 vty_out (vty, "level %s",
3077 zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
3078 vty_out (vty, "%s", VTY_NEWLINE);
3079
3080 vty_out (vty, "File logging: ");
3081 if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) ||
3082 !zl->fp)
3083 vty_out (vty, "disabled");
3084 else
3085 vty_out (vty, "level %s, filename %s",
3086 zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
3087 zl->filename);
3088 vty_out (vty, "%s", VTY_NEWLINE);
3089
3090 vty_out (vty, "Protocol name: %s%s",
3091 zlog_proto_names[zl->protocol], VTY_NEWLINE);
3092 vty_out (vty, "Record priority: %s%s",
3093 (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE);
3094
3095 return CMD_SUCCESS;
3096}
3097
paul718e3742002-12-13 20:15:29 +00003098DEFUN (config_log_stdout,
3099 config_log_stdout_cmd,
3100 "log stdout",
3101 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003102 "Set stdout logging level\n")
paul718e3742002-12-13 20:15:29 +00003103{
ajs274a4a42004-12-07 15:39:31 +00003104 zlog_set_level (NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl);
3105 return CMD_SUCCESS;
3106}
3107
3108DEFUN (config_log_stdout_level,
3109 config_log_stdout_level_cmd,
3110 "log stdout "LOG_LEVELS,
3111 "Logging control\n"
3112 "Set stdout logging level\n"
3113 LOG_LEVEL_DESC)
3114{
3115 int level;
3116
3117 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3118 return CMD_ERR_NO_MATCH;
3119 zlog_set_level (NULL, ZLOG_DEST_STDOUT, level);
paul718e3742002-12-13 20:15:29 +00003120 return CMD_SUCCESS;
3121}
3122
3123DEFUN (no_config_log_stdout,
3124 no_config_log_stdout_cmd,
ajs274a4a42004-12-07 15:39:31 +00003125 "no log stdout [LEVEL]",
paul718e3742002-12-13 20:15:29 +00003126 NO_STR
3127 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003128 "Cancel logging to stdout\n"
3129 "Logging level\n")
paul718e3742002-12-13 20:15:29 +00003130{
ajs274a4a42004-12-07 15:39:31 +00003131 zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED);
paul718e3742002-12-13 20:15:29 +00003132 return CMD_SUCCESS;
3133}
3134
ajs274a4a42004-12-07 15:39:31 +00003135DEFUN (config_log_monitor,
3136 config_log_monitor_cmd,
3137 "log monitor",
paul718e3742002-12-13 20:15:29 +00003138 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003139 "Set terminal line (monitor) logging level\n")
3140{
3141 zlog_set_level (NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl);
3142 return CMD_SUCCESS;
3143}
3144
3145DEFUN (config_log_monitor_level,
3146 config_log_monitor_level_cmd,
3147 "log monitor "LOG_LEVELS,
3148 "Logging control\n"
3149 "Set terminal line (monitor) logging level\n"
3150 LOG_LEVEL_DESC)
3151{
3152 int level;
3153
3154 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3155 return CMD_ERR_NO_MATCH;
3156 zlog_set_level (NULL, ZLOG_DEST_MONITOR, level);
3157 return CMD_SUCCESS;
3158}
3159
3160DEFUN (no_config_log_monitor,
3161 no_config_log_monitor_cmd,
3162 "no log monitor [LEVEL]",
3163 NO_STR
3164 "Logging control\n"
3165 "Disable terminal line (monitor) logging\n"
3166 "Logging level\n")
3167{
3168 zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
3169 return CMD_SUCCESS;
3170}
3171
3172static int
3173set_log_file(struct vty *vty, const char *fname, int loglevel)
paul718e3742002-12-13 20:15:29 +00003174{
3175 int ret;
paul9035efa2004-10-10 11:56:56 +00003176 char *p = NULL;
3177 const char *fullpath;
3178
paul718e3742002-12-13 20:15:29 +00003179 /* Path detection. */
ajs274a4a42004-12-07 15:39:31 +00003180 if (! IS_DIRECTORY_SEP (*fname))
paul718e3742002-12-13 20:15:29 +00003181 {
paul9035efa2004-10-10 11:56:56 +00003182 char cwd[MAXPATHLEN+1];
3183 cwd[MAXPATHLEN] = '\0';
3184
3185 if (getcwd (cwd, MAXPATHLEN) == NULL)
3186 {
3187 zlog_err ("config_log_file: Unable to alloc mem!");
3188 return CMD_WARNING;
3189 }
3190
ajs274a4a42004-12-07 15:39:31 +00003191 if ( (p = XMALLOC (MTYPE_TMP, strlen (cwd) + strlen (fname) + 2))
paul9035efa2004-10-10 11:56:56 +00003192 == NULL)
3193 {
3194 zlog_err ("config_log_file: Unable to alloc mem!");
3195 return CMD_WARNING;
3196 }
ajs274a4a42004-12-07 15:39:31 +00003197 sprintf (p, "%s/%s", cwd, fname);
paul9035efa2004-10-10 11:56:56 +00003198 fullpath = p;
paul718e3742002-12-13 20:15:29 +00003199 }
3200 else
ajs274a4a42004-12-07 15:39:31 +00003201 fullpath = fname;
paul718e3742002-12-13 20:15:29 +00003202
ajs274a4a42004-12-07 15:39:31 +00003203 ret = zlog_set_file (NULL, fullpath, loglevel);
paul718e3742002-12-13 20:15:29 +00003204
paul9035efa2004-10-10 11:56:56 +00003205 if (p)
3206 XFREE (MTYPE_TMP, p);
3207
paul718e3742002-12-13 20:15:29 +00003208 if (!ret)
3209 {
ajs274a4a42004-12-07 15:39:31 +00003210 vty_out (vty, "can't open logfile %s\n", fname);
paul718e3742002-12-13 20:15:29 +00003211 return CMD_WARNING;
3212 }
3213
3214 if (host.logfile)
3215 XFREE (MTYPE_TMP, host.logfile);
3216
ajs274a4a42004-12-07 15:39:31 +00003217 host.logfile = XSTRDUP (MTYPE_TMP, fname);
paul718e3742002-12-13 20:15:29 +00003218
3219 return CMD_SUCCESS;
3220}
3221
ajs274a4a42004-12-07 15:39:31 +00003222DEFUN (config_log_file,
3223 config_log_file_cmd,
3224 "log file FILENAME",
3225 "Logging control\n"
3226 "Logging to file\n"
3227 "Logging filename\n")
3228{
3229 return set_log_file(vty, argv[0], zlog_default->default_lvl);
3230}
3231
3232DEFUN (config_log_file_level,
3233 config_log_file_level_cmd,
3234 "log file FILENAME "LOG_LEVELS,
3235 "Logging control\n"
3236 "Logging to file\n"
3237 "Logging filename\n"
3238 LOG_LEVEL_DESC)
3239{
3240 int level;
3241
3242 if ((level = level_match(argv[1])) == ZLOG_DISABLED)
3243 return CMD_ERR_NO_MATCH;
3244 return set_log_file(vty, argv[0], level);
3245}
3246
paul718e3742002-12-13 20:15:29 +00003247DEFUN (no_config_log_file,
3248 no_config_log_file_cmd,
3249 "no log file [FILENAME]",
3250 NO_STR
3251 "Logging control\n"
3252 "Cancel logging to file\n"
3253 "Logging file name\n")
3254{
3255 zlog_reset_file (NULL);
3256
3257 if (host.logfile)
3258 XFREE (MTYPE_TMP, host.logfile);
3259
3260 host.logfile = NULL;
3261
3262 return CMD_SUCCESS;
3263}
3264
ajs274a4a42004-12-07 15:39:31 +00003265ALIAS (no_config_log_file,
3266 no_config_log_file_level_cmd,
3267 "no log file FILENAME LEVEL",
3268 NO_STR
3269 "Logging control\n"
3270 "Cancel logging to file\n"
3271 "Logging file name\n"
3272 "Logging level\n")
3273
paul718e3742002-12-13 20:15:29 +00003274DEFUN (config_log_syslog,
3275 config_log_syslog_cmd,
3276 "log syslog",
3277 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003278 "Set syslog logging level\n")
paul718e3742002-12-13 20:15:29 +00003279{
ajs274a4a42004-12-07 15:39:31 +00003280 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
paul12ab19f2003-07-26 06:14:55 +00003281 return CMD_SUCCESS;
3282}
3283
ajs274a4a42004-12-07 15:39:31 +00003284DEFUN (config_log_syslog_level,
3285 config_log_syslog_level_cmd,
3286 "log syslog "LOG_LEVELS,
paul12ab19f2003-07-26 06:14:55 +00003287 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003288 "Set syslog logging level\n"
3289 LOG_LEVEL_DESC)
paul12ab19f2003-07-26 06:14:55 +00003290{
ajs274a4a42004-12-07 15:39:31 +00003291 int level;
paul12ab19f2003-07-26 06:14:55 +00003292
ajs274a4a42004-12-07 15:39:31 +00003293 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3294 return CMD_ERR_NO_MATCH;
3295 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, level);
3296 return CMD_SUCCESS;
3297}
paul12ab19f2003-07-26 06:14:55 +00003298
ajs274a4a42004-12-07 15:39:31 +00003299DEFUN_DEPRECATED (config_log_syslog_facility,
3300 config_log_syslog_facility_cmd,
3301 "log syslog facility "LOG_FACILITIES,
3302 "Logging control\n"
3303 "Logging goes to syslog\n"
3304 "(Deprecated) Facility parameter for syslog messages\n"
3305 LOG_FACILITY_DESC)
3306{
3307 int facility;
paul12ab19f2003-07-26 06:14:55 +00003308
ajs274a4a42004-12-07 15:39:31 +00003309 if ((facility = facility_match(argv[0])) < 0)
3310 return CMD_ERR_NO_MATCH;
3311
3312 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
paul12ab19f2003-07-26 06:14:55 +00003313 zlog_default->facility = facility;
paul718e3742002-12-13 20:15:29 +00003314 return CMD_SUCCESS;
3315}
3316
3317DEFUN (no_config_log_syslog,
3318 no_config_log_syslog_cmd,
ajs274a4a42004-12-07 15:39:31 +00003319 "no log syslog [LEVEL]",
paul718e3742002-12-13 20:15:29 +00003320 NO_STR
3321 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003322 "Cancel logging to syslog\n"
3323 "Logging level\n")
paul718e3742002-12-13 20:15:29 +00003324{
ajs274a4a42004-12-07 15:39:31 +00003325 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
paul718e3742002-12-13 20:15:29 +00003326 return CMD_SUCCESS;
3327}
3328
paul12ab19f2003-07-26 06:14:55 +00003329ALIAS (no_config_log_syslog,
3330 no_config_log_syslog_facility_cmd,
ajs274a4a42004-12-07 15:39:31 +00003331 "no log syslog facility "LOG_FACILITIES,
paul12ab19f2003-07-26 06:14:55 +00003332 NO_STR
3333 "Logging control\n"
3334 "Logging goes to syslog\n"
3335 "Facility parameter for syslog messages\n"
ajs274a4a42004-12-07 15:39:31 +00003336 LOG_FACILITY_DESC)
paul12ab19f2003-07-26 06:14:55 +00003337
ajs274a4a42004-12-07 15:39:31 +00003338DEFUN (config_log_facility,
3339 config_log_facility_cmd,
3340 "log facility "LOG_FACILITIES,
paul718e3742002-12-13 20:15:29 +00003341 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003342 "Facility parameter for syslog messages\n"
3343 LOG_FACILITY_DESC)
paul718e3742002-12-13 20:15:29 +00003344{
ajs274a4a42004-12-07 15:39:31 +00003345 int facility;
3346
3347 if ((facility = facility_match(argv[0])) < 0)
3348 return CMD_ERR_NO_MATCH;
3349 zlog_default->facility = facility;
3350 return CMD_SUCCESS;
paul718e3742002-12-13 20:15:29 +00003351}
3352
ajs274a4a42004-12-07 15:39:31 +00003353DEFUN (no_config_log_facility,
3354 no_config_log_facility_cmd,
3355 "no log facility [FACILITY]",
paul718e3742002-12-13 20:15:29 +00003356 NO_STR
3357 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003358 "Reset syslog facility to default (daemon)\n"
3359 "Syslog facility\n")
paul718e3742002-12-13 20:15:29 +00003360{
ajs274a4a42004-12-07 15:39:31 +00003361 zlog_default->facility = LOG_DAEMON;
3362 return CMD_SUCCESS;
3363}
3364
3365DEFUN_DEPRECATED (config_log_trap,
3366 config_log_trap_cmd,
3367 "log trap "LOG_LEVELS,
3368 "Logging control\n"
3369 "(Deprecated) Set logging level and default for all destinations\n"
3370 LOG_LEVEL_DESC)
3371{
3372 int new_level ;
3373 int i;
3374
3375 if ((new_level = level_match(argv[0])) == ZLOG_DISABLED)
3376 return CMD_ERR_NO_MATCH;
3377
3378 zlog_default->default_lvl = new_level;
3379 for (i = 0; i < ZLOG_NUM_DESTS; i++)
3380 if (zlog_default->maxlvl[i] != ZLOG_DISABLED)
3381 zlog_default->maxlvl[i] = new_level;
3382 return CMD_SUCCESS;
3383}
3384
3385DEFUN_DEPRECATED (no_config_log_trap,
3386 no_config_log_trap_cmd,
3387 "no log trap [LEVEL]",
3388 NO_STR
3389 "Logging control\n"
3390 "Permit all logging information\n"
3391 "Logging level\n")
3392{
3393 zlog_default->default_lvl = LOG_DEBUG;
paul718e3742002-12-13 20:15:29 +00003394 return CMD_SUCCESS;
3395}
3396
3397DEFUN (config_log_record_priority,
3398 config_log_record_priority_cmd,
3399 "log record-priority",
3400 "Logging control\n"
3401 "Log the priority of the message within the message\n")
3402{
3403 zlog_default->record_priority = 1 ;
3404 return CMD_SUCCESS;
3405}
3406
3407DEFUN (no_config_log_record_priority,
3408 no_config_log_record_priority_cmd,
3409 "no log record-priority",
3410 NO_STR
3411 "Logging control\n"
3412 "Do not log the priority of the message within the message\n")
3413{
3414 zlog_default->record_priority = 0 ;
3415 return CMD_SUCCESS;
3416}
3417
paul3b0c5d92005-03-08 10:43:43 +00003418DEFUN (banner_motd_file,
3419 banner_motd_file_cmd,
3420 "banner motd file [FILE]",
3421 "Set banner\n"
3422 "Banner for motd\n"
3423 "Banner from a file\n"
3424 "Filename\n")
3425{
paulb45da6f2005-03-08 15:16:57 +00003426 if (host.motdfile)
3427 XFREE (MTYPE_TMP, host.motdfile);
3428 host.motdfile = XSTRDUP (MTYPE_TMP, argv[0]);
3429
paul3b0c5d92005-03-08 10:43:43 +00003430 return CMD_SUCCESS;
3431}
paul718e3742002-12-13 20:15:29 +00003432
3433DEFUN (banner_motd_default,
3434 banner_motd_default_cmd,
3435 "banner motd default",
3436 "Set banner string\n"
3437 "Strings for motd\n"
3438 "Default string\n")
3439{
3440 host.motd = default_motd;
3441 return CMD_SUCCESS;
3442}
3443
3444DEFUN (no_banner_motd,
3445 no_banner_motd_cmd,
3446 "no banner motd",
3447 NO_STR
3448 "Set banner string\n"
3449 "Strings for motd\n")
3450{
3451 host.motd = NULL;
paul22085182005-03-08 16:00:12 +00003452 if (host.motdfile)
3453 XFREE (MTYPE_TMP, host.motdfile);
paul3b0c5d92005-03-08 10:43:43 +00003454 host.motdfile = NULL;
paul718e3742002-12-13 20:15:29 +00003455 return CMD_SUCCESS;
3456}
3457
3458/* Set config filename. Called from vty.c */
3459void
3460host_config_set (char *filename)
3461{
3462 host.config = strdup (filename);
3463}
3464
3465void
3466install_default (enum node_type node)
3467{
3468 install_element (node, &config_exit_cmd);
3469 install_element (node, &config_quit_cmd);
3470 install_element (node, &config_end_cmd);
3471 install_element (node, &config_help_cmd);
3472 install_element (node, &config_list_cmd);
3473
3474 install_element (node, &config_write_terminal_cmd);
3475 install_element (node, &config_write_file_cmd);
3476 install_element (node, &config_write_memory_cmd);
3477 install_element (node, &config_write_cmd);
3478 install_element (node, &show_running_config_cmd);
3479}
3480
3481/* Initialize command interface. Install basic nodes and commands. */
3482void
3483cmd_init (int terminal)
3484{
3485 /* Allocate initial top vector of commands. */
3486 cmdvec = vector_init (VECTOR_MIN_SIZE);
3487
3488 /* Default host value settings. */
3489 host.name = NULL;
3490 host.password = NULL;
3491 host.enable = NULL;
3492 host.logfile = NULL;
3493 host.config = NULL;
3494 host.lines = -1;
3495 host.motd = default_motd;
paul3b0c5d92005-03-08 10:43:43 +00003496 host.motdfile = NULL;
paul718e3742002-12-13 20:15:29 +00003497
3498 /* Install top nodes. */
3499 install_node (&view_node, NULL);
3500 install_node (&enable_node, NULL);
3501 install_node (&auth_node, NULL);
3502 install_node (&auth_enable_node, NULL);
3503 install_node (&config_node, config_write_host);
3504
3505 /* Each node's basic commands. */
3506 install_element (VIEW_NODE, &show_version_cmd);
3507 if (terminal)
3508 {
3509 install_element (VIEW_NODE, &config_list_cmd);
3510 install_element (VIEW_NODE, &config_exit_cmd);
3511 install_element (VIEW_NODE, &config_quit_cmd);
3512 install_element (VIEW_NODE, &config_help_cmd);
3513 install_element (VIEW_NODE, &config_enable_cmd);
3514 install_element (VIEW_NODE, &config_terminal_length_cmd);
3515 install_element (VIEW_NODE, &config_terminal_no_length_cmd);
ajs274a4a42004-12-07 15:39:31 +00003516 install_element (VIEW_NODE, &show_logging_cmd);
ajs2885f722004-12-17 23:16:33 +00003517 install_element (VIEW_NODE, &echo_cmd);
paul718e3742002-12-13 20:15:29 +00003518 }
3519
3520 if (terminal)
3521 {
3522 install_default (ENABLE_NODE);
3523 install_element (ENABLE_NODE, &config_disable_cmd);
3524 install_element (ENABLE_NODE, &config_terminal_cmd);
3525 install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
3526 }
3527 install_element (ENABLE_NODE, &show_startup_config_cmd);
3528 install_element (ENABLE_NODE, &show_version_cmd);
paul718e3742002-12-13 20:15:29 +00003529
3530 if (terminal)
paul718e3742002-12-13 20:15:29 +00003531 {
hassoe7168df2004-10-03 20:11:32 +00003532 install_element (ENABLE_NODE, &config_terminal_length_cmd);
3533 install_element (ENABLE_NODE, &config_terminal_no_length_cmd);
ajs274a4a42004-12-07 15:39:31 +00003534 install_element (ENABLE_NODE, &show_logging_cmd);
ajs2885f722004-12-17 23:16:33 +00003535 install_element (ENABLE_NODE, &echo_cmd);
ajs274a4a42004-12-07 15:39:31 +00003536 install_element (ENABLE_NODE, &config_logmsg_cmd);
hassoe7168df2004-10-03 20:11:32 +00003537
3538 install_default (CONFIG_NODE);
hassoea8e9d92004-10-07 21:32:14 +00003539 }
3540
3541 install_element (CONFIG_NODE, &hostname_cmd);
3542 install_element (CONFIG_NODE, &no_hostname_cmd);
hassoe7168df2004-10-03 20:11:32 +00003543
hassoea8e9d92004-10-07 21:32:14 +00003544 if (terminal)
3545 {
hassoe7168df2004-10-03 20:11:32 +00003546 install_element (CONFIG_NODE, &password_cmd);
3547 install_element (CONFIG_NODE, &password_text_cmd);
3548 install_element (CONFIG_NODE, &enable_password_cmd);
3549 install_element (CONFIG_NODE, &enable_password_text_cmd);
3550 install_element (CONFIG_NODE, &no_enable_password_cmd);
3551
paul718e3742002-12-13 20:15:29 +00003552 install_element (CONFIG_NODE, &config_log_stdout_cmd);
ajs274a4a42004-12-07 15:39:31 +00003553 install_element (CONFIG_NODE, &config_log_stdout_level_cmd);
paul718e3742002-12-13 20:15:29 +00003554 install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
ajs274a4a42004-12-07 15:39:31 +00003555 install_element (CONFIG_NODE, &config_log_monitor_cmd);
3556 install_element (CONFIG_NODE, &config_log_monitor_level_cmd);
3557 install_element (CONFIG_NODE, &no_config_log_monitor_cmd);
paul718e3742002-12-13 20:15:29 +00003558 install_element (CONFIG_NODE, &config_log_file_cmd);
ajs274a4a42004-12-07 15:39:31 +00003559 install_element (CONFIG_NODE, &config_log_file_level_cmd);
paul718e3742002-12-13 20:15:29 +00003560 install_element (CONFIG_NODE, &no_config_log_file_cmd);
ajs274a4a42004-12-07 15:39:31 +00003561 install_element (CONFIG_NODE, &no_config_log_file_level_cmd);
paul718e3742002-12-13 20:15:29 +00003562 install_element (CONFIG_NODE, &config_log_syslog_cmd);
ajs274a4a42004-12-07 15:39:31 +00003563 install_element (CONFIG_NODE, &config_log_syslog_level_cmd);
paul12ab19f2003-07-26 06:14:55 +00003564 install_element (CONFIG_NODE, &config_log_syslog_facility_cmd);
paul718e3742002-12-13 20:15:29 +00003565 install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
paul12ab19f2003-07-26 06:14:55 +00003566 install_element (CONFIG_NODE, &no_config_log_syslog_facility_cmd);
ajs274a4a42004-12-07 15:39:31 +00003567 install_element (CONFIG_NODE, &config_log_facility_cmd);
3568 install_element (CONFIG_NODE, &no_config_log_facility_cmd);
paul718e3742002-12-13 20:15:29 +00003569 install_element (CONFIG_NODE, &config_log_trap_cmd);
3570 install_element (CONFIG_NODE, &no_config_log_trap_cmd);
3571 install_element (CONFIG_NODE, &config_log_record_priority_cmd);
3572 install_element (CONFIG_NODE, &no_config_log_record_priority_cmd);
3573 install_element (CONFIG_NODE, &service_password_encrypt_cmd);
3574 install_element (CONFIG_NODE, &no_service_password_encrypt_cmd);
3575 install_element (CONFIG_NODE, &banner_motd_default_cmd);
paul3b0c5d92005-03-08 10:43:43 +00003576 install_element (CONFIG_NODE, &banner_motd_file_cmd);
paul718e3742002-12-13 20:15:29 +00003577 install_element (CONFIG_NODE, &no_banner_motd_cmd);
3578 install_element (CONFIG_NODE, &service_terminal_length_cmd);
3579 install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
paul718e3742002-12-13 20:15:29 +00003580
paul9ab68122003-01-18 01:16:20 +00003581 install_element(VIEW_NODE, &show_thread_cpu_cmd);
3582 install_element(ENABLE_NODE, &show_thread_cpu_cmd);
3583 }
paul718e3742002-12-13 20:15:29 +00003584 srand(time(NULL));
3585}