blob: f64235954cb6929c9c133561c26a5a7dcd7301c6 [file] [log] [blame]
ajs274a4a42004-12-07 15:39:31 +00001/*
paul1e836592005-08-22 22:39:56 +00002 $Id: command.c,v 1.49 2005/08/22 22:39:56 paul Exp $
paul9e92eea2005-03-09 13:39:26 +00003
ajs274a4a42004-12-07 15:39:31 +00004 Command interpreter routine for virtual terminal [aka TeletYpe]
paul718e3742002-12-13 20:15:29 +00005 Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
6
7This file is part of GNU Zebra.
8
9GNU Zebra is free software; you can redistribute it and/or modify
10it under the terms of the GNU General Public License as published
11by the Free Software Foundation; either version 2, or (at your
12option) any later version.
13
14GNU Zebra is distributed in the hope that it will be useful, but
15WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with GNU Zebra; see the file COPYING. If not, write to the
21Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22Boston, MA 02111-1307, USA. */
23
24#include <zebra.h>
25
paulb21b19c2003-06-15 01:28:29 +000026
paul718e3742002-12-13 20:15:29 +000027#include "memory.h"
28#include "log.h"
gdt5e4fa162004-03-16 14:38:36 +000029#include <lib/version.h>
paul9ab68122003-01-18 01:16:20 +000030#include "thread.h"
paulb21b19c2003-06-15 01:28:29 +000031#include "vector.h"
32#include "vty.h"
33#include "command.h"
paul354d1192005-04-25 16:26:42 +000034#include "workqueue.h"
paul718e3742002-12-13 20:15:29 +000035
36/* Command vector which includes some level of command lists. Normally
37 each daemon maintains each own cmdvec. */
38vector cmdvec;
39
40/* Host information structure. */
41struct host host;
42
paul718e3742002-12-13 20:15:29 +000043/* Standard command node structures. */
44struct cmd_node auth_node =
45{
46 AUTH_NODE,
47 "Password: ",
48};
49
50struct cmd_node view_node =
51{
52 VIEW_NODE,
53 "%s> ",
54};
55
56struct cmd_node auth_enable_node =
57{
58 AUTH_ENABLE_NODE,
59 "Password: ",
60};
61
62struct cmd_node enable_node =
63{
64 ENABLE_NODE,
65 "%s# ",
66};
67
68struct cmd_node config_node =
69{
70 CONFIG_NODE,
71 "%s(config)# ",
72 1
73};
hasso6590f2c2004-10-19 20:40:08 +000074
75/* Default motd string. */
76const char *default_motd =
77"\r\n\
78Hello, this is " QUAGGA_PROGNAME " (version " QUAGGA_VERSION ").\r\n\
79" QUAGGA_COPYRIGHT "\r\n\
80\r\n";
81
ajs274a4a42004-12-07 15:39:31 +000082
83static struct facility_map {
84 int facility;
85 const char *name;
86 size_t match;
87} syslog_facilities[] =
88 {
89 { LOG_KERN, "kern", 1 },
90 { LOG_USER, "user", 2 },
91 { LOG_MAIL, "mail", 1 },
92 { LOG_DAEMON, "daemon", 1 },
93 { LOG_AUTH, "auth", 1 },
94 { LOG_SYSLOG, "syslog", 1 },
95 { LOG_LPR, "lpr", 2 },
96 { LOG_NEWS, "news", 1 },
97 { LOG_UUCP, "uucp", 2 },
98 { LOG_CRON, "cron", 1 },
99#ifdef LOG_FTP
100 { LOG_FTP, "ftp", 1 },
101#endif
102 { LOG_LOCAL0, "local0", 6 },
103 { LOG_LOCAL1, "local1", 6 },
104 { LOG_LOCAL2, "local2", 6 },
105 { LOG_LOCAL3, "local3", 6 },
106 { LOG_LOCAL4, "local4", 6 },
107 { LOG_LOCAL5, "local5", 6 },
108 { LOG_LOCAL6, "local6", 6 },
109 { LOG_LOCAL7, "local7", 6 },
110 { 0, NULL, 0 },
111 };
112
113static const char *
114facility_name(int facility)
115{
116 struct facility_map *fm;
117
118 for (fm = syslog_facilities; fm->name; fm++)
119 if (fm->facility == facility)
120 return fm->name;
121 return "";
122}
123
124static int
125facility_match(const char *str)
126{
127 struct facility_map *fm;
128
129 for (fm = syslog_facilities; fm->name; fm++)
130 if (!strncmp(str,fm->name,fm->match))
131 return fm->facility;
132 return -1;
133}
134
135static int
136level_match(const char *s)
137{
138 int level ;
139
140 for ( level = 0 ; zlog_priority [level] != NULL ; level ++ )
141 if (!strncmp (s, zlog_priority[level], 2))
142 return level;
143 return ZLOG_DISABLED;
144}
145
ajscb585b62005-01-14 17:09:38 +0000146/* This is called from main when a daemon is invoked with -v or --version. */
hasso6590f2c2004-10-19 20:40:08 +0000147void
148print_version (const char *progname)
149{
ajscb585b62005-01-14 17:09:38 +0000150 printf ("%s version %s\n", progname, QUAGGA_VERSION);
151 printf ("%s\n", QUAGGA_COPYRIGHT);
hasso6590f2c2004-10-19 20:40:08 +0000152}
153
paul718e3742002-12-13 20:15:29 +0000154
155/* Utility function to concatenate argv argument into a single string
156 with inserting ' ' character between each argument. */
157char *
paul42d49862004-10-13 05:22:18 +0000158argv_concat (const char **argv, int argc, int shift)
paul718e3742002-12-13 20:15:29 +0000159{
160 int i;
ajsf6834d42005-01-28 20:28:35 +0000161 size_t len;
paul718e3742002-12-13 20:15:29 +0000162 char *str;
ajsf6834d42005-01-28 20:28:35 +0000163 char *p;
paul718e3742002-12-13 20:15:29 +0000164
ajsf6834d42005-01-28 20:28:35 +0000165 len = 0;
166 for (i = shift; i < argc; i++)
167 len += strlen(argv[i])+1;
168 if (!len)
169 return NULL;
170 p = str = XMALLOC(MTYPE_TMP, len);
paul718e3742002-12-13 20:15:29 +0000171 for (i = shift; i < argc; i++)
172 {
ajsf6834d42005-01-28 20:28:35 +0000173 size_t arglen;
174 memcpy(p, argv[i], (arglen = strlen(argv[i])));
175 p += arglen;
176 *p++ = ' ';
paul718e3742002-12-13 20:15:29 +0000177 }
ajsf6834d42005-01-28 20:28:35 +0000178 *(p-1) = '\0';
paul718e3742002-12-13 20:15:29 +0000179 return str;
180}
181
182/* Install top node of command vector. */
183void
184install_node (struct cmd_node *node,
185 int (*func) (struct vty *))
186{
187 vector_set_index (cmdvec, node->node, node);
188 node->func = func;
189 node->cmd_vector = vector_init (VECTOR_MIN_SIZE);
190}
191
192/* Compare two command's string. Used in sort_node (). */
ajs274a4a42004-12-07 15:39:31 +0000193static int
paul718e3742002-12-13 20:15:29 +0000194cmp_node (const void *p, const void *q)
195{
paul8cc41982005-05-06 21:25:49 +0000196 const struct cmd_element *a = *(struct cmd_element **)p;
197 const struct cmd_element *b = *(struct cmd_element **)q;
paul718e3742002-12-13 20:15:29 +0000198
199 return strcmp (a->string, b->string);
200}
201
ajs274a4a42004-12-07 15:39:31 +0000202static int
paul718e3742002-12-13 20:15:29 +0000203cmp_desc (const void *p, const void *q)
204{
paul8cc41982005-05-06 21:25:49 +0000205 const struct desc *a = *(struct desc **)p;
206 const struct desc *b = *(struct desc **)q;
paul718e3742002-12-13 20:15:29 +0000207
208 return strcmp (a->cmd, b->cmd);
209}
210
211/* Sort each node's command element according to command string. */
212void
213sort_node ()
214{
hasso8c328f12004-10-05 21:01:23 +0000215 unsigned int i, j;
paul718e3742002-12-13 20:15:29 +0000216 struct cmd_node *cnode;
217 vector descvec;
218 struct cmd_element *cmd_element;
219
paul55468c82005-03-14 20:19:01 +0000220 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +0000221 if ((cnode = vector_slot (cmdvec, i)) != NULL)
222 {
223 vector cmd_vector = cnode->cmd_vector;
paul55468c82005-03-14 20:19:01 +0000224 qsort (cmd_vector->index, vector_active (cmd_vector),
paulb8961472005-03-14 17:35:52 +0000225 sizeof (void *), cmp_node);
paul718e3742002-12-13 20:15:29 +0000226
paul55468c82005-03-14 20:19:01 +0000227 for (j = 0; j < vector_active (cmd_vector); j++)
paulb8961472005-03-14 17:35:52 +0000228 if ((cmd_element = vector_slot (cmd_vector, j)) != NULL
paul55468c82005-03-14 20:19:01 +0000229 && vector_active (cmd_element->strvec))
paul718e3742002-12-13 20:15:29 +0000230 {
231 descvec = vector_slot (cmd_element->strvec,
paul55468c82005-03-14 20:19:01 +0000232 vector_active (cmd_element->strvec) - 1);
233 qsort (descvec->index, vector_active (descvec),
paulb8961472005-03-14 17:35:52 +0000234 sizeof (void *), cmp_desc);
paul718e3742002-12-13 20:15:29 +0000235 }
236 }
237}
238
239/* Breaking up string into each command piece. I assume given
240 character is separated by a space character. Return value is a
241 vector which includes char ** data element. */
242vector
hassoea8e9d92004-10-07 21:32:14 +0000243cmd_make_strvec (const char *string)
paul718e3742002-12-13 20:15:29 +0000244{
hassoea8e9d92004-10-07 21:32:14 +0000245 const char *cp, *start;
246 char *token;
paul718e3742002-12-13 20:15:29 +0000247 int strlen;
248 vector strvec;
249
250 if (string == NULL)
251 return NULL;
252
253 cp = string;
254
255 /* Skip white spaces. */
256 while (isspace ((int) *cp) && *cp != '\0')
257 cp++;
258
259 /* Return if there is only white spaces */
260 if (*cp == '\0')
261 return NULL;
262
263 if (*cp == '!' || *cp == '#')
264 return NULL;
265
266 /* Prepare return vector. */
267 strvec = vector_init (VECTOR_MIN_SIZE);
268
269 /* Copy each command piece and set into vector. */
270 while (1)
271 {
272 start = cp;
273 while (!(isspace ((int) *cp) || *cp == '\r' || *cp == '\n') &&
274 *cp != '\0')
275 cp++;
276 strlen = cp - start;
277 token = XMALLOC (MTYPE_STRVEC, strlen + 1);
278 memcpy (token, start, strlen);
279 *(token + strlen) = '\0';
280 vector_set (strvec, token);
281
282 while ((isspace ((int) *cp) || *cp == '\n' || *cp == '\r') &&
283 *cp != '\0')
284 cp++;
285
286 if (*cp == '\0')
287 return strvec;
288 }
289}
290
291/* Free allocated string vector. */
292void
293cmd_free_strvec (vector v)
294{
hasso8c328f12004-10-05 21:01:23 +0000295 unsigned int i;
paul718e3742002-12-13 20:15:29 +0000296 char *cp;
297
298 if (!v)
299 return;
300
paul55468c82005-03-14 20:19:01 +0000301 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +0000302 if ((cp = vector_slot (v, i)) != NULL)
303 XFREE (MTYPE_STRVEC, cp);
304
305 vector_free (v);
306}
307
308/* Fetch next description. Used in cmd_make_descvec(). */
ajs274a4a42004-12-07 15:39:31 +0000309static char *
hasso6ad96ea2004-10-07 19:33:46 +0000310cmd_desc_str (const char **string)
paul718e3742002-12-13 20:15:29 +0000311{
hasso6ad96ea2004-10-07 19:33:46 +0000312 const char *cp, *start;
313 char *token;
paul718e3742002-12-13 20:15:29 +0000314 int strlen;
315
316 cp = *string;
317
318 if (cp == NULL)
319 return NULL;
320
321 /* Skip white spaces. */
322 while (isspace ((int) *cp) && *cp != '\0')
323 cp++;
324
325 /* Return if there is only white spaces */
326 if (*cp == '\0')
327 return NULL;
328
329 start = cp;
330
331 while (!(*cp == '\r' || *cp == '\n') && *cp != '\0')
332 cp++;
333
334 strlen = cp - start;
335 token = XMALLOC (MTYPE_STRVEC, strlen + 1);
336 memcpy (token, start, strlen);
337 *(token + strlen) = '\0';
338
339 *string = cp;
340
341 return token;
342}
343
344/* New string vector. */
ajs274a4a42004-12-07 15:39:31 +0000345static vector
hasso8c328f12004-10-05 21:01:23 +0000346cmd_make_descvec (const char *string, const char *descstr)
paul718e3742002-12-13 20:15:29 +0000347{
348 int multiple = 0;
hasso8c328f12004-10-05 21:01:23 +0000349 const char *sp;
paul718e3742002-12-13 20:15:29 +0000350 char *token;
351 int len;
hasso8c328f12004-10-05 21:01:23 +0000352 const char *cp;
353 const char *dp;
paul718e3742002-12-13 20:15:29 +0000354 vector allvec;
355 vector strvec = NULL;
356 struct desc *desc;
357
358 cp = string;
359 dp = descstr;
360
361 if (cp == NULL)
362 return NULL;
363
364 allvec = vector_init (VECTOR_MIN_SIZE);
365
366 while (1)
367 {
368 while (isspace ((int) *cp) && *cp != '\0')
369 cp++;
370
371 if (*cp == '(')
372 {
373 multiple = 1;
374 cp++;
375 }
376 if (*cp == ')')
377 {
378 multiple = 0;
379 cp++;
380 }
381 if (*cp == '|')
382 {
383 if (! multiple)
384 {
385 fprintf (stderr, "Command parse error!: %s\n", string);
386 exit (1);
387 }
388 cp++;
389 }
390
391 while (isspace ((int) *cp) && *cp != '\0')
392 cp++;
393
394 if (*cp == '(')
395 {
396 multiple = 1;
397 cp++;
398 }
399
400 if (*cp == '\0')
401 return allvec;
402
403 sp = cp;
404
405 while (! (isspace ((int) *cp) || *cp == '\r' || *cp == '\n' || *cp == ')' || *cp == '|') && *cp != '\0')
406 cp++;
407
408 len = cp - sp;
409
410 token = XMALLOC (MTYPE_STRVEC, len + 1);
411 memcpy (token, sp, len);
412 *(token + len) = '\0';
413
414 desc = XCALLOC (MTYPE_DESC, sizeof (struct desc));
415 desc->cmd = token;
416 desc->str = cmd_desc_str (&dp);
417
418 if (multiple)
419 {
420 if (multiple == 1)
421 {
422 strvec = vector_init (VECTOR_MIN_SIZE);
423 vector_set (allvec, strvec);
424 }
425 multiple++;
426 }
427 else
428 {
429 strvec = vector_init (VECTOR_MIN_SIZE);
430 vector_set (allvec, strvec);
431 }
432 vector_set (strvec, desc);
433 }
434}
435
436/* Count mandantory string vector size. This is to determine inputed
437 command has enough command length. */
ajs274a4a42004-12-07 15:39:31 +0000438static int
paul718e3742002-12-13 20:15:29 +0000439cmd_cmdsize (vector strvec)
440{
hasso8c328f12004-10-05 21:01:23 +0000441 unsigned int i;
paul718e3742002-12-13 20:15:29 +0000442 int size = 0;
443 vector descvec;
paulb8961472005-03-14 17:35:52 +0000444 struct desc *desc;
paul718e3742002-12-13 20:15:29 +0000445
paul55468c82005-03-14 20:19:01 +0000446 for (i = 0; i < vector_active (strvec); i++)
paulb8961472005-03-14 17:35:52 +0000447 if ((descvec = vector_slot (strvec, i)) != NULL)
paul718e3742002-12-13 20:15:29 +0000448 {
paul55468c82005-03-14 20:19:01 +0000449 if ((vector_active (descvec)) == 1
paulb8961472005-03-14 17:35:52 +0000450 && (desc = vector_slot (descvec, 0)) != NULL)
paul718e3742002-12-13 20:15:29 +0000451 {
hasso8c328f12004-10-05 21:01:23 +0000452 if (desc->cmd == NULL || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +0000453 return size;
454 else
455 size++;
456 }
457 else
458 size++;
459 }
460 return size;
461}
462
463/* Return prompt character of specified node. */
hasso8c328f12004-10-05 21:01:23 +0000464const char *
paul718e3742002-12-13 20:15:29 +0000465cmd_prompt (enum node_type node)
466{
467 struct cmd_node *cnode;
468
469 cnode = vector_slot (cmdvec, node);
470 return cnode->prompt;
471}
472
473/* Install a command into a node. */
474void
475install_element (enum node_type ntype, struct cmd_element *cmd)
476{
477 struct cmd_node *cnode;
478
479 cnode = vector_slot (cmdvec, ntype);
480
481 if (cnode == NULL)
482 {
483 fprintf (stderr, "Command node %d doesn't exist, please check it\n",
484 ntype);
485 exit (1);
486 }
487
488 vector_set (cnode->cmd_vector, cmd);
489
490 cmd->strvec = cmd_make_descvec (cmd->string, cmd->doc);
491 cmd->cmdsize = cmd_cmdsize (cmd->strvec);
492}
493
494static unsigned char itoa64[] =
495"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
496
ajs274a4a42004-12-07 15:39:31 +0000497static void
paul718e3742002-12-13 20:15:29 +0000498to64(char *s, long v, int n)
499{
500 while (--n >= 0)
501 {
502 *s++ = itoa64[v&0x3f];
503 v >>= 6;
504 }
505}
506
ajs274a4a42004-12-07 15:39:31 +0000507static char *
508zencrypt (const char *passwd)
paul718e3742002-12-13 20:15:29 +0000509{
510 char salt[6];
511 struct timeval tv;
512 char *crypt (const char *, const char *);
513
514 gettimeofday(&tv,0);
515
516 to64(&salt[0], random(), 3);
517 to64(&salt[3], tv.tv_usec, 3);
518 salt[5] = '\0';
519
520 return crypt (passwd, salt);
521}
522
523/* This function write configuration of this host. */
ajs274a4a42004-12-07 15:39:31 +0000524static int
paul718e3742002-12-13 20:15:29 +0000525config_write_host (struct vty *vty)
526{
527 if (host.name)
528 vty_out (vty, "hostname %s%s", host.name, VTY_NEWLINE);
529
530 if (host.encrypt)
531 {
532 if (host.password_encrypt)
533 vty_out (vty, "password 8 %s%s", host.password_encrypt, VTY_NEWLINE);
534 if (host.enable_encrypt)
535 vty_out (vty, "enable password 8 %s%s", host.enable_encrypt, VTY_NEWLINE);
536 }
537 else
538 {
539 if (host.password)
540 vty_out (vty, "password %s%s", host.password, VTY_NEWLINE);
541 if (host.enable)
542 vty_out (vty, "enable password %s%s", host.enable, VTY_NEWLINE);
543 }
544
ajs274a4a42004-12-07 15:39:31 +0000545 if (zlog_default->default_lvl != LOG_DEBUG)
ajs82146b82004-12-07 17:15:55 +0000546 {
547 vty_out (vty, "! N.B. The 'log trap' command is deprecated.%s",
548 VTY_NEWLINE);
549 vty_out (vty, "log trap %s%s",
550 zlog_priority[zlog_default->default_lvl], VTY_NEWLINE);
551 }
paul718e3742002-12-13 20:15:29 +0000552
ajs274a4a42004-12-07 15:39:31 +0000553 if (host.logfile && (zlog_default->maxlvl[ZLOG_DEST_FILE] != ZLOG_DISABLED))
paul12ab19f2003-07-26 06:14:55 +0000554 {
ajs274a4a42004-12-07 15:39:31 +0000555 vty_out (vty, "log file %s", host.logfile);
556 if (zlog_default->maxlvl[ZLOG_DEST_FILE] != zlog_default->default_lvl)
557 vty_out (vty, " %s",
558 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_FILE]]);
paul12ab19f2003-07-26 06:14:55 +0000559 vty_out (vty, "%s", VTY_NEWLINE);
560 }
ajs274a4a42004-12-07 15:39:31 +0000561
562 if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != ZLOG_DISABLED)
563 {
564 vty_out (vty, "log stdout");
565 if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != zlog_default->default_lvl)
566 vty_out (vty, " %s",
567 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_STDOUT]]);
568 vty_out (vty, "%s", VTY_NEWLINE);
569 }
570
571 if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
572 vty_out(vty,"no log monitor%s",VTY_NEWLINE);
573 else if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] != zlog_default->default_lvl)
574 vty_out(vty,"log monitor %s%s",
575 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_MONITOR]],VTY_NEWLINE);
576
577 if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED)
578 {
579 vty_out (vty, "log syslog");
580 if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != zlog_default->default_lvl)
581 vty_out (vty, " %s",
582 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_SYSLOG]]);
583 vty_out (vty, "%s", VTY_NEWLINE);
584 }
585
586 if (zlog_default->facility != LOG_DAEMON)
587 vty_out (vty, "log facility %s%s",
588 facility_name(zlog_default->facility), VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +0000589
590 if (zlog_default->record_priority == 1)
591 vty_out (vty, "log record-priority%s", VTY_NEWLINE);
592
593 if (host.advanced)
594 vty_out (vty, "service advanced-vty%s", VTY_NEWLINE);
595
596 if (host.encrypt)
597 vty_out (vty, "service password-encryption%s", VTY_NEWLINE);
598
599 if (host.lines >= 0)
600 vty_out (vty, "service terminal-length %d%s", host.lines,
601 VTY_NEWLINE);
602
paul3b0c5d92005-03-08 10:43:43 +0000603 if (host.motdfile)
604 vty_out (vty, "banner motd file %s%s", host.motdfile, VTY_NEWLINE);
605 else if (! host.motd)
paul718e3742002-12-13 20:15:29 +0000606 vty_out (vty, "no banner motd%s", VTY_NEWLINE);
607
608 return 1;
609}
610
611/* Utility function for getting command vector. */
ajs274a4a42004-12-07 15:39:31 +0000612static vector
paul718e3742002-12-13 20:15:29 +0000613cmd_node_vector (vector v, enum node_type ntype)
614{
615 struct cmd_node *cnode = vector_slot (v, ntype);
616 return cnode->cmd_vector;
617}
618
ajs274a4a42004-12-07 15:39:31 +0000619#if 0
620/* Filter command vector by symbol. This function is not actually used;
621 * should it be deleted? */
622static int
paul718e3742002-12-13 20:15:29 +0000623cmd_filter_by_symbol (char *command, char *symbol)
624{
625 int i, lim;
626
627 if (strcmp (symbol, "IPV4_ADDRESS") == 0)
628 {
629 i = 0;
630 lim = strlen (command);
631 while (i < lim)
632 {
633 if (! (isdigit ((int) command[i]) || command[i] == '.' || command[i] == '/'))
634 return 1;
635 i++;
636 }
637 return 0;
638 }
639 if (strcmp (symbol, "STRING") == 0)
640 {
641 i = 0;
642 lim = strlen (command);
643 while (i < lim)
644 {
645 if (! (isalpha ((int) command[i]) || command[i] == '_' || command[i] == '-'))
646 return 1;
647 i++;
648 }
649 return 0;
650 }
651 if (strcmp (symbol, "IFNAME") == 0)
652 {
653 i = 0;
654 lim = strlen (command);
655 while (i < lim)
656 {
657 if (! isalnum ((int) command[i]))
658 return 1;
659 i++;
660 }
661 return 0;
662 }
663 return 0;
664}
ajs274a4a42004-12-07 15:39:31 +0000665#endif
paul718e3742002-12-13 20:15:29 +0000666
667/* Completion match types. */
668enum match_type
669{
670 no_match,
671 extend_match,
672 ipv4_prefix_match,
673 ipv4_match,
674 ipv6_prefix_match,
675 ipv6_match,
676 range_match,
677 vararg_match,
678 partly_match,
679 exact_match
680};
681
ajs274a4a42004-12-07 15:39:31 +0000682static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000683cmd_ipv4_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000684{
hasso8c328f12004-10-05 21:01:23 +0000685 const char *sp;
paul718e3742002-12-13 20:15:29 +0000686 int dots = 0, nums = 0;
687 char buf[4];
688
689 if (str == NULL)
690 return partly_match;
691
692 for (;;)
693 {
694 memset (buf, 0, sizeof (buf));
695 sp = str;
696 while (*str != '\0')
697 {
698 if (*str == '.')
699 {
700 if (dots >= 3)
701 return no_match;
702
703 if (*(str + 1) == '.')
704 return no_match;
705
706 if (*(str + 1) == '\0')
707 return partly_match;
708
709 dots++;
710 break;
711 }
712 if (!isdigit ((int) *str))
713 return no_match;
714
715 str++;
716 }
717
718 if (str - sp > 3)
719 return no_match;
720
721 strncpy (buf, sp, str - sp);
722 if (atoi (buf) > 255)
723 return no_match;
724
725 nums++;
726
727 if (*str == '\0')
728 break;
729
730 str++;
731 }
732
733 if (nums < 4)
734 return partly_match;
735
736 return exact_match;
737}
738
ajs274a4a42004-12-07 15:39:31 +0000739static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000740cmd_ipv4_prefix_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000741{
hasso8c328f12004-10-05 21:01:23 +0000742 const char *sp;
paul718e3742002-12-13 20:15:29 +0000743 int dots = 0;
744 char buf[4];
745
746 if (str == NULL)
747 return partly_match;
748
749 for (;;)
750 {
751 memset (buf, 0, sizeof (buf));
752 sp = str;
753 while (*str != '\0' && *str != '/')
754 {
755 if (*str == '.')
756 {
757 if (dots == 3)
758 return no_match;
759
760 if (*(str + 1) == '.' || *(str + 1) == '/')
761 return no_match;
762
763 if (*(str + 1) == '\0')
764 return partly_match;
765
766 dots++;
767 break;
768 }
769
770 if (!isdigit ((int) *str))
771 return no_match;
772
773 str++;
774 }
775
776 if (str - sp > 3)
777 return no_match;
778
779 strncpy (buf, sp, str - sp);
780 if (atoi (buf) > 255)
781 return no_match;
782
783 if (dots == 3)
784 {
785 if (*str == '/')
786 {
787 if (*(str + 1) == '\0')
788 return partly_match;
789
790 str++;
791 break;
792 }
793 else if (*str == '\0')
794 return partly_match;
795 }
796
797 if (*str == '\0')
798 return partly_match;
799
800 str++;
801 }
802
803 sp = str;
804 while (*str != '\0')
805 {
806 if (!isdigit ((int) *str))
807 return no_match;
808
809 str++;
810 }
811
812 if (atoi (sp) > 32)
813 return no_match;
814
815 return exact_match;
816}
817
818#define IPV6_ADDR_STR "0123456789abcdefABCDEF:.%"
819#define IPV6_PREFIX_STR "0123456789abcdefABCDEF:.%/"
820#define STATE_START 1
821#define STATE_COLON 2
822#define STATE_DOUBLE 3
823#define STATE_ADDR 4
824#define STATE_DOT 5
825#define STATE_SLASH 6
826#define STATE_MASK 7
827
paul22e0a9e2003-07-11 17:55:46 +0000828#ifdef HAVE_IPV6
829
ajs274a4a42004-12-07 15:39:31 +0000830static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000831cmd_ipv6_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000832{
833 int state = STATE_START;
834 int colons = 0, nums = 0, double_colon = 0;
hasso8c328f12004-10-05 21:01:23 +0000835 const char *sp = NULL;
hasso726f9b22003-05-25 21:04:54 +0000836 struct sockaddr_in6 sin6_dummy;
837 int ret;
paul718e3742002-12-13 20:15:29 +0000838
839 if (str == NULL)
840 return partly_match;
841
842 if (strspn (str, IPV6_ADDR_STR) != strlen (str))
843 return no_match;
844
hasso726f9b22003-05-25 21:04:54 +0000845 /* use inet_pton that has a better support,
846 * for example inet_pton can support the automatic addresses:
847 * ::1.2.3.4
848 */
849 ret = inet_pton(AF_INET6, str, &sin6_dummy.sin6_addr);
850
851 if (ret == 1)
852 return exact_match;
853
paul718e3742002-12-13 20:15:29 +0000854 while (*str != '\0')
855 {
856 switch (state)
857 {
858 case STATE_START:
859 if (*str == ':')
860 {
861 if (*(str + 1) != ':' && *(str + 1) != '\0')
862 return no_match;
863 colons--;
864 state = STATE_COLON;
865 }
866 else
867 {
868 sp = str;
869 state = STATE_ADDR;
870 }
871
872 continue;
873 case STATE_COLON:
874 colons++;
875 if (*(str + 1) == ':')
876 state = STATE_DOUBLE;
877 else
878 {
879 sp = str + 1;
880 state = STATE_ADDR;
881 }
882 break;
883 case STATE_DOUBLE:
884 if (double_colon)
885 return no_match;
886
887 if (*(str + 1) == ':')
888 return no_match;
889 else
890 {
891 if (*(str + 1) != '\0')
892 colons++;
893 sp = str + 1;
894 state = STATE_ADDR;
895 }
896
897 double_colon++;
898 nums++;
899 break;
900 case STATE_ADDR:
901 if (*(str + 1) == ':' || *(str + 1) == '\0')
902 {
903 if (str - sp > 3)
904 return no_match;
905
906 nums++;
907 state = STATE_COLON;
908 }
909 if (*(str + 1) == '.')
910 state = STATE_DOT;
911 break;
912 case STATE_DOT:
913 state = STATE_ADDR;
914 break;
915 default:
916 break;
917 }
918
919 if (nums > 8)
920 return no_match;
921
922 if (colons > 7)
923 return no_match;
924
925 str++;
926 }
927
928#if 0
929 if (nums < 11)
930 return partly_match;
931#endif /* 0 */
932
933 return exact_match;
934}
935
ajs274a4a42004-12-07 15:39:31 +0000936static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000937cmd_ipv6_prefix_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000938{
939 int state = STATE_START;
940 int colons = 0, nums = 0, double_colon = 0;
941 int mask;
hasso8c328f12004-10-05 21:01:23 +0000942 const char *sp = NULL;
paul718e3742002-12-13 20:15:29 +0000943 char *endptr = NULL;
944
945 if (str == NULL)
946 return partly_match;
947
948 if (strspn (str, IPV6_PREFIX_STR) != strlen (str))
949 return no_match;
950
951 while (*str != '\0' && state != STATE_MASK)
952 {
953 switch (state)
954 {
955 case STATE_START:
956 if (*str == ':')
957 {
958 if (*(str + 1) != ':' && *(str + 1) != '\0')
959 return no_match;
960 colons--;
961 state = STATE_COLON;
962 }
963 else
964 {
965 sp = str;
966 state = STATE_ADDR;
967 }
968
969 continue;
970 case STATE_COLON:
971 colons++;
972 if (*(str + 1) == '/')
973 return no_match;
974 else if (*(str + 1) == ':')
975 state = STATE_DOUBLE;
976 else
977 {
978 sp = str + 1;
979 state = STATE_ADDR;
980 }
981 break;
982 case STATE_DOUBLE:
983 if (double_colon)
984 return no_match;
985
986 if (*(str + 1) == ':')
987 return no_match;
988 else
989 {
990 if (*(str + 1) != '\0' && *(str + 1) != '/')
991 colons++;
992 sp = str + 1;
993
994 if (*(str + 1) == '/')
995 state = STATE_SLASH;
996 else
997 state = STATE_ADDR;
998 }
999
1000 double_colon++;
1001 nums += 1;
1002 break;
1003 case STATE_ADDR:
1004 if (*(str + 1) == ':' || *(str + 1) == '.'
1005 || *(str + 1) == '\0' || *(str + 1) == '/')
1006 {
1007 if (str - sp > 3)
1008 return no_match;
1009
1010 for (; sp <= str; sp++)
1011 if (*sp == '/')
1012 return no_match;
1013
1014 nums++;
1015
1016 if (*(str + 1) == ':')
1017 state = STATE_COLON;
1018 else if (*(str + 1) == '.')
1019 state = STATE_DOT;
1020 else if (*(str + 1) == '/')
1021 state = STATE_SLASH;
1022 }
1023 break;
1024 case STATE_DOT:
1025 state = STATE_ADDR;
1026 break;
1027 case STATE_SLASH:
1028 if (*(str + 1) == '\0')
1029 return partly_match;
1030
1031 state = STATE_MASK;
1032 break;
1033 default:
1034 break;
1035 }
1036
1037 if (nums > 11)
1038 return no_match;
1039
1040 if (colons > 7)
1041 return no_match;
1042
1043 str++;
1044 }
1045
1046 if (state < STATE_MASK)
1047 return partly_match;
1048
1049 mask = strtol (str, &endptr, 10);
1050 if (*endptr != '\0')
1051 return no_match;
1052
1053 if (mask < 0 || mask > 128)
1054 return no_match;
1055
1056/* I don't know why mask < 13 makes command match partly.
1057 Forgive me to make this comments. I Want to set static default route
1058 because of lack of function to originate default in ospf6d; sorry
1059 yasu
1060 if (mask < 13)
1061 return partly_match;
1062*/
1063
1064 return exact_match;
1065}
1066
paul22e0a9e2003-07-11 17:55:46 +00001067#endif /* HAVE_IPV6 */
1068
paul718e3742002-12-13 20:15:29 +00001069#define DECIMAL_STRLEN_MAX 10
1070
ajs274a4a42004-12-07 15:39:31 +00001071static int
hasso8c328f12004-10-05 21:01:23 +00001072cmd_range_match (const char *range, const char *str)
paul718e3742002-12-13 20:15:29 +00001073{
1074 char *p;
1075 char buf[DECIMAL_STRLEN_MAX + 1];
1076 char *endptr = NULL;
1077 unsigned long min, max, val;
1078
1079 if (str == NULL)
1080 return 1;
1081
1082 val = strtoul (str, &endptr, 10);
1083 if (*endptr != '\0')
1084 return 0;
1085
1086 range++;
1087 p = strchr (range, '-');
1088 if (p == NULL)
1089 return 0;
1090 if (p - range > DECIMAL_STRLEN_MAX)
1091 return 0;
1092 strncpy (buf, range, p - range);
1093 buf[p - range] = '\0';
1094 min = strtoul (buf, &endptr, 10);
1095 if (*endptr != '\0')
1096 return 0;
1097
1098 range = p + 1;
1099 p = strchr (range, '>');
1100 if (p == NULL)
1101 return 0;
1102 if (p - range > DECIMAL_STRLEN_MAX)
1103 return 0;
1104 strncpy (buf, range, p - range);
1105 buf[p - range] = '\0';
1106 max = strtoul (buf, &endptr, 10);
1107 if (*endptr != '\0')
1108 return 0;
1109
1110 if (val < min || val > max)
1111 return 0;
1112
1113 return 1;
1114}
1115
1116/* Make completion match and return match type flag. */
ajs274a4a42004-12-07 15:39:31 +00001117static enum match_type
hasso8c328f12004-10-05 21:01:23 +00001118cmd_filter_by_completion (char *command, vector v, unsigned int index)
paul718e3742002-12-13 20:15:29 +00001119{
hasso8c328f12004-10-05 21:01:23 +00001120 unsigned int i;
1121 const char *str;
paul718e3742002-12-13 20:15:29 +00001122 struct cmd_element *cmd_element;
1123 enum match_type match_type;
1124 vector descvec;
1125 struct desc *desc;
paul909a2152005-03-14 17:41:45 +00001126
paul718e3742002-12-13 20:15:29 +00001127 match_type = no_match;
1128
1129 /* If command and cmd_element string does not match set NULL to vector */
paul55468c82005-03-14 20:19:01 +00001130 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001131 if ((cmd_element = vector_slot (v, i)) != NULL)
1132 {
paul55468c82005-03-14 20:19:01 +00001133 if (index >= vector_active (cmd_element->strvec))
paul718e3742002-12-13 20:15:29 +00001134 vector_slot (v, i) = NULL;
1135 else
1136 {
hasso8c328f12004-10-05 21:01:23 +00001137 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001138 int matched = 0;
1139
1140 descvec = vector_slot (cmd_element->strvec, index);
paul909a2152005-03-14 17:41:45 +00001141
paul55468c82005-03-14 20:19:01 +00001142 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001143 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001144 {
1145 str = desc->cmd;
1146
1147 if (CMD_VARARG (str))
1148 {
1149 if (match_type < vararg_match)
1150 match_type = vararg_match;
1151 matched++;
1152 }
1153 else if (CMD_RANGE (str))
1154 {
1155 if (cmd_range_match (str, command))
1156 {
1157 if (match_type < range_match)
1158 match_type = range_match;
paul718e3742002-12-13 20:15:29 +00001159
paul909a2152005-03-14 17:41:45 +00001160 matched++;
1161 }
1162 }
paul22e0a9e2003-07-11 17:55:46 +00001163#ifdef HAVE_IPV6
paul909a2152005-03-14 17:41:45 +00001164 else if (CMD_IPV6 (str))
1165 {
1166 if (cmd_ipv6_match (command))
1167 {
1168 if (match_type < ipv6_match)
1169 match_type = ipv6_match;
paul718e3742002-12-13 20:15:29 +00001170
paul909a2152005-03-14 17:41:45 +00001171 matched++;
1172 }
1173 }
1174 else if (CMD_IPV6_PREFIX (str))
1175 {
1176 if (cmd_ipv6_prefix_match (command))
1177 {
1178 if (match_type < ipv6_prefix_match)
1179 match_type = ipv6_prefix_match;
paul718e3742002-12-13 20:15:29 +00001180
paul909a2152005-03-14 17:41:45 +00001181 matched++;
1182 }
1183 }
1184#endif /* HAVE_IPV6 */
1185 else if (CMD_IPV4 (str))
1186 {
1187 if (cmd_ipv4_match (command))
1188 {
1189 if (match_type < ipv4_match)
1190 match_type = ipv4_match;
paul718e3742002-12-13 20:15:29 +00001191
paul909a2152005-03-14 17:41:45 +00001192 matched++;
1193 }
1194 }
1195 else if (CMD_IPV4_PREFIX (str))
1196 {
1197 if (cmd_ipv4_prefix_match (command))
1198 {
1199 if (match_type < ipv4_prefix_match)
1200 match_type = ipv4_prefix_match;
1201 matched++;
1202 }
1203 }
1204 else
1205 /* Check is this point's argument optional ? */
1206 if (CMD_OPTION (str) || CMD_VARIABLE (str))
1207 {
1208 if (match_type < extend_match)
1209 match_type = extend_match;
1210 matched++;
1211 }
1212 else if (strncmp (command, str, strlen (command)) == 0)
1213 {
1214 if (strcmp (command, str) == 0)
1215 match_type = exact_match;
1216 else
1217 {
1218 if (match_type < partly_match)
1219 match_type = partly_match;
1220 }
1221 matched++;
1222 }
1223 }
1224 if (!matched)
paul718e3742002-12-13 20:15:29 +00001225 vector_slot (v, i) = NULL;
1226 }
1227 }
1228 return match_type;
1229}
1230
1231/* Filter vector by command character with index. */
ajs274a4a42004-12-07 15:39:31 +00001232static enum match_type
hasso8c328f12004-10-05 21:01:23 +00001233cmd_filter_by_string (char *command, vector v, unsigned int index)
paul718e3742002-12-13 20:15:29 +00001234{
hasso8c328f12004-10-05 21:01:23 +00001235 unsigned int i;
1236 const char *str;
paul718e3742002-12-13 20:15:29 +00001237 struct cmd_element *cmd_element;
1238 enum match_type match_type;
1239 vector descvec;
1240 struct desc *desc;
paul909a2152005-03-14 17:41:45 +00001241
paul718e3742002-12-13 20:15:29 +00001242 match_type = no_match;
1243
1244 /* If command and cmd_element string does not match set NULL to vector */
paul55468c82005-03-14 20:19:01 +00001245 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001246 if ((cmd_element = vector_slot (v, i)) != NULL)
1247 {
1248 /* If given index is bigger than max string vector of command,
paul909a2152005-03-14 17:41:45 +00001249 set NULL */
paul55468c82005-03-14 20:19:01 +00001250 if (index >= vector_active (cmd_element->strvec))
paul718e3742002-12-13 20:15:29 +00001251 vector_slot (v, i) = NULL;
paul909a2152005-03-14 17:41:45 +00001252 else
paul718e3742002-12-13 20:15:29 +00001253 {
hasso8c328f12004-10-05 21:01:23 +00001254 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001255 int matched = 0;
1256
1257 descvec = vector_slot (cmd_element->strvec, index);
1258
paul55468c82005-03-14 20:19:01 +00001259 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001260 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001261 {
1262 str = desc->cmd;
paul718e3742002-12-13 20:15:29 +00001263
paul909a2152005-03-14 17:41:45 +00001264 if (CMD_VARARG (str))
1265 {
1266 if (match_type < vararg_match)
1267 match_type = vararg_match;
1268 matched++;
1269 }
1270 else if (CMD_RANGE (str))
1271 {
1272 if (cmd_range_match (str, command))
1273 {
1274 if (match_type < range_match)
1275 match_type = range_match;
1276 matched++;
1277 }
1278 }
paul22e0a9e2003-07-11 17:55:46 +00001279#ifdef HAVE_IPV6
paul909a2152005-03-14 17:41:45 +00001280 else if (CMD_IPV6 (str))
1281 {
1282 if (cmd_ipv6_match (command) == exact_match)
1283 {
1284 if (match_type < ipv6_match)
1285 match_type = ipv6_match;
1286 matched++;
1287 }
1288 }
1289 else if (CMD_IPV6_PREFIX (str))
1290 {
1291 if (cmd_ipv6_prefix_match (command) == exact_match)
1292 {
1293 if (match_type < ipv6_prefix_match)
1294 match_type = ipv6_prefix_match;
1295 matched++;
1296 }
1297 }
paul22e0a9e2003-07-11 17:55:46 +00001298#endif /* HAVE_IPV6 */
paul909a2152005-03-14 17:41:45 +00001299 else if (CMD_IPV4 (str))
1300 {
1301 if (cmd_ipv4_match (command) == exact_match)
1302 {
1303 if (match_type < ipv4_match)
1304 match_type = ipv4_match;
1305 matched++;
1306 }
1307 }
1308 else if (CMD_IPV4_PREFIX (str))
1309 {
1310 if (cmd_ipv4_prefix_match (command) == exact_match)
1311 {
1312 if (match_type < ipv4_prefix_match)
1313 match_type = ipv4_prefix_match;
1314 matched++;
1315 }
1316 }
1317 else if (CMD_OPTION (str) || CMD_VARIABLE (str))
1318 {
1319 if (match_type < extend_match)
1320 match_type = extend_match;
1321 matched++;
1322 }
1323 else
1324 {
1325 if (strcmp (command, str) == 0)
1326 {
1327 match_type = exact_match;
1328 matched++;
1329 }
1330 }
1331 }
1332 if (!matched)
paul718e3742002-12-13 20:15:29 +00001333 vector_slot (v, i) = NULL;
1334 }
1335 }
1336 return match_type;
1337}
1338
1339/* Check ambiguous match */
ajs274a4a42004-12-07 15:39:31 +00001340static int
paul718e3742002-12-13 20:15:29 +00001341is_cmd_ambiguous (char *command, vector v, int index, enum match_type type)
1342{
hasso8c328f12004-10-05 21:01:23 +00001343 unsigned int i;
1344 unsigned int j;
1345 const char *str = NULL;
paul718e3742002-12-13 20:15:29 +00001346 struct cmd_element *cmd_element;
hasso8c328f12004-10-05 21:01:23 +00001347 const char *matched = NULL;
paul718e3742002-12-13 20:15:29 +00001348 vector descvec;
1349 struct desc *desc;
paul909a2152005-03-14 17:41:45 +00001350
paul55468c82005-03-14 20:19:01 +00001351 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001352 if ((cmd_element = vector_slot (v, i)) != NULL)
1353 {
1354 int match = 0;
1355
1356 descvec = vector_slot (cmd_element->strvec, index);
1357
paul55468c82005-03-14 20:19:01 +00001358 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001359 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001360 {
1361 enum match_type ret;
1362
1363 str = desc->cmd;
paul718e3742002-12-13 20:15:29 +00001364
paul909a2152005-03-14 17:41:45 +00001365 switch (type)
1366 {
1367 case exact_match:
1368 if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
1369 && strcmp (command, str) == 0)
1370 match++;
1371 break;
1372 case partly_match:
1373 if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
1374 && strncmp (command, str, strlen (command)) == 0)
1375 {
1376 if (matched && strcmp (matched, str) != 0)
1377 return 1; /* There is ambiguous match. */
1378 else
1379 matched = str;
1380 match++;
1381 }
1382 break;
1383 case range_match:
1384 if (cmd_range_match (str, command))
1385 {
1386 if (matched && strcmp (matched, str) != 0)
1387 return 1;
1388 else
1389 matched = str;
1390 match++;
1391 }
1392 break;
1393#ifdef HAVE_IPV6
1394 case ipv6_match:
1395 if (CMD_IPV6 (str))
1396 match++;
1397 break;
1398 case ipv6_prefix_match:
1399 if ((ret = cmd_ipv6_prefix_match (command)) != no_match)
1400 {
1401 if (ret == partly_match)
1402 return 2; /* There is incomplete match. */
paul718e3742002-12-13 20:15:29 +00001403
paul909a2152005-03-14 17:41:45 +00001404 match++;
1405 }
1406 break;
1407#endif /* HAVE_IPV6 */
1408 case ipv4_match:
1409 if (CMD_IPV4 (str))
paul718e3742002-12-13 20:15:29 +00001410 match++;
paul909a2152005-03-14 17:41:45 +00001411 break;
1412 case ipv4_prefix_match:
1413 if ((ret = cmd_ipv4_prefix_match (command)) != no_match)
1414 {
1415 if (ret == partly_match)
1416 return 2; /* There is incomplete match. */
paul718e3742002-12-13 20:15:29 +00001417
paul909a2152005-03-14 17:41:45 +00001418 match++;
1419 }
1420 break;
1421 case extend_match:
1422 if (CMD_OPTION (str) || CMD_VARIABLE (str))
paul718e3742002-12-13 20:15:29 +00001423 match++;
paul909a2152005-03-14 17:41:45 +00001424 break;
1425 case no_match:
1426 default:
1427 break;
1428 }
1429 }
1430 if (!match)
paul718e3742002-12-13 20:15:29 +00001431 vector_slot (v, i) = NULL;
1432 }
1433 return 0;
1434}
1435
1436/* If src matches dst return dst string, otherwise return NULL */
ajs274a4a42004-12-07 15:39:31 +00001437static const char *
hasso8c328f12004-10-05 21:01:23 +00001438cmd_entry_function (const char *src, const char *dst)
paul718e3742002-12-13 20:15:29 +00001439{
1440 /* Skip variable arguments. */
1441 if (CMD_OPTION (dst) || CMD_VARIABLE (dst) || CMD_VARARG (dst) ||
1442 CMD_IPV4 (dst) || CMD_IPV4_PREFIX (dst) || CMD_RANGE (dst))
1443 return NULL;
1444
1445 /* In case of 'command \t', given src is NULL string. */
1446 if (src == NULL)
1447 return dst;
1448
1449 /* Matched with input string. */
1450 if (strncmp (src, dst, strlen (src)) == 0)
1451 return dst;
1452
1453 return NULL;
1454}
1455
1456/* If src matches dst return dst string, otherwise return NULL */
1457/* This version will return the dst string always if it is
1458 CMD_VARIABLE for '?' key processing */
ajs274a4a42004-12-07 15:39:31 +00001459static const char *
hasso8c328f12004-10-05 21:01:23 +00001460cmd_entry_function_desc (const char *src, const char *dst)
paul718e3742002-12-13 20:15:29 +00001461{
1462 if (CMD_VARARG (dst))
1463 return dst;
1464
1465 if (CMD_RANGE (dst))
1466 {
1467 if (cmd_range_match (dst, src))
1468 return dst;
1469 else
1470 return NULL;
1471 }
1472
paul22e0a9e2003-07-11 17:55:46 +00001473#ifdef HAVE_IPV6
paul718e3742002-12-13 20:15:29 +00001474 if (CMD_IPV6 (dst))
1475 {
1476 if (cmd_ipv6_match (src))
1477 return dst;
1478 else
1479 return NULL;
1480 }
1481
1482 if (CMD_IPV6_PREFIX (dst))
1483 {
1484 if (cmd_ipv6_prefix_match (src))
1485 return dst;
1486 else
1487 return NULL;
1488 }
paul22e0a9e2003-07-11 17:55:46 +00001489#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +00001490
1491 if (CMD_IPV4 (dst))
1492 {
1493 if (cmd_ipv4_match (src))
1494 return dst;
1495 else
1496 return NULL;
1497 }
1498
1499 if (CMD_IPV4_PREFIX (dst))
1500 {
1501 if (cmd_ipv4_prefix_match (src))
1502 return dst;
1503 else
1504 return NULL;
1505 }
1506
1507 /* Optional or variable commands always match on '?' */
1508 if (CMD_OPTION (dst) || CMD_VARIABLE (dst))
1509 return dst;
1510
1511 /* In case of 'command \t', given src is NULL string. */
1512 if (src == NULL)
1513 return dst;
1514
1515 if (strncmp (src, dst, strlen (src)) == 0)
1516 return dst;
1517 else
1518 return NULL;
1519}
1520
1521/* Check same string element existence. If it isn't there return
1522 1. */
ajs274a4a42004-12-07 15:39:31 +00001523static int
hasso8c328f12004-10-05 21:01:23 +00001524cmd_unique_string (vector v, const char *str)
paul718e3742002-12-13 20:15:29 +00001525{
hasso8c328f12004-10-05 21:01:23 +00001526 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001527 char *match;
1528
paul55468c82005-03-14 20:19:01 +00001529 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001530 if ((match = vector_slot (v, i)) != NULL)
1531 if (strcmp (match, str) == 0)
1532 return 0;
1533 return 1;
1534}
1535
1536/* Compare string to description vector. If there is same string
1537 return 1 else return 0. */
ajs274a4a42004-12-07 15:39:31 +00001538static int
hasso8c328f12004-10-05 21:01:23 +00001539desc_unique_string (vector v, const char *str)
paul718e3742002-12-13 20:15:29 +00001540{
hasso8c328f12004-10-05 21:01:23 +00001541 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001542 struct desc *desc;
1543
paul55468c82005-03-14 20:19:01 +00001544 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001545 if ((desc = vector_slot (v, i)) != NULL)
1546 if (strcmp (desc->cmd, str) == 0)
1547 return 1;
1548 return 0;
1549}
1550
ajs274a4a42004-12-07 15:39:31 +00001551static int
paulb92938a2002-12-13 21:20:42 +00001552cmd_try_do_shortcut (enum node_type node, char* first_word) {
1553 if ( first_word != NULL &&
1554 node != AUTH_NODE &&
1555 node != VIEW_NODE &&
1556 node != AUTH_ENABLE_NODE &&
1557 node != ENABLE_NODE &&
1558 0 == strcmp( "do", first_word ) )
1559 return 1;
1560 return 0;
1561}
1562
paul718e3742002-12-13 20:15:29 +00001563/* '?' describe command support. */
ajs274a4a42004-12-07 15:39:31 +00001564static vector
paulb92938a2002-12-13 21:20:42 +00001565cmd_describe_command_real (vector vline, struct vty *vty, int *status)
paul718e3742002-12-13 20:15:29 +00001566{
paulb8961472005-03-14 17:35:52 +00001567 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001568 vector cmd_vector;
1569#define INIT_MATCHVEC_SIZE 10
1570 vector matchvec;
1571 struct cmd_element *cmd_element;
paulb8961472005-03-14 17:35:52 +00001572 unsigned int index;
paul54aba542003-08-21 20:28:24 +00001573 int ret;
1574 enum match_type match;
1575 char *command;
paul718e3742002-12-13 20:15:29 +00001576 static struct desc desc_cr = { "<cr>", "" };
1577
1578 /* Set index. */
paul55468c82005-03-14 20:19:01 +00001579 if (vector_active (vline) == 0)
paulb8961472005-03-14 17:35:52 +00001580 {
1581 *status = CMD_ERR_NO_MATCH;
1582 return NULL;
1583 }
1584 else
paul55468c82005-03-14 20:19:01 +00001585 index = vector_active (vline) - 1;
paul909a2152005-03-14 17:41:45 +00001586
paul718e3742002-12-13 20:15:29 +00001587 /* Make copy vector of current node's command vector. */
1588 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1589
1590 /* Prepare match vector */
1591 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1592
1593 /* Filter commands. */
paul54aba542003-08-21 20:28:24 +00001594 /* Only words precedes current word will be checked in this loop. */
paul718e3742002-12-13 20:15:29 +00001595 for (i = 0; i < index; i++)
paulb8961472005-03-14 17:35:52 +00001596 if ((command = vector_slot (vline, i)))
paul909a2152005-03-14 17:41:45 +00001597 {
1598 match = cmd_filter_by_completion (command, cmd_vector, i);
1599
1600 if (match == vararg_match)
1601 {
1602 struct cmd_element *cmd_element;
1603 vector descvec;
1604 unsigned int j, k;
paul718e3742002-12-13 20:15:29 +00001605
paul55468c82005-03-14 20:19:01 +00001606 for (j = 0; j < vector_active (cmd_vector); j++)
paulb8961472005-03-14 17:35:52 +00001607 if ((cmd_element = vector_slot (cmd_vector, j)) != NULL
paul55468c82005-03-14 20:19:01 +00001608 && (vector_active (cmd_element->strvec)))
paul909a2152005-03-14 17:41:45 +00001609 {
1610 descvec = vector_slot (cmd_element->strvec,
paul55468c82005-03-14 20:19:01 +00001611 vector_active (cmd_element->strvec) - 1);
1612 for (k = 0; k < vector_active (descvec); k++)
paul909a2152005-03-14 17:41:45 +00001613 {
1614 struct desc *desc = vector_slot (descvec, k);
1615 vector_set (matchvec, desc);
1616 }
1617 }
1618
1619 vector_set (matchvec, &desc_cr);
1620 vector_free (cmd_vector);
paul718e3742002-12-13 20:15:29 +00001621
paul909a2152005-03-14 17:41:45 +00001622 return matchvec;
1623 }
paul718e3742002-12-13 20:15:29 +00001624
paul909a2152005-03-14 17:41:45 +00001625 if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
1626 {
1627 vector_free (cmd_vector);
1628 *status = CMD_ERR_AMBIGUOUS;
1629 return NULL;
1630 }
1631 else if (ret == 2)
1632 {
1633 vector_free (cmd_vector);
1634 *status = CMD_ERR_NO_MATCH;
1635 return NULL;
1636 }
1637 }
paul718e3742002-12-13 20:15:29 +00001638
1639 /* Prepare match vector */
1640 /* matchvec = vector_init (INIT_MATCHVEC_SIZE); */
1641
paul54aba542003-08-21 20:28:24 +00001642 /* Make sure that cmd_vector is filtered based on current word */
1643 command = vector_slot (vline, index);
1644 if (command)
1645 match = cmd_filter_by_completion (command, cmd_vector, index);
1646
paul718e3742002-12-13 20:15:29 +00001647 /* Make description vector. */
paul55468c82005-03-14 20:19:01 +00001648 for (i = 0; i < vector_active (cmd_vector); i++)
paul718e3742002-12-13 20:15:29 +00001649 if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
1650 {
hasso8c328f12004-10-05 21:01:23 +00001651 const char *string = NULL;
paul718e3742002-12-13 20:15:29 +00001652 vector strvec = cmd_element->strvec;
1653
paul55468c82005-03-14 20:19:01 +00001654 /* if command is NULL, index may be equal to vector_active */
1655 if (command && index >= vector_active (strvec))
paul718e3742002-12-13 20:15:29 +00001656 vector_slot (cmd_vector, i) = NULL;
1657 else
1658 {
paul54aba542003-08-21 20:28:24 +00001659 /* Check if command is completed. */
paul55468c82005-03-14 20:19:01 +00001660 if (command == NULL && index == vector_active (strvec))
paul718e3742002-12-13 20:15:29 +00001661 {
1662 string = "<cr>";
paul909a2152005-03-14 17:41:45 +00001663 if (!desc_unique_string (matchvec, string))
paul718e3742002-12-13 20:15:29 +00001664 vector_set (matchvec, &desc_cr);
1665 }
1666 else
1667 {
hasso8c328f12004-10-05 21:01:23 +00001668 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001669 vector descvec = vector_slot (strvec, index);
1670 struct desc *desc;
1671
paul55468c82005-03-14 20:19:01 +00001672 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001673 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001674 {
1675 string = cmd_entry_function_desc (command, desc->cmd);
1676 if (string)
1677 {
1678 /* Uniqueness check */
1679 if (!desc_unique_string (matchvec, string))
1680 vector_set (matchvec, desc);
1681 }
1682 }
paul718e3742002-12-13 20:15:29 +00001683 }
1684 }
1685 }
1686 vector_free (cmd_vector);
1687
1688 if (vector_slot (matchvec, 0) == NULL)
1689 {
1690 vector_free (matchvec);
paul909a2152005-03-14 17:41:45 +00001691 *status = CMD_ERR_NO_MATCH;
paul718e3742002-12-13 20:15:29 +00001692 }
1693 else
1694 *status = CMD_SUCCESS;
1695
1696 return matchvec;
1697}
1698
paulb92938a2002-12-13 21:20:42 +00001699vector
1700cmd_describe_command (vector vline, struct vty *vty, int *status)
1701{
1702 vector ret;
1703
1704 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1705 {
1706 enum node_type onode;
1707 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00001708 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00001709
1710 onode = vty->node;
1711 vty->node = ENABLE_NODE;
1712 /* We can try it on enable node, cos' the vty is authenticated */
1713
1714 shifted_vline = vector_init (vector_count(vline));
1715 /* use memcpy? */
paul55468c82005-03-14 20:19:01 +00001716 for (index = 1; index < vector_active (vline); index++)
paulb92938a2002-12-13 21:20:42 +00001717 {
1718 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1719 }
1720
1721 ret = cmd_describe_command_real (shifted_vline, vty, status);
1722
1723 vector_free(shifted_vline);
1724 vty->node = onode;
1725 return ret;
1726 }
1727
1728
1729 return cmd_describe_command_real (vline, vty, status);
1730}
1731
1732
paul718e3742002-12-13 20:15:29 +00001733/* Check LCD of matched command. */
ajs274a4a42004-12-07 15:39:31 +00001734static int
paul718e3742002-12-13 20:15:29 +00001735cmd_lcd (char **matched)
1736{
1737 int i;
1738 int j;
1739 int lcd = -1;
1740 char *s1, *s2;
1741 char c1, c2;
1742
1743 if (matched[0] == NULL || matched[1] == NULL)
1744 return 0;
1745
1746 for (i = 1; matched[i] != NULL; i++)
1747 {
1748 s1 = matched[i - 1];
1749 s2 = matched[i];
1750
1751 for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
1752 if (c1 != c2)
1753 break;
1754
1755 if (lcd < 0)
1756 lcd = j;
1757 else
1758 {
1759 if (lcd > j)
1760 lcd = j;
1761 }
1762 }
1763 return lcd;
1764}
1765
1766/* Command line completion support. */
ajs274a4a42004-12-07 15:39:31 +00001767static char **
paulb92938a2002-12-13 21:20:42 +00001768cmd_complete_command_real (vector vline, struct vty *vty, int *status)
paul718e3742002-12-13 20:15:29 +00001769{
paulb8961472005-03-14 17:35:52 +00001770 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001771 vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1772#define INIT_MATCHVEC_SIZE 10
1773 vector matchvec;
1774 struct cmd_element *cmd_element;
paulb8961472005-03-14 17:35:52 +00001775 unsigned int index;
paul718e3742002-12-13 20:15:29 +00001776 char **match_str;
1777 struct desc *desc;
1778 vector descvec;
1779 char *command;
1780 int lcd;
1781
paul55468c82005-03-14 20:19:01 +00001782 if (vector_active (vline) == 0)
paulb8961472005-03-14 17:35:52 +00001783 {
1784 *status = CMD_ERR_NO_MATCH;
1785 return NULL;
1786 }
1787 else
paul55468c82005-03-14 20:19:01 +00001788 index = vector_active (vline) - 1;
paulb8961472005-03-14 17:35:52 +00001789
paul718e3742002-12-13 20:15:29 +00001790 /* First, filter by preceeding command string */
1791 for (i = 0; i < index; i++)
paulb8961472005-03-14 17:35:52 +00001792 if ((command = vector_slot (vline, i)))
paul909a2152005-03-14 17:41:45 +00001793 {
1794 enum match_type match;
1795 int ret;
paul718e3742002-12-13 20:15:29 +00001796
paul909a2152005-03-14 17:41:45 +00001797 /* First try completion match, if there is exactly match return 1 */
1798 match = cmd_filter_by_completion (command, cmd_vector, i);
paul718e3742002-12-13 20:15:29 +00001799
paul909a2152005-03-14 17:41:45 +00001800 /* If there is exact match then filter ambiguous match else check
1801 ambiguousness. */
1802 if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
1803 {
1804 vector_free (cmd_vector);
1805 *status = CMD_ERR_AMBIGUOUS;
1806 return NULL;
1807 }
1808 /*
1809 else if (ret == 2)
1810 {
1811 vector_free (cmd_vector);
1812 *status = CMD_ERR_NO_MATCH;
1813 return NULL;
1814 }
1815 */
1816 }
1817
paul718e3742002-12-13 20:15:29 +00001818 /* Prepare match vector. */
1819 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1820
1821 /* Now we got into completion */
paul55468c82005-03-14 20:19:01 +00001822 for (i = 0; i < vector_active (cmd_vector); i++)
paulb8961472005-03-14 17:35:52 +00001823 if ((cmd_element = vector_slot (cmd_vector, i)))
paul718e3742002-12-13 20:15:29 +00001824 {
hasso8c328f12004-10-05 21:01:23 +00001825 const char *string;
paul718e3742002-12-13 20:15:29 +00001826 vector strvec = cmd_element->strvec;
paul909a2152005-03-14 17:41:45 +00001827
paul718e3742002-12-13 20:15:29 +00001828 /* Check field length */
paul55468c82005-03-14 20:19:01 +00001829 if (index >= vector_active (strvec))
paul718e3742002-12-13 20:15:29 +00001830 vector_slot (cmd_vector, i) = NULL;
paul909a2152005-03-14 17:41:45 +00001831 else
paul718e3742002-12-13 20:15:29 +00001832 {
hasso8c328f12004-10-05 21:01:23 +00001833 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001834
1835 descvec = vector_slot (strvec, index);
paul55468c82005-03-14 20:19:01 +00001836 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001837 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001838 {
paulb8961472005-03-14 17:35:52 +00001839 if ((string =
1840 cmd_entry_function (vector_slot (vline, index),
paul909a2152005-03-14 17:41:45 +00001841 desc->cmd)))
1842 if (cmd_unique_string (matchvec, string))
1843 vector_set (matchvec, XSTRDUP (MTYPE_TMP, string));
1844 }
paul718e3742002-12-13 20:15:29 +00001845 }
1846 }
1847
1848 /* We don't need cmd_vector any more. */
1849 vector_free (cmd_vector);
1850
1851 /* No matched command */
1852 if (vector_slot (matchvec, 0) == NULL)
1853 {
1854 vector_free (matchvec);
1855
1856 /* In case of 'command \t' pattern. Do you need '?' command at
1857 the end of the line. */
1858 if (vector_slot (vline, index) == '\0')
1859 *status = CMD_ERR_NOTHING_TODO;
1860 else
1861 *status = CMD_ERR_NO_MATCH;
1862 return NULL;
1863 }
1864
1865 /* Only one matched */
1866 if (vector_slot (matchvec, 1) == NULL)
1867 {
1868 match_str = (char **) matchvec->index;
1869 vector_only_wrapper_free (matchvec);
1870 *status = CMD_COMPLETE_FULL_MATCH;
1871 return match_str;
1872 }
1873 /* Make it sure last element is NULL. */
1874 vector_set (matchvec, NULL);
1875
1876 /* Check LCD of matched strings. */
1877 if (vector_slot (vline, index) != NULL)
1878 {
1879 lcd = cmd_lcd ((char **) matchvec->index);
1880
1881 if (lcd)
1882 {
1883 int len = strlen (vector_slot (vline, index));
paul909a2152005-03-14 17:41:45 +00001884
paul718e3742002-12-13 20:15:29 +00001885 if (len < lcd)
1886 {
1887 char *lcdstr;
paul909a2152005-03-14 17:41:45 +00001888
paul718e3742002-12-13 20:15:29 +00001889 lcdstr = XMALLOC (MTYPE_TMP, lcd + 1);
1890 memcpy (lcdstr, matchvec->index[0], lcd);
1891 lcdstr[lcd] = '\0';
1892
1893 /* match_str = (char **) &lcdstr; */
1894
1895 /* Free matchvec. */
paul55468c82005-03-14 20:19:01 +00001896 for (i = 0; i < vector_active (matchvec); i++)
paul718e3742002-12-13 20:15:29 +00001897 {
1898 if (vector_slot (matchvec, i))
1899 XFREE (MTYPE_TMP, vector_slot (matchvec, i));
1900 }
1901 vector_free (matchvec);
1902
paul909a2152005-03-14 17:41:45 +00001903 /* Make new matchvec. */
paul718e3742002-12-13 20:15:29 +00001904 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1905 vector_set (matchvec, lcdstr);
1906 match_str = (char **) matchvec->index;
1907 vector_only_wrapper_free (matchvec);
1908
1909 *status = CMD_COMPLETE_MATCH;
1910 return match_str;
1911 }
1912 }
1913 }
1914
1915 match_str = (char **) matchvec->index;
1916 vector_only_wrapper_free (matchvec);
1917 *status = CMD_COMPLETE_LIST_MATCH;
1918 return match_str;
1919}
1920
paulb92938a2002-12-13 21:20:42 +00001921char **
paul9ab68122003-01-18 01:16:20 +00001922cmd_complete_command (vector vline, struct vty *vty, int *status)
paulb92938a2002-12-13 21:20:42 +00001923{
1924 char **ret;
1925
1926 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1927 {
1928 enum node_type onode;
1929 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00001930 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00001931
1932 onode = vty->node;
1933 vty->node = ENABLE_NODE;
1934 /* We can try it on enable node, cos' the vty is authenticated */
1935
1936 shifted_vline = vector_init (vector_count(vline));
1937 /* use memcpy? */
paul55468c82005-03-14 20:19:01 +00001938 for (index = 1; index < vector_active (vline); index++)
paulb92938a2002-12-13 21:20:42 +00001939 {
1940 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1941 }
1942
1943 ret = cmd_complete_command_real (shifted_vline, vty, status);
1944
1945 vector_free(shifted_vline);
1946 vty->node = onode;
1947 return ret;
1948 }
1949
1950
1951 return cmd_complete_command_real (vline, vty, status);
1952}
1953
1954/* return parent node */
1955/* MUST eventually converge on CONFIG_NODE */
hasso13bfca72005-01-23 21:42:25 +00001956enum node_type
ajs274a4a42004-12-07 15:39:31 +00001957node_parent ( enum node_type node )
paulb92938a2002-12-13 21:20:42 +00001958{
1959 enum node_type ret;
1960
paul9ab68122003-01-18 01:16:20 +00001961 assert (node > CONFIG_NODE);
1962
1963 switch (node)
1964 {
1965 case BGP_VPNV4_NODE:
1966 case BGP_IPV4_NODE:
1967 case BGP_IPV4M_NODE:
1968 case BGP_IPV6_NODE:
paul1e836592005-08-22 22:39:56 +00001969 case BGP_IPV6M_NODE:
paul9ab68122003-01-18 01:16:20 +00001970 ret = BGP_NODE;
1971 break;
1972 case KEYCHAIN_KEY_NODE:
1973 ret = KEYCHAIN_NODE;
1974 break;
1975 default:
1976 ret = CONFIG_NODE;
paulb92938a2002-12-13 21:20:42 +00001977 }
1978
1979 return ret;
1980}
1981
paul718e3742002-12-13 20:15:29 +00001982/* Execute command by argument vline vector. */
ajs274a4a42004-12-07 15:39:31 +00001983static int
paulb8961472005-03-14 17:35:52 +00001984cmd_execute_command_real (vector vline, struct vty *vty,
1985 struct cmd_element **cmd)
paul718e3742002-12-13 20:15:29 +00001986{
hasso8c328f12004-10-05 21:01:23 +00001987 unsigned int i;
1988 unsigned int index;
paul718e3742002-12-13 20:15:29 +00001989 vector cmd_vector;
1990 struct cmd_element *cmd_element;
1991 struct cmd_element *matched_element;
1992 unsigned int matched_count, incomplete_count;
1993 int argc;
paul9035efa2004-10-10 11:56:56 +00001994 const char *argv[CMD_ARGC_MAX];
paul718e3742002-12-13 20:15:29 +00001995 enum match_type match = 0;
1996 int varflag;
1997 char *command;
1998
1999 /* Make copy of command elements. */
2000 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2001
paul55468c82005-03-14 20:19:01 +00002002 for (index = 0; index < vector_active (vline); index++)
paulb8961472005-03-14 17:35:52 +00002003 if ((command = vector_slot (vline, index)))
paul909a2152005-03-14 17:41:45 +00002004 {
2005 int ret;
paul718e3742002-12-13 20:15:29 +00002006
paul909a2152005-03-14 17:41:45 +00002007 match = cmd_filter_by_completion (command, cmd_vector, index);
paul718e3742002-12-13 20:15:29 +00002008
paul909a2152005-03-14 17:41:45 +00002009 if (match == vararg_match)
2010 break;
2011
2012 ret = is_cmd_ambiguous (command, cmd_vector, index, match);
paul718e3742002-12-13 20:15:29 +00002013
paul909a2152005-03-14 17:41:45 +00002014 if (ret == 1)
2015 {
2016 vector_free (cmd_vector);
2017 return CMD_ERR_AMBIGUOUS;
2018 }
2019 else if (ret == 2)
2020 {
2021 vector_free (cmd_vector);
2022 return CMD_ERR_NO_MATCH;
2023 }
2024 }
paul718e3742002-12-13 20:15:29 +00002025
2026 /* Check matched count. */
2027 matched_element = NULL;
2028 matched_count = 0;
2029 incomplete_count = 0;
2030
paul55468c82005-03-14 20:19:01 +00002031 for (i = 0; i < vector_active (cmd_vector); i++)
paulb8961472005-03-14 17:35:52 +00002032 if ((cmd_element = vector_slot (cmd_vector, i)))
paul718e3742002-12-13 20:15:29 +00002033 {
paul718e3742002-12-13 20:15:29 +00002034 if (match == vararg_match || index >= cmd_element->cmdsize)
2035 {
2036 matched_element = cmd_element;
2037#if 0
2038 printf ("DEBUG: %s\n", cmd_element->string);
2039#endif
2040 matched_count++;
2041 }
2042 else
2043 {
2044 incomplete_count++;
2045 }
2046 }
paul909a2152005-03-14 17:41:45 +00002047
paul718e3742002-12-13 20:15:29 +00002048 /* Finish of using cmd_vector. */
2049 vector_free (cmd_vector);
2050
paul909a2152005-03-14 17:41:45 +00002051 /* To execute command, matched_count must be 1. */
2052 if (matched_count == 0)
paul718e3742002-12-13 20:15:29 +00002053 {
2054 if (incomplete_count)
2055 return CMD_ERR_INCOMPLETE;
2056 else
2057 return CMD_ERR_NO_MATCH;
2058 }
2059
paul909a2152005-03-14 17:41:45 +00002060 if (matched_count > 1)
paul718e3742002-12-13 20:15:29 +00002061 return CMD_ERR_AMBIGUOUS;
2062
2063 /* Argument treatment */
2064 varflag = 0;
2065 argc = 0;
2066
paul55468c82005-03-14 20:19:01 +00002067 for (i = 0; i < vector_active (vline); i++)
paul718e3742002-12-13 20:15:29 +00002068 {
2069 if (varflag)
2070 argv[argc++] = vector_slot (vline, i);
2071 else
paul909a2152005-03-14 17:41:45 +00002072 {
paul718e3742002-12-13 20:15:29 +00002073 vector descvec = vector_slot (matched_element->strvec, i);
2074
paul55468c82005-03-14 20:19:01 +00002075 if (vector_active (descvec) == 1)
paul718e3742002-12-13 20:15:29 +00002076 {
2077 struct desc *desc = vector_slot (descvec, 0);
paul718e3742002-12-13 20:15:29 +00002078
hasso8c328f12004-10-05 21:01:23 +00002079 if (CMD_VARARG (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002080 varflag = 1;
2081
hasso8c328f12004-10-05 21:01:23 +00002082 if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002083 argv[argc++] = vector_slot (vline, i);
2084 }
2085 else
2086 argv[argc++] = vector_slot (vline, i);
2087 }
2088
2089 if (argc >= CMD_ARGC_MAX)
2090 return CMD_ERR_EXEED_ARGC_MAX;
2091 }
2092
2093 /* For vtysh execution. */
2094 if (cmd)
2095 *cmd = matched_element;
2096
2097 if (matched_element->daemon)
2098 return CMD_SUCCESS_DAEMON;
2099
2100 /* Execute matched command. */
2101 return (*matched_element->func) (matched_element, vty, argc, argv);
2102}
2103
paulb92938a2002-12-13 21:20:42 +00002104int
hasso87d683b2005-01-16 23:31:54 +00002105cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,
2106 int vtysh) {
paul9ab68122003-01-18 01:16:20 +00002107 int ret, saved_ret, tried = 0;
2108 enum node_type onode, try_node;
2109
2110 onode = try_node = vty->node;
paulb92938a2002-12-13 21:20:42 +00002111
2112 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
2113 {
2114 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00002115 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00002116
2117 vty->node = ENABLE_NODE;
2118 /* We can try it on enable node, cos' the vty is authenticated */
2119
2120 shifted_vline = vector_init (vector_count(vline));
2121 /* use memcpy? */
paul55468c82005-03-14 20:19:01 +00002122 for (index = 1; index < vector_active (vline); index++)
paulb92938a2002-12-13 21:20:42 +00002123 {
2124 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
2125 }
2126
2127 ret = cmd_execute_command_real (shifted_vline, vty, cmd);
2128
2129 vector_free(shifted_vline);
2130 vty->node = onode;
2131 return ret;
2132 }
2133
2134
paul9ab68122003-01-18 01:16:20 +00002135 saved_ret = ret = cmd_execute_command_real (vline, vty, cmd);
paulb92938a2002-12-13 21:20:42 +00002136
hasso87d683b2005-01-16 23:31:54 +00002137 if (vtysh)
2138 return saved_ret;
2139
paulb92938a2002-12-13 21:20:42 +00002140 /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
paul9ab68122003-01-18 01:16:20 +00002141 while ( ret != CMD_SUCCESS && ret != CMD_WARNING
paulb92938a2002-12-13 21:20:42 +00002142 && vty->node > CONFIG_NODE )
2143 {
paul9ab68122003-01-18 01:16:20 +00002144 try_node = node_parent(try_node);
2145 vty->node = try_node;
paulb92938a2002-12-13 21:20:42 +00002146 ret = cmd_execute_command_real (vline, vty, cmd);
paul9ab68122003-01-18 01:16:20 +00002147 tried = 1;
2148 if (ret == CMD_SUCCESS || ret == CMD_WARNING)
paulb92938a2002-12-13 21:20:42 +00002149 {
paul9ab68122003-01-18 01:16:20 +00002150 /* succesfull command, leave the node as is */
paulb92938a2002-12-13 21:20:42 +00002151 return ret;
2152 }
paulb92938a2002-12-13 21:20:42 +00002153 }
paul9ab68122003-01-18 01:16:20 +00002154 /* no command succeeded, reset the vty to the original node and
2155 return the error for this node */
2156 if ( tried )
2157 vty->node = onode;
2158 return saved_ret;
pauleda031f2003-01-18 00:39:19 +00002159}
2160
paul718e3742002-12-13 20:15:29 +00002161/* Execute command by argument readline. */
2162int
paul909a2152005-03-14 17:41:45 +00002163cmd_execute_command_strict (vector vline, struct vty *vty,
paul718e3742002-12-13 20:15:29 +00002164 struct cmd_element **cmd)
2165{
hasso8c328f12004-10-05 21:01:23 +00002166 unsigned int i;
2167 unsigned int index;
paul718e3742002-12-13 20:15:29 +00002168 vector cmd_vector;
2169 struct cmd_element *cmd_element;
2170 struct cmd_element *matched_element;
2171 unsigned int matched_count, incomplete_count;
2172 int argc;
paul9035efa2004-10-10 11:56:56 +00002173 const char *argv[CMD_ARGC_MAX];
paul718e3742002-12-13 20:15:29 +00002174 int varflag;
2175 enum match_type match = 0;
2176 char *command;
2177
2178 /* Make copy of command element */
2179 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2180
paul55468c82005-03-14 20:19:01 +00002181 for (index = 0; index < vector_active (vline); index++)
paulb8961472005-03-14 17:35:52 +00002182 if ((command = vector_slot (vline, index)))
paul909a2152005-03-14 17:41:45 +00002183 {
2184 int ret;
2185
2186 match = cmd_filter_by_string (vector_slot (vline, index),
2187 cmd_vector, index);
paul718e3742002-12-13 20:15:29 +00002188
paul909a2152005-03-14 17:41:45 +00002189 /* If command meets '.VARARG' then finish matching. */
2190 if (match == vararg_match)
2191 break;
2192
2193 ret = is_cmd_ambiguous (command, cmd_vector, index, match);
2194 if (ret == 1)
2195 {
2196 vector_free (cmd_vector);
2197 return CMD_ERR_AMBIGUOUS;
2198 }
2199 if (ret == 2)
2200 {
2201 vector_free (cmd_vector);
2202 return CMD_ERR_NO_MATCH;
2203 }
2204 }
paul718e3742002-12-13 20:15:29 +00002205
2206 /* Check matched count. */
2207 matched_element = NULL;
2208 matched_count = 0;
2209 incomplete_count = 0;
paul55468c82005-03-14 20:19:01 +00002210 for (i = 0; i < vector_active (cmd_vector); i++)
paul909a2152005-03-14 17:41:45 +00002211 if (vector_slot (cmd_vector, i) != NULL)
paul718e3742002-12-13 20:15:29 +00002212 {
paul909a2152005-03-14 17:41:45 +00002213 cmd_element = vector_slot (cmd_vector, i);
paul718e3742002-12-13 20:15:29 +00002214
2215 if (match == vararg_match || index >= cmd_element->cmdsize)
2216 {
2217 matched_element = cmd_element;
2218 matched_count++;
2219 }
2220 else
2221 incomplete_count++;
2222 }
paul909a2152005-03-14 17:41:45 +00002223
paul718e3742002-12-13 20:15:29 +00002224 /* Finish of using cmd_vector. */
2225 vector_free (cmd_vector);
2226
paul909a2152005-03-14 17:41:45 +00002227 /* To execute command, matched_count must be 1. */
2228 if (matched_count == 0)
paul718e3742002-12-13 20:15:29 +00002229 {
2230 if (incomplete_count)
2231 return CMD_ERR_INCOMPLETE;
2232 else
2233 return CMD_ERR_NO_MATCH;
2234 }
2235
paul909a2152005-03-14 17:41:45 +00002236 if (matched_count > 1)
paul718e3742002-12-13 20:15:29 +00002237 return CMD_ERR_AMBIGUOUS;
2238
2239 /* Argument treatment */
2240 varflag = 0;
2241 argc = 0;
2242
paul55468c82005-03-14 20:19:01 +00002243 for (i = 0; i < vector_active (vline); i++)
paul718e3742002-12-13 20:15:29 +00002244 {
2245 if (varflag)
2246 argv[argc++] = vector_slot (vline, i);
2247 else
paul909a2152005-03-14 17:41:45 +00002248 {
paul718e3742002-12-13 20:15:29 +00002249 vector descvec = vector_slot (matched_element->strvec, i);
2250
paul55468c82005-03-14 20:19:01 +00002251 if (vector_active (descvec) == 1)
paul718e3742002-12-13 20:15:29 +00002252 {
2253 struct desc *desc = vector_slot (descvec, 0);
paul718e3742002-12-13 20:15:29 +00002254
hasso8c328f12004-10-05 21:01:23 +00002255 if (CMD_VARARG (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002256 varflag = 1;
paul909a2152005-03-14 17:41:45 +00002257
hasso8c328f12004-10-05 21:01:23 +00002258 if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002259 argv[argc++] = vector_slot (vline, i);
2260 }
2261 else
2262 argv[argc++] = vector_slot (vline, i);
2263 }
2264
2265 if (argc >= CMD_ARGC_MAX)
2266 return CMD_ERR_EXEED_ARGC_MAX;
2267 }
2268
2269 /* For vtysh execution. */
2270 if (cmd)
2271 *cmd = matched_element;
2272
2273 if (matched_element->daemon)
2274 return CMD_SUCCESS_DAEMON;
2275
2276 /* Now execute matched command */
2277 return (*matched_element->func) (matched_element, vty, argc, argv);
2278}
2279
2280/* Configration make from file. */
2281int
2282config_from_file (struct vty *vty, FILE *fp)
2283{
2284 int ret;
2285 vector vline;
2286
2287 while (fgets (vty->buf, VTY_BUFSIZ, fp))
2288 {
2289 vline = cmd_make_strvec (vty->buf);
2290
2291 /* In case of comment line */
2292 if (vline == NULL)
2293 continue;
2294 /* Execute configuration command : this is strict match */
2295 ret = cmd_execute_command_strict (vline, vty, NULL);
2296
2297 /* Try again with setting node to CONFIG_NODE */
paulb92938a2002-12-13 21:20:42 +00002298 while (ret != CMD_SUCCESS && ret != CMD_WARNING
hassoddd85ed2004-10-13 08:18:07 +00002299 && ret != CMD_ERR_NOTHING_TODO && vty->node != CONFIG_NODE)
2300 {
paulb92938a2002-12-13 21:20:42 +00002301 vty->node = node_parent(vty->node);
hassoddd85ed2004-10-13 08:18:07 +00002302 ret = cmd_execute_command_strict (vline, vty, NULL);
2303 }
paul9ab68122003-01-18 01:16:20 +00002304
paul718e3742002-12-13 20:15:29 +00002305 cmd_free_strvec (vline);
2306
hassoddd85ed2004-10-13 08:18:07 +00002307 if (ret != CMD_SUCCESS && ret != CMD_WARNING
2308 && ret != CMD_ERR_NOTHING_TODO)
paul718e3742002-12-13 20:15:29 +00002309 return ret;
2310 }
2311 return CMD_SUCCESS;
2312}
2313
2314/* Configration from terminal */
2315DEFUN (config_terminal,
2316 config_terminal_cmd,
2317 "configure terminal",
2318 "Configuration from vty interface\n"
2319 "Configuration terminal\n")
2320{
2321 if (vty_config_lock (vty))
2322 vty->node = CONFIG_NODE;
2323 else
2324 {
2325 vty_out (vty, "VTY configuration is locked by other VTY%s", VTY_NEWLINE);
2326 return CMD_WARNING;
2327 }
2328 return CMD_SUCCESS;
2329}
2330
2331/* Enable command */
2332DEFUN (enable,
2333 config_enable_cmd,
2334 "enable",
2335 "Turn on privileged mode command\n")
2336{
2337 /* If enable password is NULL, change to ENABLE_NODE */
2338 if ((host.enable == NULL && host.enable_encrypt == NULL) ||
2339 vty->type == VTY_SHELL_SERV)
2340 vty->node = ENABLE_NODE;
2341 else
2342 vty->node = AUTH_ENABLE_NODE;
2343
2344 return CMD_SUCCESS;
2345}
2346
2347/* Disable command */
2348DEFUN (disable,
2349 config_disable_cmd,
2350 "disable",
2351 "Turn off privileged mode command\n")
2352{
2353 if (vty->node == ENABLE_NODE)
2354 vty->node = VIEW_NODE;
2355 return CMD_SUCCESS;
2356}
2357
2358/* Down vty node level. */
2359DEFUN (config_exit,
2360 config_exit_cmd,
2361 "exit",
2362 "Exit current mode and down to previous mode\n")
2363{
2364 switch (vty->node)
2365 {
2366 case VIEW_NODE:
2367 case ENABLE_NODE:
2368 if (vty_shell (vty))
2369 exit (0);
2370 else
2371 vty->status = VTY_CLOSE;
2372 break;
2373 case CONFIG_NODE:
2374 vty->node = ENABLE_NODE;
2375 vty_config_unlock (vty);
2376 break;
2377 case INTERFACE_NODE:
2378 case ZEBRA_NODE:
2379 case BGP_NODE:
2380 case RIP_NODE:
2381 case RIPNG_NODE:
2382 case OSPF_NODE:
2383 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00002384 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00002385 case KEYCHAIN_NODE:
2386 case MASC_NODE:
2387 case RMAP_NODE:
2388 case VTY_NODE:
2389 vty->node = CONFIG_NODE;
2390 break;
2391 case BGP_VPNV4_NODE:
2392 case BGP_IPV4_NODE:
2393 case BGP_IPV4M_NODE:
2394 case BGP_IPV6_NODE:
paul1e836592005-08-22 22:39:56 +00002395 case BGP_IPV6M_NODE:
paul718e3742002-12-13 20:15:29 +00002396 vty->node = BGP_NODE;
2397 break;
2398 case KEYCHAIN_KEY_NODE:
2399 vty->node = KEYCHAIN_NODE;
2400 break;
2401 default:
2402 break;
2403 }
2404 return CMD_SUCCESS;
2405}
2406
2407/* quit is alias of exit. */
2408ALIAS (config_exit,
2409 config_quit_cmd,
2410 "quit",
2411 "Exit current mode and down to previous mode\n")
2412
2413/* End of configuration. */
2414DEFUN (config_end,
2415 config_end_cmd,
2416 "end",
2417 "End current mode and change to enable mode.")
2418{
2419 switch (vty->node)
2420 {
2421 case VIEW_NODE:
2422 case ENABLE_NODE:
2423 /* Nothing to do. */
2424 break;
2425 case CONFIG_NODE:
2426 case INTERFACE_NODE:
2427 case ZEBRA_NODE:
2428 case RIP_NODE:
2429 case RIPNG_NODE:
2430 case BGP_NODE:
2431 case BGP_VPNV4_NODE:
2432 case BGP_IPV4_NODE:
2433 case BGP_IPV4M_NODE:
2434 case BGP_IPV6_NODE:
paul1e836592005-08-22 22:39:56 +00002435 case BGP_IPV6M_NODE:
paul718e3742002-12-13 20:15:29 +00002436 case RMAP_NODE:
2437 case OSPF_NODE:
2438 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00002439 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00002440 case KEYCHAIN_NODE:
2441 case KEYCHAIN_KEY_NODE:
2442 case MASC_NODE:
2443 case VTY_NODE:
2444 vty_config_unlock (vty);
2445 vty->node = ENABLE_NODE;
2446 break;
2447 default:
2448 break;
2449 }
2450 return CMD_SUCCESS;
2451}
2452
2453/* Show version. */
2454DEFUN (show_version,
2455 show_version_cmd,
2456 "show version",
2457 SHOW_STR
2458 "Displays zebra version\n")
2459{
hasso12f6ea22005-03-07 08:35:39 +00002460 vty_out (vty, "Quagga %s (%s).%s", QUAGGA_VERSION, host.name?host.name:"",
2461 VTY_NEWLINE);
hasso6590f2c2004-10-19 20:40:08 +00002462 vty_out (vty, "%s%s", QUAGGA_COPYRIGHT, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00002463
2464 return CMD_SUCCESS;
2465}
2466
2467/* Help display function for all node. */
2468DEFUN (config_help,
2469 config_help_cmd,
2470 "help",
2471 "Description of the interactive help system\n")
2472{
2473 vty_out (vty,
hasso6590f2c2004-10-19 20:40:08 +00002474 "Quagga VTY provides advanced help feature. When you need help,%s\
paul718e3742002-12-13 20:15:29 +00002475anytime at the command line please press '?'.%s\
2476%s\
2477If nothing matches, the help list will be empty and you must backup%s\
2478 until entering a '?' shows the available options.%s\
2479Two styles of help are provided:%s\
24801. Full help is available when you are ready to enter a%s\
2481command argument (e.g. 'show ?') and describes each possible%s\
2482argument.%s\
24832. Partial help is provided when an abbreviated argument is entered%s\
2484 and you want to know what arguments match the input%s\
2485 (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2486 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2487 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
2488 return CMD_SUCCESS;
2489}
2490
2491/* Help display function for all node. */
2492DEFUN (config_list,
2493 config_list_cmd,
2494 "list",
2495 "Print command list\n")
2496{
hasso8c328f12004-10-05 21:01:23 +00002497 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002498 struct cmd_node *cnode = vector_slot (cmdvec, vty->node);
2499 struct cmd_element *cmd;
2500
paul55468c82005-03-14 20:19:01 +00002501 for (i = 0; i < vector_active (cnode->cmd_vector); i++)
paul4275b1d2005-03-09 13:42:23 +00002502 if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL
2503 && !(cmd->attr == CMD_ATTR_DEPRECATED
2504 || cmd->attr == CMD_ATTR_HIDDEN))
paul718e3742002-12-13 20:15:29 +00002505 vty_out (vty, " %s%s", cmd->string,
2506 VTY_NEWLINE);
2507 return CMD_SUCCESS;
2508}
2509
2510/* Write current configuration into file. */
2511DEFUN (config_write_file,
2512 config_write_file_cmd,
2513 "write file",
2514 "Write running configuration to memory, network, or terminal\n"
2515 "Write to configuration file\n")
2516{
hasso8c328f12004-10-05 21:01:23 +00002517 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002518 int fd;
2519 struct cmd_node *node;
2520 char *config_file;
2521 char *config_file_tmp = NULL;
2522 char *config_file_sav = NULL;
2523 struct vty *file_vty;
2524
2525 /* Check and see if we are operating under vtysh configuration */
2526 if (host.config == NULL)
2527 {
2528 vty_out (vty, "Can't save to configuration file, using vtysh.%s",
2529 VTY_NEWLINE);
2530 return CMD_WARNING;
2531 }
2532
2533 /* Get filename. */
2534 config_file = host.config;
2535
2536 config_file_sav = malloc (strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
2537 strcpy (config_file_sav, config_file);
2538 strcat (config_file_sav, CONF_BACKUP_EXT);
2539
2540
2541 config_file_tmp = malloc (strlen (config_file) + 8);
2542 sprintf (config_file_tmp, "%s.XXXXXX", config_file);
2543
2544 /* Open file to configuration write. */
2545 fd = mkstemp (config_file_tmp);
2546 if (fd < 0)
2547 {
2548 vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
2549 VTY_NEWLINE);
2550 free (config_file_tmp);
2551 free (config_file_sav);
2552 return CMD_WARNING;
2553 }
2554
2555 /* Make vty for configuration file. */
2556 file_vty = vty_new ();
2557 file_vty->fd = fd;
2558 file_vty->type = VTY_FILE;
2559
2560 /* Config file header print. */
2561 vty_out (file_vty, "!\n! Zebra configuration saved from vty\n! ");
2562 vty_time_print (file_vty, 1);
2563 vty_out (file_vty, "!\n");
2564
paul55468c82005-03-14 20:19:01 +00002565 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +00002566 if ((node = vector_slot (cmdvec, i)) && node->func)
2567 {
2568 if ((*node->func) (file_vty))
2569 vty_out (file_vty, "!\n");
2570 }
2571 vty_close (file_vty);
2572
2573 if (unlink (config_file_sav) != 0)
2574 if (errno != ENOENT)
2575 {
2576 vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
2577 VTY_NEWLINE);
2578 free (config_file_sav);
2579 free (config_file_tmp);
2580 unlink (config_file_tmp);
2581 return CMD_WARNING;
2582 }
2583 if (link (config_file, config_file_sav) != 0)
2584 {
2585 vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
2586 VTY_NEWLINE);
2587 free (config_file_sav);
2588 free (config_file_tmp);
2589 unlink (config_file_tmp);
2590 return CMD_WARNING;
2591 }
2592 sync ();
2593 if (unlink (config_file) != 0)
2594 {
2595 vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
2596 VTY_NEWLINE);
2597 free (config_file_sav);
2598 free (config_file_tmp);
2599 unlink (config_file_tmp);
2600 return CMD_WARNING;
2601 }
2602 if (link (config_file_tmp, config_file) != 0)
2603 {
2604 vty_out (vty, "Can't save configuration file %s.%s", config_file,
2605 VTY_NEWLINE);
2606 free (config_file_sav);
2607 free (config_file_tmp);
2608 unlink (config_file_tmp);
2609 return CMD_WARNING;
2610 }
2611 unlink (config_file_tmp);
2612 sync ();
2613
2614 free (config_file_sav);
2615 free (config_file_tmp);
gdtaa593d52003-12-22 20:15:53 +00002616
2617 if (chmod (config_file, CONFIGFILE_MASK) != 0)
2618 {
2619 vty_out (vty, "Can't chmod configuration file %s: %s (%d).%s",
ajs6099b3b2004-11-20 02:06:59 +00002620 config_file, safe_strerror(errno), errno, VTY_NEWLINE);
gdtaa593d52003-12-22 20:15:53 +00002621 return CMD_WARNING;
2622 }
2623
paul718e3742002-12-13 20:15:29 +00002624 vty_out (vty, "Configuration saved to %s%s", config_file,
2625 VTY_NEWLINE);
2626 return CMD_SUCCESS;
2627}
2628
2629ALIAS (config_write_file,
2630 config_write_cmd,
2631 "write",
2632 "Write running configuration to memory, network, or terminal\n")
2633
2634ALIAS (config_write_file,
2635 config_write_memory_cmd,
2636 "write memory",
2637 "Write running configuration to memory, network, or terminal\n"
2638 "Write configuration to the file (same as write file)\n")
2639
2640ALIAS (config_write_file,
2641 copy_runningconfig_startupconfig_cmd,
2642 "copy running-config startup-config",
2643 "Copy configuration\n"
2644 "Copy running config to... \n"
2645 "Copy running config to startup config (same as write file)\n")
2646
2647/* Write current configuration into the terminal. */
2648DEFUN (config_write_terminal,
2649 config_write_terminal_cmd,
2650 "write terminal",
2651 "Write running configuration to memory, network, or terminal\n"
2652 "Write to terminal\n")
2653{
hasso8c328f12004-10-05 21:01:23 +00002654 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002655 struct cmd_node *node;
2656
2657 if (vty->type == VTY_SHELL_SERV)
2658 {
paul55468c82005-03-14 20:19:01 +00002659 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +00002660 if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
2661 {
2662 if ((*node->func) (vty))
2663 vty_out (vty, "!%s", VTY_NEWLINE);
2664 }
2665 }
2666 else
2667 {
2668 vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
2669 VTY_NEWLINE);
2670 vty_out (vty, "!%s", VTY_NEWLINE);
2671
paul55468c82005-03-14 20:19:01 +00002672 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +00002673 if ((node = vector_slot (cmdvec, i)) && node->func)
2674 {
2675 if ((*node->func) (vty))
2676 vty_out (vty, "!%s", VTY_NEWLINE);
2677 }
2678 vty_out (vty, "end%s",VTY_NEWLINE);
2679 }
2680 return CMD_SUCCESS;
2681}
2682
2683/* Write current configuration into the terminal. */
2684ALIAS (config_write_terminal,
2685 show_running_config_cmd,
2686 "show running-config",
2687 SHOW_STR
2688 "running configuration\n")
2689
2690/* Write startup configuration into the terminal. */
2691DEFUN (show_startup_config,
2692 show_startup_config_cmd,
2693 "show startup-config",
2694 SHOW_STR
2695 "Contentes of startup configuration\n")
2696{
2697 char buf[BUFSIZ];
2698 FILE *confp;
2699
2700 confp = fopen (host.config, "r");
2701 if (confp == NULL)
2702 {
2703 vty_out (vty, "Can't open configuration file [%s]%s",
2704 host.config, VTY_NEWLINE);
2705 return CMD_WARNING;
2706 }
2707
2708 while (fgets (buf, BUFSIZ, confp))
2709 {
2710 char *cp = buf;
2711
2712 while (*cp != '\r' && *cp != '\n' && *cp != '\0')
2713 cp++;
2714 *cp = '\0';
2715
2716 vty_out (vty, "%s%s", buf, VTY_NEWLINE);
2717 }
2718
2719 fclose (confp);
2720
2721 return CMD_SUCCESS;
2722}
2723
2724/* Hostname configuration */
2725DEFUN (config_hostname,
2726 hostname_cmd,
2727 "hostname WORD",
2728 "Set system's network name\n"
2729 "This system's network name\n")
2730{
2731 if (!isalpha((int) *argv[0]))
2732 {
2733 vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
2734 return CMD_WARNING;
2735 }
2736
2737 if (host.name)
2738 XFREE (0, host.name);
2739
2740 host.name = strdup (argv[0]);
2741 return CMD_SUCCESS;
2742}
2743
2744DEFUN (config_no_hostname,
2745 no_hostname_cmd,
2746 "no hostname [HOSTNAME]",
2747 NO_STR
2748 "Reset system's network name\n"
2749 "Host name of this router\n")
2750{
2751 if (host.name)
2752 XFREE (0, host.name);
2753 host.name = NULL;
2754 return CMD_SUCCESS;
2755}
2756
2757/* VTY interface password set. */
2758DEFUN (config_password, password_cmd,
2759 "password (8|) WORD",
2760 "Assign the terminal connection password\n"
2761 "Specifies a HIDDEN password will follow\n"
2762 "dummy string \n"
2763 "The HIDDEN line password string\n")
2764{
2765 /* Argument check. */
2766 if (argc == 0)
2767 {
2768 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2769 return CMD_WARNING;
2770 }
2771
2772 if (argc == 2)
2773 {
2774 if (*argv[0] == '8')
2775 {
2776 if (host.password)
2777 XFREE (0, host.password);
2778 host.password = NULL;
2779 if (host.password_encrypt)
2780 XFREE (0, host.password_encrypt);
2781 host.password_encrypt = XSTRDUP (0, strdup (argv[1]));
2782 return CMD_SUCCESS;
2783 }
2784 else
2785 {
2786 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2787 return CMD_WARNING;
2788 }
2789 }
2790
2791 if (!isalnum ((int) *argv[0]))
2792 {
2793 vty_out (vty,
2794 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2795 return CMD_WARNING;
2796 }
2797
2798 if (host.password)
2799 XFREE (0, host.password);
2800 host.password = NULL;
2801
2802 if (host.encrypt)
2803 {
2804 if (host.password_encrypt)
2805 XFREE (0, host.password_encrypt);
2806 host.password_encrypt = XSTRDUP (0, zencrypt (argv[0]));
2807 }
2808 else
2809 host.password = XSTRDUP (0, argv[0]);
2810
2811 return CMD_SUCCESS;
2812}
2813
2814ALIAS (config_password, password_text_cmd,
2815 "password LINE",
2816 "Assign the terminal connection password\n"
2817 "The UNENCRYPTED (cleartext) line password\n")
2818
2819/* VTY enable password set. */
2820DEFUN (config_enable_password, enable_password_cmd,
2821 "enable password (8|) WORD",
2822 "Modify enable password parameters\n"
2823 "Assign the privileged level password\n"
2824 "Specifies a HIDDEN password will follow\n"
2825 "dummy string \n"
2826 "The HIDDEN 'enable' password string\n")
2827{
2828 /* Argument check. */
2829 if (argc == 0)
2830 {
2831 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2832 return CMD_WARNING;
2833 }
2834
2835 /* Crypt type is specified. */
2836 if (argc == 2)
2837 {
2838 if (*argv[0] == '8')
2839 {
2840 if (host.enable)
2841 XFREE (0, host.enable);
2842 host.enable = NULL;
2843
2844 if (host.enable_encrypt)
2845 XFREE (0, host.enable_encrypt);
2846 host.enable_encrypt = XSTRDUP (0, argv[1]);
2847
2848 return CMD_SUCCESS;
2849 }
2850 else
2851 {
2852 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2853 return CMD_WARNING;
2854 }
2855 }
2856
2857 if (!isalnum ((int) *argv[0]))
2858 {
2859 vty_out (vty,
2860 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2861 return CMD_WARNING;
2862 }
2863
2864 if (host.enable)
2865 XFREE (0, host.enable);
2866 host.enable = NULL;
2867
2868 /* Plain password input. */
2869 if (host.encrypt)
2870 {
2871 if (host.enable_encrypt)
2872 XFREE (0, host.enable_encrypt);
2873 host.enable_encrypt = XSTRDUP (0, zencrypt (argv[0]));
2874 }
2875 else
2876 host.enable = XSTRDUP (0, argv[0]);
2877
2878 return CMD_SUCCESS;
2879}
2880
2881ALIAS (config_enable_password,
2882 enable_password_text_cmd,
2883 "enable password LINE",
2884 "Modify enable password parameters\n"
2885 "Assign the privileged level password\n"
2886 "The UNENCRYPTED (cleartext) 'enable' password\n")
2887
2888/* VTY enable password delete. */
2889DEFUN (no_config_enable_password, no_enable_password_cmd,
2890 "no enable password",
2891 NO_STR
2892 "Modify enable password parameters\n"
2893 "Assign the privileged level password\n")
2894{
2895 if (host.enable)
2896 XFREE (0, host.enable);
2897 host.enable = NULL;
2898
2899 if (host.enable_encrypt)
2900 XFREE (0, host.enable_encrypt);
2901 host.enable_encrypt = NULL;
2902
2903 return CMD_SUCCESS;
2904}
2905
2906DEFUN (service_password_encrypt,
2907 service_password_encrypt_cmd,
2908 "service password-encryption",
2909 "Set up miscellaneous service\n"
2910 "Enable encrypted passwords\n")
2911{
2912 if (host.encrypt)
2913 return CMD_SUCCESS;
2914
2915 host.encrypt = 1;
2916
2917 if (host.password)
2918 {
2919 if (host.password_encrypt)
2920 XFREE (0, host.password_encrypt);
2921 host.password_encrypt = XSTRDUP (0, zencrypt (host.password));
2922 }
2923 if (host.enable)
2924 {
2925 if (host.enable_encrypt)
2926 XFREE (0, host.enable_encrypt);
2927 host.enable_encrypt = XSTRDUP (0, zencrypt (host.enable));
2928 }
2929
2930 return CMD_SUCCESS;
2931}
2932
2933DEFUN (no_service_password_encrypt,
2934 no_service_password_encrypt_cmd,
2935 "no service password-encryption",
2936 NO_STR
2937 "Set up miscellaneous service\n"
2938 "Enable encrypted passwords\n")
2939{
2940 if (! host.encrypt)
2941 return CMD_SUCCESS;
2942
2943 host.encrypt = 0;
2944
2945 if (host.password_encrypt)
2946 XFREE (0, host.password_encrypt);
2947 host.password_encrypt = NULL;
2948
2949 if (host.enable_encrypt)
2950 XFREE (0, host.enable_encrypt);
2951 host.enable_encrypt = NULL;
2952
2953 return CMD_SUCCESS;
2954}
2955
2956DEFUN (config_terminal_length, config_terminal_length_cmd,
2957 "terminal length <0-512>",
2958 "Set terminal line parameters\n"
2959 "Set number of lines on a screen\n"
2960 "Number of lines on screen (0 for no pausing)\n")
2961{
2962 int lines;
2963 char *endptr = NULL;
2964
2965 lines = strtol (argv[0], &endptr, 10);
2966 if (lines < 0 || lines > 512 || *endptr != '\0')
2967 {
2968 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2969 return CMD_WARNING;
2970 }
2971 vty->lines = lines;
2972
2973 return CMD_SUCCESS;
2974}
2975
2976DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
2977 "terminal no length",
2978 "Set terminal line parameters\n"
2979 NO_STR
2980 "Set number of lines on a screen\n")
2981{
2982 vty->lines = -1;
2983 return CMD_SUCCESS;
2984}
2985
2986DEFUN (service_terminal_length, service_terminal_length_cmd,
2987 "service terminal-length <0-512>",
2988 "Set up miscellaneous service\n"
2989 "System wide terminal length configuration\n"
2990 "Number of lines of VTY (0 means no line control)\n")
2991{
2992 int lines;
2993 char *endptr = NULL;
2994
2995 lines = strtol (argv[0], &endptr, 10);
2996 if (lines < 0 || lines > 512 || *endptr != '\0')
2997 {
2998 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2999 return CMD_WARNING;
3000 }
3001 host.lines = lines;
3002
3003 return CMD_SUCCESS;
3004}
3005
3006DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
3007 "no service terminal-length [<0-512>]",
3008 NO_STR
3009 "Set up miscellaneous service\n"
3010 "System wide terminal length configuration\n"
3011 "Number of lines of VTY (0 means no line control)\n")
3012{
3013 host.lines = -1;
3014 return CMD_SUCCESS;
3015}
3016
ajs2885f722004-12-17 23:16:33 +00003017DEFUN_HIDDEN (do_echo,
3018 echo_cmd,
3019 "echo .MESSAGE",
3020 "Echo a message back to the vty\n"
3021 "The message to echo\n")
3022{
3023 char *message;
3024
ajsf6834d42005-01-28 20:28:35 +00003025 vty_out (vty, "%s%s", ((message = argv_concat(argv, argc, 0)) ? message : ""),
3026 VTY_NEWLINE);
3027 if (message)
3028 XFREE(MTYPE_TMP, message);
ajs2885f722004-12-17 23:16:33 +00003029 return CMD_SUCCESS;
3030}
3031
ajs274a4a42004-12-07 15:39:31 +00003032DEFUN (config_logmsg,
3033 config_logmsg_cmd,
3034 "logmsg "LOG_LEVELS" .MESSAGE",
3035 "Send a message to enabled logging destinations\n"
3036 LOG_LEVEL_DESC
3037 "The message to send\n")
3038{
3039 int level;
3040 char *message;
3041
3042 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3043 return CMD_ERR_NO_MATCH;
3044
ajsf6834d42005-01-28 20:28:35 +00003045 zlog(NULL, level, ((message = argv_concat(argv, argc, 1)) ? message : ""));
3046 if (message)
3047 XFREE(MTYPE_TMP, message);
ajs274a4a42004-12-07 15:39:31 +00003048 return CMD_SUCCESS;
3049}
3050
3051DEFUN (show_logging,
3052 show_logging_cmd,
3053 "show logging",
3054 SHOW_STR
3055 "Show current logging configuration\n")
3056{
3057 struct zlog *zl = zlog_default;
3058
3059 vty_out (vty, "Syslog logging: ");
3060 if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED)
3061 vty_out (vty, "disabled");
3062 else
3063 vty_out (vty, "level %s, facility %s, ident %s",
3064 zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]],
3065 facility_name(zl->facility), zl->ident);
3066 vty_out (vty, "%s", VTY_NEWLINE);
3067
3068 vty_out (vty, "Stdout logging: ");
3069 if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED)
3070 vty_out (vty, "disabled");
3071 else
3072 vty_out (vty, "level %s",
3073 zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
3074 vty_out (vty, "%s", VTY_NEWLINE);
3075
3076 vty_out (vty, "Monitor logging: ");
3077 if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
3078 vty_out (vty, "disabled");
3079 else
3080 vty_out (vty, "level %s",
3081 zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
3082 vty_out (vty, "%s", VTY_NEWLINE);
3083
3084 vty_out (vty, "File logging: ");
3085 if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) ||
3086 !zl->fp)
3087 vty_out (vty, "disabled");
3088 else
3089 vty_out (vty, "level %s, filename %s",
3090 zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
3091 zl->filename);
3092 vty_out (vty, "%s", VTY_NEWLINE);
3093
3094 vty_out (vty, "Protocol name: %s%s",
3095 zlog_proto_names[zl->protocol], VTY_NEWLINE);
3096 vty_out (vty, "Record priority: %s%s",
3097 (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE);
3098
3099 return CMD_SUCCESS;
3100}
3101
paul718e3742002-12-13 20:15:29 +00003102DEFUN (config_log_stdout,
3103 config_log_stdout_cmd,
3104 "log stdout",
3105 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003106 "Set stdout logging level\n")
paul718e3742002-12-13 20:15:29 +00003107{
ajs274a4a42004-12-07 15:39:31 +00003108 zlog_set_level (NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl);
3109 return CMD_SUCCESS;
3110}
3111
3112DEFUN (config_log_stdout_level,
3113 config_log_stdout_level_cmd,
3114 "log stdout "LOG_LEVELS,
3115 "Logging control\n"
3116 "Set stdout logging level\n"
3117 LOG_LEVEL_DESC)
3118{
3119 int level;
3120
3121 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3122 return CMD_ERR_NO_MATCH;
3123 zlog_set_level (NULL, ZLOG_DEST_STDOUT, level);
paul718e3742002-12-13 20:15:29 +00003124 return CMD_SUCCESS;
3125}
3126
3127DEFUN (no_config_log_stdout,
3128 no_config_log_stdout_cmd,
ajs274a4a42004-12-07 15:39:31 +00003129 "no log stdout [LEVEL]",
paul718e3742002-12-13 20:15:29 +00003130 NO_STR
3131 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003132 "Cancel logging to stdout\n"
3133 "Logging level\n")
paul718e3742002-12-13 20:15:29 +00003134{
ajs274a4a42004-12-07 15:39:31 +00003135 zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED);
paul718e3742002-12-13 20:15:29 +00003136 return CMD_SUCCESS;
3137}
3138
ajs274a4a42004-12-07 15:39:31 +00003139DEFUN (config_log_monitor,
3140 config_log_monitor_cmd,
3141 "log monitor",
paul718e3742002-12-13 20:15:29 +00003142 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003143 "Set terminal line (monitor) logging level\n")
3144{
3145 zlog_set_level (NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl);
3146 return CMD_SUCCESS;
3147}
3148
3149DEFUN (config_log_monitor_level,
3150 config_log_monitor_level_cmd,
3151 "log monitor "LOG_LEVELS,
3152 "Logging control\n"
3153 "Set terminal line (monitor) logging level\n"
3154 LOG_LEVEL_DESC)
3155{
3156 int level;
3157
3158 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3159 return CMD_ERR_NO_MATCH;
3160 zlog_set_level (NULL, ZLOG_DEST_MONITOR, level);
3161 return CMD_SUCCESS;
3162}
3163
3164DEFUN (no_config_log_monitor,
3165 no_config_log_monitor_cmd,
3166 "no log monitor [LEVEL]",
3167 NO_STR
3168 "Logging control\n"
3169 "Disable terminal line (monitor) logging\n"
3170 "Logging level\n")
3171{
3172 zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
3173 return CMD_SUCCESS;
3174}
3175
3176static int
3177set_log_file(struct vty *vty, const char *fname, int loglevel)
paul718e3742002-12-13 20:15:29 +00003178{
3179 int ret;
paul9035efa2004-10-10 11:56:56 +00003180 char *p = NULL;
3181 const char *fullpath;
3182
paul718e3742002-12-13 20:15:29 +00003183 /* Path detection. */
ajs274a4a42004-12-07 15:39:31 +00003184 if (! IS_DIRECTORY_SEP (*fname))
paul718e3742002-12-13 20:15:29 +00003185 {
paul9035efa2004-10-10 11:56:56 +00003186 char cwd[MAXPATHLEN+1];
3187 cwd[MAXPATHLEN] = '\0';
3188
3189 if (getcwd (cwd, MAXPATHLEN) == NULL)
3190 {
3191 zlog_err ("config_log_file: Unable to alloc mem!");
3192 return CMD_WARNING;
3193 }
3194
ajs274a4a42004-12-07 15:39:31 +00003195 if ( (p = XMALLOC (MTYPE_TMP, strlen (cwd) + strlen (fname) + 2))
paul9035efa2004-10-10 11:56:56 +00003196 == NULL)
3197 {
3198 zlog_err ("config_log_file: Unable to alloc mem!");
3199 return CMD_WARNING;
3200 }
ajs274a4a42004-12-07 15:39:31 +00003201 sprintf (p, "%s/%s", cwd, fname);
paul9035efa2004-10-10 11:56:56 +00003202 fullpath = p;
paul718e3742002-12-13 20:15:29 +00003203 }
3204 else
ajs274a4a42004-12-07 15:39:31 +00003205 fullpath = fname;
paul718e3742002-12-13 20:15:29 +00003206
ajs274a4a42004-12-07 15:39:31 +00003207 ret = zlog_set_file (NULL, fullpath, loglevel);
paul718e3742002-12-13 20:15:29 +00003208
paul9035efa2004-10-10 11:56:56 +00003209 if (p)
3210 XFREE (MTYPE_TMP, p);
3211
paul718e3742002-12-13 20:15:29 +00003212 if (!ret)
3213 {
ajs274a4a42004-12-07 15:39:31 +00003214 vty_out (vty, "can't open logfile %s\n", fname);
paul718e3742002-12-13 20:15:29 +00003215 return CMD_WARNING;
3216 }
3217
3218 if (host.logfile)
3219 XFREE (MTYPE_TMP, host.logfile);
3220
ajs274a4a42004-12-07 15:39:31 +00003221 host.logfile = XSTRDUP (MTYPE_TMP, fname);
paul718e3742002-12-13 20:15:29 +00003222
3223 return CMD_SUCCESS;
3224}
3225
ajs274a4a42004-12-07 15:39:31 +00003226DEFUN (config_log_file,
3227 config_log_file_cmd,
3228 "log file FILENAME",
3229 "Logging control\n"
3230 "Logging to file\n"
3231 "Logging filename\n")
3232{
3233 return set_log_file(vty, argv[0], zlog_default->default_lvl);
3234}
3235
3236DEFUN (config_log_file_level,
3237 config_log_file_level_cmd,
3238 "log file FILENAME "LOG_LEVELS,
3239 "Logging control\n"
3240 "Logging to file\n"
3241 "Logging filename\n"
3242 LOG_LEVEL_DESC)
3243{
3244 int level;
3245
3246 if ((level = level_match(argv[1])) == ZLOG_DISABLED)
3247 return CMD_ERR_NO_MATCH;
3248 return set_log_file(vty, argv[0], level);
3249}
3250
paul718e3742002-12-13 20:15:29 +00003251DEFUN (no_config_log_file,
3252 no_config_log_file_cmd,
3253 "no log file [FILENAME]",
3254 NO_STR
3255 "Logging control\n"
3256 "Cancel logging to file\n"
3257 "Logging file name\n")
3258{
3259 zlog_reset_file (NULL);
3260
3261 if (host.logfile)
3262 XFREE (MTYPE_TMP, host.logfile);
3263
3264 host.logfile = NULL;
3265
3266 return CMD_SUCCESS;
3267}
3268
ajs274a4a42004-12-07 15:39:31 +00003269ALIAS (no_config_log_file,
3270 no_config_log_file_level_cmd,
3271 "no log file FILENAME LEVEL",
3272 NO_STR
3273 "Logging control\n"
3274 "Cancel logging to file\n"
3275 "Logging file name\n"
3276 "Logging level\n")
3277
paul718e3742002-12-13 20:15:29 +00003278DEFUN (config_log_syslog,
3279 config_log_syslog_cmd,
3280 "log syslog",
3281 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003282 "Set syslog logging level\n")
paul718e3742002-12-13 20:15:29 +00003283{
ajs274a4a42004-12-07 15:39:31 +00003284 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
paul12ab19f2003-07-26 06:14:55 +00003285 return CMD_SUCCESS;
3286}
3287
ajs274a4a42004-12-07 15:39:31 +00003288DEFUN (config_log_syslog_level,
3289 config_log_syslog_level_cmd,
3290 "log syslog "LOG_LEVELS,
paul12ab19f2003-07-26 06:14:55 +00003291 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003292 "Set syslog logging level\n"
3293 LOG_LEVEL_DESC)
paul12ab19f2003-07-26 06:14:55 +00003294{
ajs274a4a42004-12-07 15:39:31 +00003295 int level;
paul12ab19f2003-07-26 06:14:55 +00003296
ajs274a4a42004-12-07 15:39:31 +00003297 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3298 return CMD_ERR_NO_MATCH;
3299 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, level);
3300 return CMD_SUCCESS;
3301}
paul12ab19f2003-07-26 06:14:55 +00003302
ajs274a4a42004-12-07 15:39:31 +00003303DEFUN_DEPRECATED (config_log_syslog_facility,
3304 config_log_syslog_facility_cmd,
3305 "log syslog facility "LOG_FACILITIES,
3306 "Logging control\n"
3307 "Logging goes to syslog\n"
3308 "(Deprecated) Facility parameter for syslog messages\n"
3309 LOG_FACILITY_DESC)
3310{
3311 int facility;
paul12ab19f2003-07-26 06:14:55 +00003312
ajs274a4a42004-12-07 15:39:31 +00003313 if ((facility = facility_match(argv[0])) < 0)
3314 return CMD_ERR_NO_MATCH;
3315
3316 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
paul12ab19f2003-07-26 06:14:55 +00003317 zlog_default->facility = facility;
paul718e3742002-12-13 20:15:29 +00003318 return CMD_SUCCESS;
3319}
3320
3321DEFUN (no_config_log_syslog,
3322 no_config_log_syslog_cmd,
ajs274a4a42004-12-07 15:39:31 +00003323 "no log syslog [LEVEL]",
paul718e3742002-12-13 20:15:29 +00003324 NO_STR
3325 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003326 "Cancel logging to syslog\n"
3327 "Logging level\n")
paul718e3742002-12-13 20:15:29 +00003328{
ajs274a4a42004-12-07 15:39:31 +00003329 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
paul718e3742002-12-13 20:15:29 +00003330 return CMD_SUCCESS;
3331}
3332
paul12ab19f2003-07-26 06:14:55 +00003333ALIAS (no_config_log_syslog,
3334 no_config_log_syslog_facility_cmd,
ajs274a4a42004-12-07 15:39:31 +00003335 "no log syslog facility "LOG_FACILITIES,
paul12ab19f2003-07-26 06:14:55 +00003336 NO_STR
3337 "Logging control\n"
3338 "Logging goes to syslog\n"
3339 "Facility parameter for syslog messages\n"
ajs274a4a42004-12-07 15:39:31 +00003340 LOG_FACILITY_DESC)
paul12ab19f2003-07-26 06:14:55 +00003341
ajs274a4a42004-12-07 15:39:31 +00003342DEFUN (config_log_facility,
3343 config_log_facility_cmd,
3344 "log facility "LOG_FACILITIES,
paul718e3742002-12-13 20:15:29 +00003345 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003346 "Facility parameter for syslog messages\n"
3347 LOG_FACILITY_DESC)
paul718e3742002-12-13 20:15:29 +00003348{
ajs274a4a42004-12-07 15:39:31 +00003349 int facility;
3350
3351 if ((facility = facility_match(argv[0])) < 0)
3352 return CMD_ERR_NO_MATCH;
3353 zlog_default->facility = facility;
3354 return CMD_SUCCESS;
paul718e3742002-12-13 20:15:29 +00003355}
3356
ajs274a4a42004-12-07 15:39:31 +00003357DEFUN (no_config_log_facility,
3358 no_config_log_facility_cmd,
3359 "no log facility [FACILITY]",
paul718e3742002-12-13 20:15:29 +00003360 NO_STR
3361 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003362 "Reset syslog facility to default (daemon)\n"
3363 "Syslog facility\n")
paul718e3742002-12-13 20:15:29 +00003364{
ajs274a4a42004-12-07 15:39:31 +00003365 zlog_default->facility = LOG_DAEMON;
3366 return CMD_SUCCESS;
3367}
3368
3369DEFUN_DEPRECATED (config_log_trap,
3370 config_log_trap_cmd,
3371 "log trap "LOG_LEVELS,
3372 "Logging control\n"
3373 "(Deprecated) Set logging level and default for all destinations\n"
3374 LOG_LEVEL_DESC)
3375{
3376 int new_level ;
3377 int i;
3378
3379 if ((new_level = level_match(argv[0])) == ZLOG_DISABLED)
3380 return CMD_ERR_NO_MATCH;
3381
3382 zlog_default->default_lvl = new_level;
3383 for (i = 0; i < ZLOG_NUM_DESTS; i++)
3384 if (zlog_default->maxlvl[i] != ZLOG_DISABLED)
3385 zlog_default->maxlvl[i] = new_level;
3386 return CMD_SUCCESS;
3387}
3388
3389DEFUN_DEPRECATED (no_config_log_trap,
3390 no_config_log_trap_cmd,
3391 "no log trap [LEVEL]",
3392 NO_STR
3393 "Logging control\n"
3394 "Permit all logging information\n"
3395 "Logging level\n")
3396{
3397 zlog_default->default_lvl = LOG_DEBUG;
paul718e3742002-12-13 20:15:29 +00003398 return CMD_SUCCESS;
3399}
3400
3401DEFUN (config_log_record_priority,
3402 config_log_record_priority_cmd,
3403 "log record-priority",
3404 "Logging control\n"
3405 "Log the priority of the message within the message\n")
3406{
3407 zlog_default->record_priority = 1 ;
3408 return CMD_SUCCESS;
3409}
3410
3411DEFUN (no_config_log_record_priority,
3412 no_config_log_record_priority_cmd,
3413 "no log record-priority",
3414 NO_STR
3415 "Logging control\n"
3416 "Do not log the priority of the message within the message\n")
3417{
3418 zlog_default->record_priority = 0 ;
3419 return CMD_SUCCESS;
3420}
3421
paul3b0c5d92005-03-08 10:43:43 +00003422DEFUN (banner_motd_file,
3423 banner_motd_file_cmd,
3424 "banner motd file [FILE]",
3425 "Set banner\n"
3426 "Banner for motd\n"
3427 "Banner from a file\n"
3428 "Filename\n")
3429{
paulb45da6f2005-03-08 15:16:57 +00003430 if (host.motdfile)
3431 XFREE (MTYPE_TMP, host.motdfile);
3432 host.motdfile = XSTRDUP (MTYPE_TMP, argv[0]);
3433
paul3b0c5d92005-03-08 10:43:43 +00003434 return CMD_SUCCESS;
3435}
paul718e3742002-12-13 20:15:29 +00003436
3437DEFUN (banner_motd_default,
3438 banner_motd_default_cmd,
3439 "banner motd default",
3440 "Set banner string\n"
3441 "Strings for motd\n"
3442 "Default string\n")
3443{
3444 host.motd = default_motd;
3445 return CMD_SUCCESS;
3446}
3447
3448DEFUN (no_banner_motd,
3449 no_banner_motd_cmd,
3450 "no banner motd",
3451 NO_STR
3452 "Set banner string\n"
3453 "Strings for motd\n")
3454{
3455 host.motd = NULL;
paul22085182005-03-08 16:00:12 +00003456 if (host.motdfile)
3457 XFREE (MTYPE_TMP, host.motdfile);
paul3b0c5d92005-03-08 10:43:43 +00003458 host.motdfile = NULL;
paul718e3742002-12-13 20:15:29 +00003459 return CMD_SUCCESS;
3460}
3461
3462/* Set config filename. Called from vty.c */
3463void
3464host_config_set (char *filename)
3465{
3466 host.config = strdup (filename);
3467}
3468
3469void
3470install_default (enum node_type node)
3471{
3472 install_element (node, &config_exit_cmd);
3473 install_element (node, &config_quit_cmd);
3474 install_element (node, &config_end_cmd);
3475 install_element (node, &config_help_cmd);
3476 install_element (node, &config_list_cmd);
3477
3478 install_element (node, &config_write_terminal_cmd);
3479 install_element (node, &config_write_file_cmd);
3480 install_element (node, &config_write_memory_cmd);
3481 install_element (node, &config_write_cmd);
3482 install_element (node, &show_running_config_cmd);
3483}
3484
3485/* Initialize command interface. Install basic nodes and commands. */
3486void
3487cmd_init (int terminal)
3488{
3489 /* Allocate initial top vector of commands. */
3490 cmdvec = vector_init (VECTOR_MIN_SIZE);
3491
3492 /* Default host value settings. */
3493 host.name = NULL;
3494 host.password = NULL;
3495 host.enable = NULL;
3496 host.logfile = NULL;
3497 host.config = NULL;
3498 host.lines = -1;
3499 host.motd = default_motd;
paul3b0c5d92005-03-08 10:43:43 +00003500 host.motdfile = NULL;
paul718e3742002-12-13 20:15:29 +00003501
3502 /* Install top nodes. */
3503 install_node (&view_node, NULL);
3504 install_node (&enable_node, NULL);
3505 install_node (&auth_node, NULL);
3506 install_node (&auth_enable_node, NULL);
3507 install_node (&config_node, config_write_host);
3508
3509 /* Each node's basic commands. */
3510 install_element (VIEW_NODE, &show_version_cmd);
3511 if (terminal)
3512 {
3513 install_element (VIEW_NODE, &config_list_cmd);
3514 install_element (VIEW_NODE, &config_exit_cmd);
3515 install_element (VIEW_NODE, &config_quit_cmd);
3516 install_element (VIEW_NODE, &config_help_cmd);
3517 install_element (VIEW_NODE, &config_enable_cmd);
3518 install_element (VIEW_NODE, &config_terminal_length_cmd);
3519 install_element (VIEW_NODE, &config_terminal_no_length_cmd);
ajs274a4a42004-12-07 15:39:31 +00003520 install_element (VIEW_NODE, &show_logging_cmd);
ajs2885f722004-12-17 23:16:33 +00003521 install_element (VIEW_NODE, &echo_cmd);
paul718e3742002-12-13 20:15:29 +00003522 }
3523
3524 if (terminal)
3525 {
3526 install_default (ENABLE_NODE);
3527 install_element (ENABLE_NODE, &config_disable_cmd);
3528 install_element (ENABLE_NODE, &config_terminal_cmd);
3529 install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
3530 }
3531 install_element (ENABLE_NODE, &show_startup_config_cmd);
3532 install_element (ENABLE_NODE, &show_version_cmd);
paul718e3742002-12-13 20:15:29 +00003533
3534 if (terminal)
paul718e3742002-12-13 20:15:29 +00003535 {
hassoe7168df2004-10-03 20:11:32 +00003536 install_element (ENABLE_NODE, &config_terminal_length_cmd);
3537 install_element (ENABLE_NODE, &config_terminal_no_length_cmd);
ajs274a4a42004-12-07 15:39:31 +00003538 install_element (ENABLE_NODE, &show_logging_cmd);
ajs2885f722004-12-17 23:16:33 +00003539 install_element (ENABLE_NODE, &echo_cmd);
ajs274a4a42004-12-07 15:39:31 +00003540 install_element (ENABLE_NODE, &config_logmsg_cmd);
hassoe7168df2004-10-03 20:11:32 +00003541
3542 install_default (CONFIG_NODE);
hassoea8e9d92004-10-07 21:32:14 +00003543 }
3544
3545 install_element (CONFIG_NODE, &hostname_cmd);
3546 install_element (CONFIG_NODE, &no_hostname_cmd);
hassoe7168df2004-10-03 20:11:32 +00003547
hassoea8e9d92004-10-07 21:32:14 +00003548 if (terminal)
3549 {
hassoe7168df2004-10-03 20:11:32 +00003550 install_element (CONFIG_NODE, &password_cmd);
3551 install_element (CONFIG_NODE, &password_text_cmd);
3552 install_element (CONFIG_NODE, &enable_password_cmd);
3553 install_element (CONFIG_NODE, &enable_password_text_cmd);
3554 install_element (CONFIG_NODE, &no_enable_password_cmd);
3555
paul718e3742002-12-13 20:15:29 +00003556 install_element (CONFIG_NODE, &config_log_stdout_cmd);
ajs274a4a42004-12-07 15:39:31 +00003557 install_element (CONFIG_NODE, &config_log_stdout_level_cmd);
paul718e3742002-12-13 20:15:29 +00003558 install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
ajs274a4a42004-12-07 15:39:31 +00003559 install_element (CONFIG_NODE, &config_log_monitor_cmd);
3560 install_element (CONFIG_NODE, &config_log_monitor_level_cmd);
3561 install_element (CONFIG_NODE, &no_config_log_monitor_cmd);
paul718e3742002-12-13 20:15:29 +00003562 install_element (CONFIG_NODE, &config_log_file_cmd);
ajs274a4a42004-12-07 15:39:31 +00003563 install_element (CONFIG_NODE, &config_log_file_level_cmd);
paul718e3742002-12-13 20:15:29 +00003564 install_element (CONFIG_NODE, &no_config_log_file_cmd);
ajs274a4a42004-12-07 15:39:31 +00003565 install_element (CONFIG_NODE, &no_config_log_file_level_cmd);
paul718e3742002-12-13 20:15:29 +00003566 install_element (CONFIG_NODE, &config_log_syslog_cmd);
ajs274a4a42004-12-07 15:39:31 +00003567 install_element (CONFIG_NODE, &config_log_syslog_level_cmd);
paul12ab19f2003-07-26 06:14:55 +00003568 install_element (CONFIG_NODE, &config_log_syslog_facility_cmd);
paul718e3742002-12-13 20:15:29 +00003569 install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
paul12ab19f2003-07-26 06:14:55 +00003570 install_element (CONFIG_NODE, &no_config_log_syslog_facility_cmd);
ajs274a4a42004-12-07 15:39:31 +00003571 install_element (CONFIG_NODE, &config_log_facility_cmd);
3572 install_element (CONFIG_NODE, &no_config_log_facility_cmd);
paul718e3742002-12-13 20:15:29 +00003573 install_element (CONFIG_NODE, &config_log_trap_cmd);
3574 install_element (CONFIG_NODE, &no_config_log_trap_cmd);
3575 install_element (CONFIG_NODE, &config_log_record_priority_cmd);
3576 install_element (CONFIG_NODE, &no_config_log_record_priority_cmd);
3577 install_element (CONFIG_NODE, &service_password_encrypt_cmd);
3578 install_element (CONFIG_NODE, &no_service_password_encrypt_cmd);
3579 install_element (CONFIG_NODE, &banner_motd_default_cmd);
paul3b0c5d92005-03-08 10:43:43 +00003580 install_element (CONFIG_NODE, &banner_motd_file_cmd);
paul718e3742002-12-13 20:15:29 +00003581 install_element (CONFIG_NODE, &no_banner_motd_cmd);
3582 install_element (CONFIG_NODE, &service_terminal_length_cmd);
3583 install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
paul718e3742002-12-13 20:15:29 +00003584
paul354d1192005-04-25 16:26:42 +00003585 install_element (VIEW_NODE, &show_thread_cpu_cmd);
3586 install_element (ENABLE_NODE, &show_thread_cpu_cmd);
3587 install_element (VIEW_NODE, &show_work_queues_cmd);
3588 install_element (ENABLE_NODE, &show_work_queues_cmd);
paul9ab68122003-01-18 01:16:20 +00003589 }
paul718e3742002-12-13 20:15:29 +00003590 srand(time(NULL));
3591}