]> git.proxmox.com Git - mirror_frr.git/blame - lib/command.c
lib: use traditional yacc empty statement
[mirror_frr.git] / lib / command.c
CommitLineData
274a4a44 1/*
9547b5d0
QY
2 * CLI backend interface.
3 *
4 * --
5 * Copyright (C) 2016 Cumulus Networks, Inc.
6 * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
7 * Copyright (C) 2013 by Open Source Routing.
8 * Copyright (C) 2013 by Internet Systems Consortium, Inc. ("ISC")
9 *
10 * This file is part of GNU Zebra.
11 *
12 * GNU Zebra is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2, or (at your option) any
15 * later version.
16 *
17 * GNU Zebra is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with GNU Zebra; see the file COPYING. If not, write to the Free
24 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
25 * 02111-1307, USA.
26 */
718e3744 27
28#include <zebra.h>
29
b21b19c5 30
718e3744 31#include "memory.h"
32#include "log.h"
5e4fa164 33#include <lib/version.h>
9ab6812d 34#include "thread.h"
b21b19c5 35#include "vector.h"
d0bfb22c 36#include "linklist.h"
b21b19c5 37#include "vty.h"
38#include "command.h"
354d119a 39#include "workqueue.h"
19dc275e 40#include "vrf.h"
d0bfb22c
QY
41#include "command_match.h"
42#include "command_parse.h"
1bf9f027 43#include "qobj.h"
d0bfb22c 44
4a1ab8e4
DL
45DEFINE_MTYPE( LIB, HOST, "Host config")
46DEFINE_MTYPE( LIB, STRVEC, "String vector")
47DEFINE_MTYPE_STATIC(LIB, CMD_TOKENS, "Command desc")
48
718e3744 49/* Command vector which includes some level of command lists. Normally
50 each daemon maintains each own cmdvec. */
eb820afe 51vector cmdvec = NULL;
718e3744 52
53/* Host information structure. */
54struct host host;
55
718e3744 56/* Standard command node structures. */
7fc626de 57static struct cmd_node auth_node =
718e3744 58{
59 AUTH_NODE,
60 "Password: ",
61};
62
7fc626de 63static struct cmd_node view_node =
718e3744 64{
65 VIEW_NODE,
66 "%s> ",
67};
68
7fc626de 69static struct cmd_node auth_enable_node =
718e3744 70{
71 AUTH_ENABLE_NODE,
72 "Password: ",
73};
74
7fc626de 75static struct cmd_node enable_node =
718e3744 76{
77 ENABLE_NODE,
78 "%s# ",
79};
80
7fc626de 81static struct cmd_node config_node =
718e3744 82{
83 CONFIG_NODE,
84 "%s(config)# ",
85 1
86};
6590f2c3 87
88/* Default motd string. */
2d362d10 89static const char *default_motd =
6590f2c3 90"\r\n\
91Hello, this is " QUAGGA_PROGNAME " (version " QUAGGA_VERSION ").\r\n\
92" QUAGGA_COPYRIGHT "\r\n\
0be793e6 93" GIT_INFO "\r\n";
6590f2c3 94
274a4a44 95
2d362d10 96static const struct facility_map {
274a4a44 97 int facility;
98 const char *name;
99 size_t match;
d0bfb22c 100} syslog_facilities[] =
274a4a44 101 {
102 { LOG_KERN, "kern", 1 },
103 { LOG_USER, "user", 2 },
104 { LOG_MAIL, "mail", 1 },
105 { LOG_DAEMON, "daemon", 1 },
106 { LOG_AUTH, "auth", 1 },
107 { LOG_SYSLOG, "syslog", 1 },
108 { LOG_LPR, "lpr", 2 },
109 { LOG_NEWS, "news", 1 },
110 { LOG_UUCP, "uucp", 2 },
111 { LOG_CRON, "cron", 1 },
112#ifdef LOG_FTP
113 { LOG_FTP, "ftp", 1 },
114#endif
115 { LOG_LOCAL0, "local0", 6 },
116 { LOG_LOCAL1, "local1", 6 },
117 { LOG_LOCAL2, "local2", 6 },
118 { LOG_LOCAL3, "local3", 6 },
119 { LOG_LOCAL4, "local4", 6 },
120 { LOG_LOCAL5, "local5", 6 },
121 { LOG_LOCAL6, "local6", 6 },
122 { LOG_LOCAL7, "local7", 6 },
123 { 0, NULL, 0 },
124 };
125
126static const char *
127facility_name(int facility)
128{
2d362d10 129 const struct facility_map *fm;
274a4a44 130
131 for (fm = syslog_facilities; fm->name; fm++)
132 if (fm->facility == facility)
133 return fm->name;
134 return "";
135}
136
137static int
138facility_match(const char *str)
139{
2d362d10 140 const struct facility_map *fm;
274a4a44 141
142 for (fm = syslog_facilities; fm->name; fm++)
143 if (!strncmp(str,fm->name,fm->match))
144 return fm->facility;
145 return -1;
146}
147
148static int
149level_match(const char *s)
150{
151 int level ;
d0bfb22c 152
274a4a44 153 for ( level = 0 ; zlog_priority [level] != NULL ; level ++ )
154 if (!strncmp (s, zlog_priority[level], 2))
155 return level;
156 return ZLOG_DISABLED;
157}
158
cb585b65 159/* This is called from main when a daemon is invoked with -v or --version. */
6590f2c3 160void
161print_version (const char *progname)
162{
cb585b65 163 printf ("%s version %s\n", progname, QUAGGA_VERSION);
164 printf ("%s\n", QUAGGA_COPYRIGHT);
80db5ac1 165 printf ("configured with:\n\t%s\n", QUAGGA_CONFIG_ARGS);
6590f2c3 166}
167
6b0655a2 168
718e3744 169/* Utility function to concatenate argv argument into a single string
170 with inserting ' ' character between each argument. */
171char *
d0bfb22c 172argv_concat (struct cmd_token **argv, int argc, int shift)
718e3744 173{
174 int i;
f6834d4c 175 size_t len;
718e3744 176 char *str;
f6834d4c 177 char *p;
718e3744 178
f6834d4c 179 len = 0;
180 for (i = shift; i < argc; i++)
d0bfb22c 181 len += strlen(argv[i]->arg)+1;
f6834d4c 182 if (!len)
183 return NULL;
184 p = str = XMALLOC(MTYPE_TMP, len);
718e3744 185 for (i = shift; i < argc; i++)
186 {
f6834d4c 187 size_t arglen;
d0bfb22c 188 memcpy(p, argv[i]->arg, (arglen = strlen(argv[i]->arg)));
f6834d4c 189 p += arglen;
190 *p++ = ' ';
718e3744 191 }
f6834d4c 192 *(p-1) = '\0';
718e3744 193 return str;
194}
195
ae19d7dd
QY
196/**
197 * Convenience function for accessing argv data.
198 *
199 * @param argc
200 * @param argv
201 * @param text definition snippet of the desired token
202 * @param index the starting index, and where to store the
203 * index of the found token if it exists
204 * @return 1 if found, 0 otherwise
205 */
206int
207argv_find (struct cmd_token **argv, int argc, const char *text, int *index)
208{
209 int found = 0;
210 for (int i = *index; i < argc && found == 0; i++)
211 if ((found = strmatch (text, argv[i]->text)))
212 *index = i;
213 return found;
214}
215
274f29b2
PJ
216static unsigned int
217cmd_hash_key (void *p)
218{
219 return (uintptr_t) p;
220}
221
222static int
223cmd_hash_cmp (const void *a, const void *b)
224{
225 return a == b;
226}
227
718e3744 228/* Install top node of command vector. */
229void
d0bfb22c
QY
230install_node (struct cmd_node *node,
231 int (*func) (struct vty *))
718e3744 232{
233 vector_set_index (cmdvec, node->node, node);
234 node->func = func;
d0bfb22c 235 node->cmdgraph = graph_new ();
76b6abb9
QY
236 node->cmd_vector = vector_init (VECTOR_MIN_SIZE);
237 // add start node
ce882f81 238 struct cmd_token *token = new_cmd_token (START_TKN, CMD_ATTR_NORMAL, NULL, NULL);
76b6abb9 239 graph_new_node (node->cmdgraph, token, (void (*)(void *)) &del_cmd_token);
274f29b2 240 node->cmd_hash = hash_create (cmd_hash_key, cmd_hash_cmp);
718e3744 241}
242
ebacb4ed
QY
243/**
244 * Tokenizes a string, storing tokens in a vector.
245 * Whitespace is ignored.
246 *
247 * Delimiter string = " \n\r\t".
248 *
249 * @param string to tokenize
250 * @return tokenized string
251 */
718e3744 252vector
ea8e9d97 253cmd_make_strvec (const char *string)
718e3744 254{
ebacb4ed 255 if (!string) return NULL;
d0bfb22c 256
ebacb4ed
QY
257 char *copy, *copystart;
258 copystart = copy = XSTRDUP (MTYPE_TMP, string);
d0bfb22c 259
ebacb4ed
QY
260 // skip leading whitespace
261 while (isspace ((int) *copy) && *copy != '\0') copy++;
718e3744 262
ebacb4ed
QY
263 // if the entire string was whitespace or a comment, return
264 if (*copy == '\0' || *copy == '!' || *copy == '#')
17aca20b
QY
265 {
266 XFREE (MTYPE_TMP, copystart);
718e3744 267 return NULL;
17aca20b 268 }
718e3744 269
ebacb4ed
QY
270 vector strvec = vector_init (VECTOR_MIN_SIZE);
271 const char *delim = " \n\r\t", *tok = NULL;
272 while (copy)
273 {
274 tok = strsep (&copy, delim);
275 if (*tok != '\0')
276 vector_set (strvec, XSTRDUP (MTYPE_STRVEC, tok));
277 }
718e3744 278
ebacb4ed
QY
279 XFREE (MTYPE_TMP, copystart);
280 return strvec;
718e3744 281}
282
283/* Free allocated string vector. */
284void
285cmd_free_strvec (vector v)
286{
8c328f11 287 unsigned int i;
718e3744 288 char *cp;
289
290 if (!v)
291 return;
292
55468c86 293 for (i = 0; i < vector_active (v); i++)
718e3744 294 if ((cp = vector_slot (v, i)) != NULL)
295 XFREE (MTYPE_STRVEC, cp);
296
297 vector_free (v);
298}
299
42debbb4
QY
300char *
301cmd_concat_strvec (vector v)
302{
3871154b 303 size_t strsize = 0;
42debbb4
QY
304 for (unsigned int i = 0; i < vector_active (v); i++)
305 if (vector_slot (v, i))
3871154b 306 strsize += strlen ((char *) vector_slot (v, i)) + 1;
42debbb4
QY
307
308 char *concatenated = calloc (sizeof (char), strsize);
309 for (unsigned int i = 0; i < vector_active (v); i++)
3871154b 310 {
42debbb4 311 strlcat (concatenated, (char *) vector_slot (v, i), strsize);
3871154b
QY
312 strlcat (concatenated, " ", strsize);
313 }
42debbb4
QY
314
315 return concatenated;
316}
718e3744 317
318/* Return prompt character of specified node. */
8c328f11 319const char *
718e3744 320cmd_prompt (enum node_type node)
321{
322 struct cmd_node *cnode;
323
324 cnode = vector_slot (cmdvec, node);
325 return cnode->prompt;
326}
327
328/* Install a command into a node. */
329void
330install_element (enum node_type ntype, struct cmd_element *cmd)
331{
332 struct cmd_node *cnode;
d0bfb22c 333
eb820afe 334 /* cmd_init hasn't been called */
335 if (!cmdvec)
274f29b2
PJ
336 {
337 fprintf (stderr, "%s called before cmd_init, breakage likely\n",
338 __func__);
339 return;
340 }
ebacb4ed 341
718e3744 342 cnode = vector_slot (cmdvec, ntype);
343
d0bfb22c 344 if (cnode == NULL)
718e3744 345 {
346 fprintf (stderr, "Command node %d doesn't exist, please check it\n",
d0bfb22c
QY
347 ntype);
348 exit (EXIT_FAILURE);
718e3744 349 }
ebacb4ed 350
274f29b2 351 if (hash_lookup (cnode->cmd_hash, cmd) != NULL)
c0f9771d 352 {
ebacb4ed 353 fprintf (stderr,
274f29b2
PJ
354 "Multiple command installs to node %d of command:\n%s\n",
355 ntype, cmd->string);
c0f9771d
QY
356 return;
357 }
ebacb4ed 358
274f29b2 359 assert (hash_get (cnode->cmd_hash, cmd, hash_alloc_intern));
ebacb4ed 360
d0bfb22c 361 command_parse_format (cnode->cmdgraph, cmd);
718e3744 362 vector_set (cnode->cmd_vector, cmd);
735e62a0
DS
363
364 if (ntype == VIEW_NODE)
365 install_element (ENABLE_NODE, cmd);
718e3744 366}
367
2d362d10 368static const unsigned char itoa64[] =
718e3744 369"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
370
274a4a44 371static void
718e3744 372to64(char *s, long v, int n)
373{
d0bfb22c 374 while (--n >= 0)
718e3744 375 {
376 *s++ = itoa64[v&0x3f];
377 v >>= 6;
378 }
379}
380
274a4a44 381static char *
382zencrypt (const char *passwd)
718e3744 383{
384 char salt[6];
385 struct timeval tv;
386 char *crypt (const char *, const char *);
387
388 gettimeofday(&tv,0);
d0bfb22c 389
718e3744 390 to64(&salt[0], random(), 3);
391 to64(&salt[3], tv.tv_usec, 3);
392 salt[5] = '\0';
393
394 return crypt (passwd, salt);
395}
396
397/* This function write configuration of this host. */
274a4a44 398static int
718e3744 399config_write_host (struct vty *vty)
400{
401 if (host.name)
402 vty_out (vty, "hostname %s%s", host.name, VTY_NEWLINE);
403
404 if (host.encrypt)
405 {
406 if (host.password_encrypt)
d0bfb22c 407 vty_out (vty, "password 8 %s%s", host.password_encrypt, VTY_NEWLINE);
718e3744 408 if (host.enable_encrypt)
d0bfb22c 409 vty_out (vty, "enable password 8 %s%s", host.enable_encrypt, VTY_NEWLINE);
718e3744 410 }
411 else
412 {
413 if (host.password)
414 vty_out (vty, "password %s%s", host.password, VTY_NEWLINE);
415 if (host.enable)
416 vty_out (vty, "enable password %s%s", host.enable, VTY_NEWLINE);
417 }
418
274a4a44 419 if (zlog_default->default_lvl != LOG_DEBUG)
82146b88 420 {
421 vty_out (vty, "! N.B. The 'log trap' command is deprecated.%s",
d0bfb22c 422 VTY_NEWLINE);
82146b88 423 vty_out (vty, "log trap %s%s",
d0bfb22c 424 zlog_priority[zlog_default->default_lvl], VTY_NEWLINE);
82146b88 425 }
274a4a44 426
427 if (host.logfile && (zlog_default->maxlvl[ZLOG_DEST_FILE] != ZLOG_DISABLED))
428 {
429 vty_out (vty, "log file %s", host.logfile);
430 if (zlog_default->maxlvl[ZLOG_DEST_FILE] != zlog_default->default_lvl)
d0bfb22c
QY
431 vty_out (vty, " %s",
432 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_FILE]]);
274a4a44 433 vty_out (vty, "%s", VTY_NEWLINE);
434 }
435
436 if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != ZLOG_DISABLED)
437 {
438 vty_out (vty, "log stdout");
439 if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != zlog_default->default_lvl)
d0bfb22c
QY
440 vty_out (vty, " %s",
441 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_STDOUT]]);
274a4a44 442 vty_out (vty, "%s", VTY_NEWLINE);
443 }
718e3744 444
274a4a44 445 if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
446 vty_out(vty,"no log monitor%s",VTY_NEWLINE);
447 else if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] != zlog_default->default_lvl)
448 vty_out(vty,"log monitor %s%s",
d0bfb22c 449 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_MONITOR]],VTY_NEWLINE);
718e3744 450
274a4a44 451 if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED)
12ab19f1 452 {
453 vty_out (vty, "log syslog");
274a4a44 454 if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != zlog_default->default_lvl)
d0bfb22c
QY
455 vty_out (vty, " %s",
456 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_SYSLOG]]);
12ab19f1 457 vty_out (vty, "%s", VTY_NEWLINE);
458 }
274a4a44 459
460 if (zlog_default->facility != LOG_DAEMON)
461 vty_out (vty, "log facility %s%s",
d0bfb22c 462 facility_name(zlog_default->facility), VTY_NEWLINE);
718e3744 463
464 if (zlog_default->record_priority == 1)
465 vty_out (vty, "log record-priority%s", VTY_NEWLINE);
466
1ed72e0b
AS
467 if (zlog_default->timestamp_precision > 0)
468 vty_out (vty, "log timestamp precision %d%s",
d0bfb22c 469 zlog_default->timestamp_precision, VTY_NEWLINE);
1ed72e0b 470
718e3744 471 if (host.advanced)
472 vty_out (vty, "service advanced-vty%s", VTY_NEWLINE);
473
474 if (host.encrypt)
475 vty_out (vty, "service password-encryption%s", VTY_NEWLINE);
476
477 if (host.lines >= 0)
478 vty_out (vty, "service terminal-length %d%s", host.lines,
d0bfb22c 479 VTY_NEWLINE);
718e3744 480
3b0c5d9a 481 if (host.motdfile)
482 vty_out (vty, "banner motd file %s%s", host.motdfile, VTY_NEWLINE);
483 else if (! host.motd)
718e3744 484 vty_out (vty, "no banner motd%s", VTY_NEWLINE);
485
486 return 1;
487}
488
d0bfb22c
QY
489/* Utility function for getting command graph. */
490static struct graph *
491cmd_node_graph (vector v, enum node_type ntype)
718e3744 492{
d0bfb22c
QY
493 struct cmd_node *cnode = vector_slot (v, ntype);
494 return cnode->cmdgraph;
718e3744 495}
496
d0bfb22c
QY
497static int
498cmd_try_do_shortcut (enum node_type node, char* first_word) {
499 if ( first_word != NULL &&
500 node != AUTH_NODE &&
501 node != VIEW_NODE &&
502 node != AUTH_ENABLE_NODE &&
503 node != ENABLE_NODE &&
d0bfb22c
QY
504 0 == strcmp( "do", first_word ) )
505 return 1;
506 return 0;
718e3744 507}
508
d0bfb22c
QY
509/**
510 * Compare function for cmd_token.
511 * Used with qsort to sort command completions.
512 */
274a4a44 513static int
d0bfb22c 514compare_completions (const void *fst, const void *snd)
718e3744 515{
d0bfb22c
QY
516 struct cmd_token *first = *(struct cmd_token **) fst,
517 *secnd = *(struct cmd_token **) snd;
518 return strcmp (first->text, secnd->text);
718e3744 519}
520
d0bfb22c
QY
521/**
522 * Takes a list of completions returned by command_complete,
523 * dedeuplicates them based on both text and description,
6011c1b2
QY
524 * sorts them, and returns them as a vector.
525 *
526 * @param completions linked list of cmd_token
527 * @return deduplicated and sorted vector with
d0bfb22c
QY
528 */
529static vector
530completions_to_vec (struct list *completions)
718e3744 531{
d0bfb22c 532 vector comps = vector_init (VECTOR_MIN_SIZE);
718e3744 533
d0bfb22c 534 struct listnode *ln;
6011c1b2 535 struct cmd_token *token, *cr = NULL;
d0bfb22c
QY
536 unsigned int i, exists;
537 for (ALL_LIST_ELEMENTS_RO(completions,ln,token))
538 {
6011c1b2
QY
539 if (token->type == END_TKN && (cr = token))
540 continue;
541
d0bfb22c
QY
542 // linear search for token in completions vector
543 exists = 0;
544 for (i = 0; i < vector_active (comps) && !exists; i++)
cd40b329 545 {
d0bfb22c
QY
546 struct cmd_token *curr = vector_slot (comps, i);
547 exists = !strcmp (curr->text, token->text) &&
548 !strcmp (curr->desc, token->desc);
cd40b329 549 }
909a2155 550
d0bfb22c 551 if (!exists)
17aca20b 552 vector_set (comps, token);
d0bfb22c 553 }
cd40b329 554
d0bfb22c
QY
555 // sort completions
556 qsort (comps->index,
557 vector_active (comps),
558 sizeof (void *),
559 &compare_completions);
cd40b329 560
ebacb4ed 561 // make <cr> the first element, if it is present
6011c1b2
QY
562 if (cr)
563 {
564 vector_set_index (comps, vector_active (comps), NULL);
565 memmove (comps->index + 1, comps->index, (comps->alloced - 1) * sizeof (void *));
17aca20b 566 vector_set_index (comps, 0, cr);
6011c1b2
QY
567 }
568
d0bfb22c 569 return comps;
cd40b329 570}
d0bfb22c
QY
571/**
572 * Generates a vector of cmd_token representing possible completions
573 * on the current input.
574 *
575 * @param vline the vectorized input line
576 * @param vty the vty with the node to match on
577 * @param status pointer to matcher status code
ebacb4ed 578 * @return vector of struct cmd_token * with possible completions
d0bfb22c
QY
579 */
580static vector
581cmd_complete_command_real (vector vline, struct vty *vty, int *status)
cd40b329 582{
d0bfb22c
QY
583 struct list *completions;
584 struct graph *cmdgraph = cmd_node_graph (cmdvec, vty->node);
cd40b329 585
d0bfb22c 586 enum matcher_rv rv = command_complete (cmdgraph, vline, &completions);
cd40b329 587
d0bfb22c
QY
588 if (MATCHER_ERROR(rv))
589 {
17aca20b 590 *status = CMD_ERR_NO_MATCH;
d0bfb22c 591 return NULL;
b92938a7 592 }
593
d0bfb22c
QY
594 vector comps = completions_to_vec (completions);
595 list_delete (completions);
b92938a7 596
d0bfb22c
QY
597 // set status code appropriately
598 switch (vector_active (comps))
599 {
600 case 0:
601 *status = CMD_ERR_NO_MATCH;
602 break;
603 case 1:
604 *status = CMD_COMPLETE_FULL_MATCH;
605 break;
606 default:
607 *status = CMD_COMPLETE_LIST_MATCH;
608 }
718e3744 609
d0bfb22c
QY
610 return comps;
611}
718e3744 612
d0bfb22c
QY
613vector
614cmd_describe_command (vector vline, struct vty *vty, int *status)
615{
616 vector ret;
718e3744 617
d0bfb22c 618 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
718e3744 619 {
d0bfb22c
QY
620 enum node_type onode;
621 vector shifted_vline;
622 unsigned int index;
718e3744 623
d0bfb22c
QY
624 onode = vty->node;
625 vty->node = ENABLE_NODE;
626 /* We can try it on enable node, cos' the vty is authenticated */
718e3744 627
d0bfb22c
QY
628 shifted_vline = vector_init (vector_count(vline));
629 /* use memcpy? */
630 for (index = 1; index < vector_active (vline); index++)
631 {
632 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
633 }
718e3744 634
d0bfb22c
QY
635 ret = cmd_complete_command_real (shifted_vline, vty, status);
636
637 vector_free(shifted_vline);
638 vty->node = onode;
639 return ret;
640 }
718e3744 641
d0bfb22c 642 return cmd_complete_command_real (vline, vty, status);
718e3744 643}
644
ebacb4ed
QY
645/**
646 * Generate possible tab-completions for the given input. This function only
647 * returns results that would result in a valid command if used as Readline
648 * completions (as is the case in vtysh). For instance, if the passed vline ends
649 * with '4.3.2', the strings 'A.B.C.D' and 'A.B.C.D/M' will _not_ be returned.
650 *
651 * @param vline vectorized input line
652 * @param vty the vty
653 * @param status location to store matcher status code in
654 * @return set of valid strings for use with Readline as tab-completions.
655 */
656
b92938a7 657char **
ebacb4ed 658cmd_complete_command (vector vline, struct vty *vty, int *status)
b92938a7 659{
268316d1
QY
660 char **ret = NULL;
661 int original_node = vty->node;
662 vector input_line = vector_init (vector_count (vline));
663
664 // if the first token is 'do' we'll want to execute the command in the enable node
665 int do_shortcut = cmd_try_do_shortcut (vty->node, vector_slot (vline, 0));
666 vty->node = do_shortcut ? ENABLE_NODE : original_node;
667
668 // construct the input line we'll be matching on
669 unsigned int offset = (do_shortcut) ? 1 : 0;
670 for (unsigned index = 0; index + offset < vector_active (vline); index++)
671 vector_set_index (input_line, index + offset, vector_lookup (vline, index));
672
673 // get token completions -- this is a copying operation
ef736f12 674 vector comps = NULL, initial_comps;
ebacb4ed
QY
675 initial_comps = cmd_complete_command_real (input_line, vty, status);
676
268316d1
QY
677 if (!MATCHER_ERROR (*status))
678 {
5b5231b0
QY
679 assert (initial_comps);
680 // filter out everything that is not suitable for a tab-completion
681 comps = vector_init (VECTOR_MIN_SIZE);
682 for (unsigned int i = 0; i < vector_active(initial_comps); i++)
683 {
684 struct cmd_token *token = vector_slot (initial_comps, i);
685 if (token->type == WORD_TKN)
686 vector_set (comps, token);
5b5231b0
QY
687 }
688 vector_free (initial_comps);
689
268316d1 690 // copy completions text into an array of char*
17aca20b 691 ret = XMALLOC (MTYPE_TMP, (vector_active (comps)+1) * sizeof (char *));
268316d1
QY
692 unsigned int i;
693 for (i = 0; i < vector_active (comps); i++)
694 {
695 struct cmd_token *token = vector_slot (comps, i);
696 ret[i] = XSTRDUP (MTYPE_TMP, token->text);
697 vector_unset (comps, i);
268316d1 698 }
ebacb4ed
QY
699 // set the last element to NULL, because this array is used in
700 // a Readline completion_generator function which expects NULL
701 // as a sentinel value
268316d1
QY
702 ret[i] = NULL;
703 vector_free (comps);
704 comps = NULL;
705 }
b92938a7 706
268316d1
QY
707 // comps should always be null here
708 assert (!comps);
b92938a7 709
268316d1
QY
710 // free the adjusted input line
711 vector_free (input_line);
b92938a7 712
268316d1
QY
713 // reset vty->node to its original value
714 vty->node = original_node;
d0bfb22c
QY
715
716 return ret;
cde9f101 717}
b92938a7 718
b92938a7 719/* return parent node */
720/* MUST eventually converge on CONFIG_NODE */
13bfca7a 721enum node_type
274a4a44 722node_parent ( enum node_type node )
b92938a7 723{
724 enum node_type ret;
725
9ab6812d 726 assert (node > CONFIG_NODE);
727
728 switch (node)
729 {
730 case BGP_VPNV4_NODE:
8ecd3266 731 case BGP_VPNV6_NODE:
8b1fb8be
LB
732 case BGP_ENCAP_NODE:
733 case BGP_ENCAPV6_NODE:
65efcfce 734 case BGP_VNC_DEFAULTS_NODE:
e52702f2
QY
735 case BGP_VNC_NVE_GROUP_NODE:
736 case BGP_VNC_L2_GROUP_NODE:
9ab6812d 737 case BGP_IPV4_NODE:
738 case BGP_IPV4M_NODE:
739 case BGP_IPV6_NODE:
1e836590 740 case BGP_IPV6M_NODE:
9ab6812d 741 ret = BGP_NODE;
742 break;
743 case KEYCHAIN_KEY_NODE:
744 ret = KEYCHAIN_NODE;
745 break;
16f1b9ee
OD
746 case LINK_PARAMS_NODE:
747 ret = INTERFACE_NODE;
748 break;
eac6e3f0
RW
749 case LDP_IPV4_NODE:
750 case LDP_IPV6_NODE:
751 ret = LDP_NODE;
752 break;
753 case LDP_IPV4_IFACE_NODE:
754 ret = LDP_IPV4_NODE;
755 break;
756 case LDP_IPV6_IFACE_NODE:
757 ret = LDP_IPV6_NODE;
758 break;
759 case LDP_PSEUDOWIRE_NODE:
760 ret = LDP_L2VPN_NODE;
761 break;
9ab6812d 762 default:
763 ret = CONFIG_NODE;
16f1b9ee 764 break;
b92938a7 765 }
766
767 return ret;
768}
769
718e3744 770/* Execute command by argument vline vector. */
274a4a44 771static int
cd40b329 772cmd_execute_command_real (vector vline,
d0bfb22c
QY
773 enum filter_type filter,
774 struct vty *vty,
17aca20b 775 const struct cmd_element **cmd)
d0bfb22c
QY
776{
777 struct list *argv_list;
778 enum matcher_rv status;
17aca20b 779 const struct cmd_element *matched_element = NULL;
c5bd4620 780
d0bfb22c 781 struct graph *cmdgraph = cmd_node_graph (cmdvec, vty->node);
c5bd4620
QY
782 status = command_match (cmdgraph, vline, &argv_list, &matched_element);
783
784 if (cmd)
785 *cmd = matched_element;
d0bfb22c
QY
786
787 // if matcher error, return corresponding CMD_ERR
788 if (MATCHER_ERROR(status))
17aca20b 789 {
d0bfb22c
QY
790 switch (status)
791 {
792 case MATCHER_INCOMPLETE:
793 return CMD_ERR_INCOMPLETE;
794 case MATCHER_AMBIGUOUS:
795 return CMD_ERR_AMBIGUOUS;
796 default:
797 return CMD_ERR_NO_MATCH;
718e3744 798 }
17aca20b 799 }
718e3744 800
d0bfb22c
QY
801 // build argv array from argv list
802 struct cmd_token **argv = XMALLOC (MTYPE_TMP, argv_list->count * sizeof (struct cmd_token *));
803 struct listnode *ln;
804 struct cmd_token *token;
805 unsigned int i = 0;
806 for (ALL_LIST_ELEMENTS_RO(argv_list,ln,token))
807 argv[i++] = token;
718e3744 808
d0bfb22c 809 int argc = argv_list->count;
718e3744 810
d0bfb22c 811 int ret;
c5bd4620 812 if (matched_element->daemon)
d0bfb22c
QY
813 ret = CMD_SUCCESS_DAEMON;
814 else
c5bd4620 815 ret = matched_element->func (matched_element, vty, argc, argv);
718e3744 816
d0bfb22c
QY
817 // delete list and cmd_token's in it
818 list_delete (argv_list);
17aca20b 819 XFREE (MTYPE_TMP, argv);
718e3744 820
d0bfb22c 821 return ret;
718e3744 822}
823
cd40b329
CF
824/**
825 * Execute a given command, handling things like "do ..." and checking
826 * whether the given command might apply at a parent node if doesn't
827 * apply for the current node.
828 *
829 * @param vline Command line input, vector of char* where each element is
830 * one input token.
831 * @param vty The vty context in which the command should be executed.
832 * @param cmd Pointer where the struct cmd_element of the matched command
833 * will be stored, if any. May be set to NULL if this info is
834 * not needed.
835 * @param vtysh If set != 0, don't lookup the command at parent nodes.
836 * @return The status of the command that has been executed or an error code
837 * as to why no command could be executed.
838 */
eda031f6 839int
17aca20b
QY
840cmd_execute_command (vector vline, struct vty *vty,
841 const struct cmd_element **cmd,
842 int vtysh)
843{
04e64062 844 int ret, saved_ret = 0;
9ab6812d 845 enum node_type onode, try_node;
eda031f6 846
9ab6812d 847 onode = try_node = vty->node;
b92938a7 848
17aca20b 849 if (cmd_try_do_shortcut(vty->node, vector_slot(vline, 0)))
b92938a7 850 {
851 vector shifted_vline;
8c328f11 852 unsigned int index;
b92938a7 853
854 vty->node = ENABLE_NODE;
855 /* We can try it on enable node, cos' the vty is authenticated */
856
857 shifted_vline = vector_init (vector_count(vline));
858 /* use memcpy? */
d0bfb22c 859 for (index = 1; index < vector_active (vline); index++)
04e64062 860 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
b92938a7 861
cd40b329 862 ret = cmd_execute_command_real (shifted_vline, FILTER_RELAXED, vty, cmd);
b92938a7 863
864 vector_free(shifted_vline);
865 vty->node = onode;
866 return ret;
867 }
868
cd40b329 869 saved_ret = ret = cmd_execute_command_real (vline, FILTER_RELAXED, vty, cmd);
b92938a7 870
87d683b0 871 if (vtysh)
872 return saved_ret;
873
04e64062 874 if (ret != CMD_SUCCESS && ret != CMD_WARNING)
b92938a7 875 {
04e64062
QY
876 /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
877 while (vty->node > CONFIG_NODE)
878 {
879 try_node = node_parent(try_node);
880 vty->node = try_node;
881 ret = cmd_execute_command_real (vline, FILTER_RELAXED, vty, cmd);
882 if (ret == CMD_SUCCESS || ret == CMD_WARNING)
883 return ret;
884 }
885 /* no command succeeded, reset the vty to the original node */
886 vty->node = onode;
b92938a7 887 }
04e64062
QY
888
889 /* return command status for original node */
9ab6812d 890 return saved_ret;
b92938a7 891}
892
cd40b329
CF
893/**
894 * Execute a given command, matching it strictly against the current node.
895 * This mode is used when reading config files.
896 *
897 * @param vline Command line input, vector of char* where each element is
898 * one input token.
899 * @param vty The vty context in which the command should be executed.
900 * @param cmd Pointer where the struct cmd_element* of the matched command
901 * will be stored, if any. May be set to NULL if this info is
902 * not needed.
903 * @return The status of the command that has been executed or an error code
904 * as to why no command could be executed.
905 */
718e3744 906int
909a2155 907cmd_execute_command_strict (vector vline, struct vty *vty,
17aca20b 908 const struct cmd_element **cmd)
718e3744 909{
cd40b329 910 return cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd);
718e3744 911}
912
bed578b8
DS
913/**
914 * Parse one line of config, walking up the parse tree attempting to find a match
915 *
916 * @param vty The vty context in which the command should be executed.
917 * @param cmd Pointer where the struct cmd_element* of the match command
918 * will be stored, if any. May be set to NULL if this info is
919 * not needed.
920 * @param use_daemon Boolean to control whether or not we match on CMD_SUCCESS_DAEMON
921 * or not.
922 * @return The status of the command that has been executed or an error code
923 * as to why no command could be executed.
924 */
925int
17aca20b 926command_config_read_one_line (struct vty *vty, const struct cmd_element **cmd, int use_daemon)
bed578b8
DS
927{
928 vector vline;
929 int saved_node;
930 int ret;
931
932 vline = cmd_make_strvec (vty->buf);
933
934 /* In case of comment line */
935 if (vline == NULL)
936 return CMD_SUCCESS;
937
938 /* Execute configuration command : this is strict match */
939 ret = cmd_execute_command_strict (vline, vty, cmd);
940
941 // Climb the tree and try the command again at each node
942 if (!(use_daemon && ret == CMD_SUCCESS_DAEMON) &&
fd715b78
DW
943 !(!use_daemon && ret == CMD_ERR_NOTHING_TODO) &&
944 ret != CMD_SUCCESS &&
945 ret != CMD_WARNING &&
946 vty->node != CONFIG_NODE) {
bed578b8
DS
947
948 saved_node = vty->node;
949
950 while (!(use_daemon && ret == CMD_SUCCESS_DAEMON) &&
fd715b78 951 !(!use_daemon && ret == CMD_ERR_NOTHING_TODO) &&
d0bfb22c 952 ret != CMD_SUCCESS &&
fd715b78 953 ret != CMD_WARNING &&
73d2dad0 954 vty->node > CONFIG_NODE) {
bed578b8 955 vty->node = node_parent(vty->node);
fd715b78 956 ret = cmd_execute_command_strict (vline, vty, cmd);
bed578b8
DS
957 }
958
959 // If climbing the tree did not work then ignore the command and
960 // stay at the same node
961 if (!(use_daemon && ret == CMD_SUCCESS_DAEMON) &&
fd715b78 962 !(!use_daemon && ret == CMD_ERR_NOTHING_TODO) &&
d0bfb22c 963 ret != CMD_SUCCESS &&
fd715b78 964 ret != CMD_WARNING)
bed578b8 965 {
d0bfb22c 966 vty->node = saved_node;
bed578b8
DS
967 }
968 }
969
cbd7259d
QY
970 if (ret != CMD_SUCCESS && ret != CMD_WARNING)
971 memcpy (vty->error_buf, vty->buf, VTY_BUFSIZ);
972
bed578b8
DS
973 cmd_free_strvec (vline);
974
975 return ret;
976}
977
5689fe5f 978/* Configuration make from file. */
718e3744 979int
13fbc82d 980config_from_file (struct vty *vty, FILE *fp, unsigned int *line_num)
718e3744 981{
5689fe5f 982 int ret, error_ret=0;
13fbc82d 983 *line_num = 0;
718e3744 984
985 while (fgets (vty->buf, VTY_BUFSIZ, fp))
986 {
13fbc82d 987 if (!error_ret)
d0bfb22c 988 ++(*line_num);
13fbc82d 989
bed578b8 990 ret = command_config_read_one_line (vty, NULL, 0);
718e3744 991
5689fe5f 992 if (ret != CMD_SUCCESS && ret != CMD_WARNING &&
d0bfb22c
QY
993 ret != CMD_ERR_NOTHING_TODO)
994 error_ret = ret;
718e3744 995 }
5689fe5f
DW
996
997 if (error_ret) {
998 return error_ret;
999 }
1000
718e3744 1001 return CMD_SUCCESS;
1002}
1003
5689fe5f 1004/* Configuration from terminal */
718e3744 1005DEFUN (config_terminal,
1006 config_terminal_cmd,
1007 "configure terminal",
1008 "Configuration from vty interface\n"
1009 "Configuration terminal\n")
1010{
1011 if (vty_config_lock (vty))
1012 vty->node = CONFIG_NODE;
1013 else
1014 {
1015 vty_out (vty, "VTY configuration is locked by other VTY%s", VTY_NEWLINE);
1016 return CMD_WARNING;
1017 }
1018 return CMD_SUCCESS;
1019}
1020
1021/* Enable command */
d0bfb22c 1022DEFUN (enable,
718e3744 1023 config_enable_cmd,
1024 "enable",
1025 "Turn on privileged mode command\n")
1026{
1027 /* If enable password is NULL, change to ENABLE_NODE */
1028 if ((host.enable == NULL && host.enable_encrypt == NULL) ||
1029 vty->type == VTY_SHELL_SERV)
1030 vty->node = ENABLE_NODE;
1031 else
1032 vty->node = AUTH_ENABLE_NODE;
1033
1034 return CMD_SUCCESS;
1035}
1036
1037/* Disable command */
d0bfb22c 1038DEFUN (disable,
718e3744 1039 config_disable_cmd,
1040 "disable",
1041 "Turn off privileged mode command\n")
1042{
1043 if (vty->node == ENABLE_NODE)
1044 vty->node = VIEW_NODE;
1045 return CMD_SUCCESS;
1046}
1047
1048/* Down vty node level. */
1049DEFUN (config_exit,
1050 config_exit_cmd,
1051 "exit",
1052 "Exit current mode and down to previous mode\n")
1053{
1054 switch (vty->node)
1055 {
1056 case VIEW_NODE:
1057 case ENABLE_NODE:
1058 if (vty_shell (vty))
d0bfb22c 1059 exit (0);
718e3744 1060 else
d0bfb22c 1061 vty->status = VTY_CLOSE;
718e3744 1062 break;
1063 case CONFIG_NODE:
1064 vty->node = ENABLE_NODE;
1065 vty_config_unlock (vty);
1066 break;
1067 case INTERFACE_NODE:
13460c44 1068 case NS_NODE:
f93e3f69 1069 case VRF_NODE:
718e3744 1070 case ZEBRA_NODE:
1071 case BGP_NODE:
1072 case RIP_NODE:
1073 case RIPNG_NODE:
1074 case OSPF_NODE:
1075 case OSPF6_NODE:
eac6e3f0
RW
1076 case LDP_NODE:
1077 case LDP_L2VPN_NODE:
9e867fe6 1078 case ISIS_NODE:
718e3744 1079 case KEYCHAIN_NODE:
1080 case MASC_NODE:
1081 case RMAP_NODE:
12e41d03 1082 case PIM_NODE:
718e3744 1083 case VTY_NODE:
1084 vty->node = CONFIG_NODE;
1085 break;
718e3744 1086 case BGP_IPV4_NODE:
1087 case BGP_IPV4M_NODE:
8ecd3266 1088 case BGP_VPNV4_NODE:
1089 case BGP_VPNV6_NODE:
8b1fb8be
LB
1090 case BGP_ENCAP_NODE:
1091 case BGP_ENCAPV6_NODE:
65efcfce
LB
1092 case BGP_VNC_DEFAULTS_NODE:
1093 case BGP_VNC_NVE_GROUP_NODE:
1094 case BGP_VNC_L2_GROUP_NODE:
718e3744 1095 case BGP_IPV6_NODE:
1e836590 1096 case BGP_IPV6M_NODE:
718e3744 1097 vty->node = BGP_NODE;
1098 break;
eac6e3f0
RW
1099 case LDP_IPV4_NODE:
1100 case LDP_IPV6_NODE:
1101 vty->node = LDP_NODE;
1102 break;
1103 case LDP_IPV4_IFACE_NODE:
1104 vty->node = LDP_IPV4_NODE;
1105 break;
1106 case LDP_IPV6_IFACE_NODE:
1107 vty->node = LDP_IPV6_NODE;
1108 break;
1109 case LDP_PSEUDOWIRE_NODE:
1110 vty->node = LDP_L2VPN_NODE;
1111 break;
718e3744 1112 case KEYCHAIN_KEY_NODE:
1113 vty->node = KEYCHAIN_NODE;
1114 break;
16f1b9ee
OD
1115 case LINK_PARAMS_NODE:
1116 vty->node = INTERFACE_NODE;
1117 break;
718e3744 1118 default:
1119 break;
1120 }
1121 return CMD_SUCCESS;
1122}
1123
f667a580
QY
1124/* ALIAS_FIXME */
1125DEFUN (config_quit,
1126 config_quit_cmd,
1127 "quit",
1128 "Exit current mode and down to previous mode\n")
1129{
1130 return config_exit (self, vty, argc, argv);
1131}
1132
d0bfb22c 1133
718e3744 1134/* End of configuration. */
1135DEFUN (config_end,
1136 config_end_cmd,
1137 "end",
1138 "End current mode and change to enable mode.")
1139{
1140 switch (vty->node)
1141 {
1142 case VIEW_NODE:
1143 case ENABLE_NODE:
1144 /* Nothing to do. */
1145 break;
1146 case CONFIG_NODE:
1147 case INTERFACE_NODE:
13460c44 1148 case NS_NODE:
f93e3f69 1149 case VRF_NODE:
718e3744 1150 case ZEBRA_NODE:
1151 case RIP_NODE:
1152 case RIPNG_NODE:
1153 case BGP_NODE:
8b1fb8be
LB
1154 case BGP_ENCAP_NODE:
1155 case BGP_ENCAPV6_NODE:
65efcfce
LB
1156 case BGP_VNC_DEFAULTS_NODE:
1157 case BGP_VNC_NVE_GROUP_NODE:
1158 case BGP_VNC_L2_GROUP_NODE:
718e3744 1159 case BGP_VPNV4_NODE:
8ecd3266 1160 case BGP_VPNV6_NODE:
718e3744 1161 case BGP_IPV4_NODE:
1162 case BGP_IPV4M_NODE:
1163 case BGP_IPV6_NODE:
1e836590 1164 case BGP_IPV6M_NODE:
718e3744 1165 case RMAP_NODE:
1166 case OSPF_NODE:
1167 case OSPF6_NODE:
eac6e3f0
RW
1168 case LDP_NODE:
1169 case LDP_IPV4_NODE:
1170 case LDP_IPV6_NODE:
1171 case LDP_IPV4_IFACE_NODE:
1172 case LDP_IPV6_IFACE_NODE:
1173 case LDP_L2VPN_NODE:
1174 case LDP_PSEUDOWIRE_NODE:
9e867fe6 1175 case ISIS_NODE:
718e3744 1176 case KEYCHAIN_NODE:
1177 case KEYCHAIN_KEY_NODE:
1178 case MASC_NODE:
12e41d03 1179 case PIM_NODE:
718e3744 1180 case VTY_NODE:
16f1b9ee 1181 case LINK_PARAMS_NODE:
718e3744 1182 vty_config_unlock (vty);
1183 vty->node = ENABLE_NODE;
1184 break;
1185 default:
1186 break;
1187 }
1188 return CMD_SUCCESS;
1189}
1190
1191/* Show version. */
1192DEFUN (show_version,
1193 show_version_cmd,
1194 "show version",
1195 SHOW_STR
1196 "Displays zebra version\n")
1197{
12f6ea23 1198 vty_out (vty, "Quagga %s (%s).%s", QUAGGA_VERSION, host.name?host.name:"",
d0bfb22c 1199 VTY_NEWLINE);
0be793e6 1200 vty_out (vty, "%s%s%s", QUAGGA_COPYRIGHT, GIT_INFO, VTY_NEWLINE);
80db5ac1
DL
1201 vty_out (vty, "configured with:%s %s%s", VTY_NEWLINE,
1202 QUAGGA_CONFIG_ARGS, VTY_NEWLINE);
718e3744 1203
1204 return CMD_SUCCESS;
1205}
1206
1207/* Help display function for all node. */
1208DEFUN (config_help,
1209 config_help_cmd,
1210 "help",
1211 "Description of the interactive help system\n")
1212{
d0bfb22c
QY
1213 vty_out (vty,
1214 "Quagga VTY provides advanced help feature. When you need help,%s\
718e3744 1215anytime at the command line please press '?'.%s\
1216%s\
1217If nothing matches, the help list will be empty and you must backup%s\
1218 until entering a '?' shows the available options.%s\
1219Two styles of help are provided:%s\
12201. Full help is available when you are ready to enter a%s\
1221command argument (e.g. 'show ?') and describes each possible%s\
1222argument.%s\
12232. Partial help is provided when an abbreviated argument is entered%s\
1224 and you want to know what arguments match the input%s\
1225 (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
d0bfb22c
QY
1226 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
1227 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
718e3744 1228 return CMD_SUCCESS;
1229}
1230
a2454870
QY
1231static void
1232permute (struct graph_node *start, struct vty *vty)
1233{
1234 static struct list *position = NULL;
1235 if (!position) position = list_new ();
1236
1237 // recursive dfs
1238 listnode_add (position, start);
1239 for (unsigned int i = 0; i < vector_active (start->to); i++)
1240 {
1241 struct graph_node *gn = vector_slot (start->to, i);
1242 struct cmd_token *tok = gn->data;
7a4662b4
QY
1243 if (tok->attr == CMD_ATTR_HIDDEN ||
1244 tok->attr == CMD_ATTR_DEPRECATED)
1245 continue;
1246 else if (tok->type == END_TKN || gn == start)
a2454870
QY
1247 {
1248 struct graph_node *gnn;
1249 struct listnode *ln;
1250 vty_out (vty, " ");
1251 for (ALL_LIST_ELEMENTS_RO (position,ln,gnn))
1252 {
1253 struct cmd_token *tt = gnn->data;
1254 if (tt->type < SELECTOR_TKN)
1255 vty_out (vty, " %s", tt->text);
1256 }
1257 if (gn == start)
1258 vty_out (vty, "...");
1259 vty_out (vty, VTY_NEWLINE);
1260 }
1261 else
1262 permute (gn, vty);
1263 }
1264 list_delete_node (position, listtail(position));
1265}
1266
718e3744 1267/* Help display function for all node. */
1268DEFUN (config_list,
1269 config_list_cmd,
a2454870
QY
1270 "list [permutations]",
1271 "Print command list\n"
1272 "Print all possible command permutations\n")
718e3744 1273{
a2454870
QY
1274 struct cmd_node *node = vector_slot (cmdvec, vty->node);
1275
1276 if ((strmatch (argv[0]->text, "list") && argc == 2) ||
1277 (strmatch (argv[0]->text, "show") && argc == 3))
1278 permute (vector_slot (node->cmdgraph->nodes, 0), vty);
1279 else
1280 {
1281 /* loop over all commands at this node */
1282 struct cmd_element *element = NULL;
1283 for (unsigned int i = 0; i < vector_active(node->cmd_vector); i++)
1284 if ((element = vector_slot (node->cmd_vector, i)) &&
1285 element->attr != CMD_ATTR_DEPRECATED &&
1286 element->attr != CMD_ATTR_HIDDEN)
1287 vty_out (vty, " %s%s", element->string, VTY_NEWLINE);
1288 }
718e3744 1289 return CMD_SUCCESS;
1290}
1291
a2454870
QY
1292DEFUN (show_commandtree,
1293 show_commandtree_cmd,
1294 "show commandtree [permutations]",
1295 SHOW_STR
1296 "Show command tree\n")
1297{
1298 return config_list (self, vty, argc, argv);
1299}
1300
718e3744 1301/* Write current configuration into file. */
d862bffb 1302
d0bfb22c
QY
1303DEFUN (config_write,
1304 config_write_cmd,
1305 "write [<file|memory|terminal>]",
718e3744 1306 "Write running configuration to memory, network, or terminal\n"
d0bfb22c
QY
1307 "Write to configuration file\n"
1308 "Write configuration currently in memory\n"
1309 "Write configuration to terminal\n")
718e3744 1310{
c349116d 1311 int idx_type = 1;
8c328f11 1312 unsigned int i;
718e3744 1313 int fd;
1314 struct cmd_node *node;
1315 char *config_file;
1316 char *config_file_tmp = NULL;
1317 char *config_file_sav = NULL;
05865c90 1318 int ret = CMD_WARNING;
718e3744 1319 struct vty *file_vty;
e4421165 1320 struct stat conf_stat;
718e3744 1321
d862bffb
QY
1322 // if command was 'write terminal', 'write memory' or 'show running-config'
1323 if (argc == 2 && (!strcmp(argv[idx_type]->text, "terminal") ||
1324 !strcmp(argv[idx_type]->text, "memory") ||
1325 !strcmp(argv[0]->text, "show")))
d0bfb22c
QY
1326 {
1327 if (vty->type == VTY_SHELL_SERV)
1328 {
1329 for (i = 0; i < vector_active (cmdvec); i++)
1330 if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
1331 {
1332 if ((*node->func) (vty))
1333 vty_out (vty, "!%s", VTY_NEWLINE);
1334 }
1335 }
1336 else
1337 {
1338 vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
1339 VTY_NEWLINE);
1340 vty_out (vty, "!%s", VTY_NEWLINE);
1341
1342 for (i = 0; i < vector_active (cmdvec); i++)
1343 if ((node = vector_slot (cmdvec, i)) && node->func)
1344 {
1345 if ((*node->func) (vty))
1346 vty_out (vty, "!%s", VTY_NEWLINE);
1347 }
1348 vty_out (vty, "end%s",VTY_NEWLINE);
1349 }
1350 return CMD_SUCCESS;
1351 }
1352
87f44e2f
DL
1353 if (host.noconfig)
1354 return CMD_SUCCESS;
1355
718e3744 1356 /* Check and see if we are operating under vtysh configuration */
1357 if (host.config == NULL)
1358 {
1359 vty_out (vty, "Can't save to configuration file, using vtysh.%s",
d0bfb22c 1360 VTY_NEWLINE);
718e3744 1361 return CMD_WARNING;
1362 }
1363
1364 /* Get filename. */
1365 config_file = host.config;
d0bfb22c 1366
05865c90 1367 config_file_sav =
1368 XMALLOC (MTYPE_TMP, strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
718e3744 1369 strcpy (config_file_sav, config_file);
1370 strcat (config_file_sav, CONF_BACKUP_EXT);
1371
1372
05865c90 1373 config_file_tmp = XMALLOC (MTYPE_TMP, strlen (config_file) + 8);
718e3744 1374 sprintf (config_file_tmp, "%s.XXXXXX", config_file);
d0bfb22c 1375
718e3744 1376 /* Open file to configuration write. */
1377 fd = mkstemp (config_file_tmp);
1378 if (fd < 0)
1379 {
1380 vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
d0bfb22c 1381 VTY_NEWLINE);
05865c90 1382 goto finished;
718e3744 1383 }
d0bfb22c 1384
718e3744 1385 /* Make vty for configuration file. */
1386 file_vty = vty_new ();
c5e69a02 1387 file_vty->wfd = fd;
718e3744 1388 file_vty->type = VTY_FILE;
1389
1390 /* Config file header print. */
1391 vty_out (file_vty, "!\n! Zebra configuration saved from vty\n! ");
1392 vty_time_print (file_vty, 1);
1393 vty_out (file_vty, "!\n");
1394
55468c86 1395 for (i = 0; i < vector_active (cmdvec); i++)
718e3744 1396 if ((node = vector_slot (cmdvec, i)) && node->func)
1397 {
d0bfb22c
QY
1398 if ((*node->func) (file_vty))
1399 vty_out (file_vty, "!\n");
718e3744 1400 }
1401 vty_close (file_vty);
1402
e4421165 1403 if (stat(config_file, &conf_stat) >= 0)
718e3744 1404 {
e4421165 1405 if (unlink (config_file_sav) != 0)
d0bfb22c
QY
1406 if (errno != ENOENT)
1407 {
1408 vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
1409 VTY_NEWLINE);
1410 goto finished;
1411 }
e4421165 1412 if (link (config_file, config_file_sav) != 0)
d0bfb22c
QY
1413 {
1414 vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
1415 VTY_NEWLINE);
1416 goto finished;
1417 }
e4421165
DS
1418 sync ();
1419 if (unlink (config_file) != 0)
d0bfb22c
QY
1420 {
1421 vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
1422 VTY_NEWLINE);
1423 goto finished;
1424 }
718e3744 1425 }
1426 if (link (config_file_tmp, config_file) != 0)
1427 {
1428 vty_out (vty, "Can't save configuration file %s.%s", config_file,
d0bfb22c 1429 VTY_NEWLINE);
05865c90 1430 goto finished;
718e3744 1431 }
718e3744 1432 sync ();
d0bfb22c 1433
aa593d5e 1434 if (chmod (config_file, CONFIGFILE_MASK) != 0)
1435 {
d0bfb22c
QY
1436 vty_out (vty, "Can't chmod configuration file %s: %s (%d).%s",
1437 config_file, safe_strerror(errno), errno, VTY_NEWLINE);
05865c90 1438 goto finished;
aa593d5e 1439 }
1440
718e3744 1441 vty_out (vty, "Configuration saved to %s%s", config_file,
d0bfb22c 1442 VTY_NEWLINE);
05865c90 1443 ret = CMD_SUCCESS;
1444
1445finished:
1446 unlink (config_file_tmp);
1447 XFREE (MTYPE_TMP, config_file_tmp);
1448 XFREE (MTYPE_TMP, config_file_sav);
1449 return ret;
718e3744 1450}
1451
d862bffb
QY
1452/* ALIAS_FIXME for 'write <terminal|memory>' */
1453DEFUN (show_running_config,
1454 show_running_config_cmd,
1455 "show running-config",
1456 SHOW_STR
1457 "running configuration (same as write terminal/memory)\n")
1458{
1459 return config_write (self, vty, argc, argv);
1460}
718e3744 1461
d862bffb
QY
1462/* ALIAS_FIXME for 'write file' */
1463DEFUN (copy_runningconf_startupconf,
1464 copy_runningconf_startupconf_cmd,
1465 "copy running-config startup-config",
1466 "Copy configuration\n"
1467 "Copy running config to... \n"
1468 "Copy running config to startup config (same as write file)\n")
1469{
1470 return config_write (self, vty, argc, argv);
1471}
1472/** -- **/
718e3744 1473
1474/* Write startup configuration into the terminal. */
1475DEFUN (show_startup_config,
1476 show_startup_config_cmd,
1477 "show startup-config",
1478 SHOW_STR
d0bfb22c 1479 "Contents of startup configuration\n")
718e3744 1480{
1481 char buf[BUFSIZ];
1482 FILE *confp;
1483
87f44e2f
DL
1484 if (host.noconfig)
1485 return CMD_SUCCESS;
1486 if (host.config == NULL)
1487 return CMD_WARNING;
1488
718e3744 1489 confp = fopen (host.config, "r");
1490 if (confp == NULL)
1491 {
1db63918 1492 vty_out (vty, "Can't open configuration file [%s] due to '%s'%s",
d0bfb22c 1493 host.config, safe_strerror(errno), VTY_NEWLINE);
718e3744 1494 return CMD_WARNING;
1495 }
1496
1497 while (fgets (buf, BUFSIZ, confp))
1498 {
1499 char *cp = buf;
1500
1501 while (*cp != '\r' && *cp != '\n' && *cp != '\0')
d0bfb22c 1502 cp++;
718e3744 1503 *cp = '\0';
1504
1505 vty_out (vty, "%s%s", buf, VTY_NEWLINE);
1506 }
1507
1508 fclose (confp);
1509
1510 return CMD_SUCCESS;
1511}
1512
1513/* Hostname configuration */
d0bfb22c 1514DEFUN (config_hostname,
718e3744 1515 hostname_cmd,
1516 "hostname WORD",
1517 "Set system's network name\n"
1518 "This system's network name\n")
1519{
d0bfb22c
QY
1520 struct cmd_token *word = argv[1];
1521
e4123a9b 1522 if (!isalpha((int) word->arg[0]))
718e3744 1523 {
1524 vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
1525 return CMD_WARNING;
1526 }
1527
1528 if (host.name)
05865c90 1529 XFREE (MTYPE_HOST, host.name);
d0bfb22c
QY
1530
1531 host.name = XSTRDUP (MTYPE_HOST, word->arg);
718e3744 1532 return CMD_SUCCESS;
1533}
1534
d0bfb22c 1535DEFUN (config_no_hostname,
718e3744 1536 no_hostname_cmd,
1537 "no hostname [HOSTNAME]",
1538 NO_STR
1539 "Reset system's network name\n"
1540 "Host name of this router\n")
1541{
1542 if (host.name)
05865c90 1543 XFREE (MTYPE_HOST, host.name);
718e3744 1544 host.name = NULL;
1545 return CMD_SUCCESS;
1546}
1547
1548/* VTY interface password set. */
f412b39a
DW
1549DEFUN (config_password,
1550 password_cmd,
98463e0a 1551 "password [(8-8)] WORD",
718e3744 1552 "Assign the terminal connection password\n"
1553 "Specifies a HIDDEN password will follow\n"
d0bfb22c 1554 "The password string\n")
718e3744 1555{
c349116d
DW
1556 int idx_8 = 1;
1557 int idx_word = 2;
d0bfb22c
QY
1558 if (argc == 3) // '8' was specified
1559 {
1560 if (host.password)
1561 XFREE (MTYPE_HOST, host.password);
1562 host.password = NULL;
1563 if (host.password_encrypt)
1564 XFREE (MTYPE_HOST, host.password_encrypt);
c349116d 1565 host.password_encrypt = XSTRDUP (MTYPE_HOST, argv[idx_word]->arg);
d0bfb22c
QY
1566 return CMD_SUCCESS;
1567 }
718e3744 1568
c349116d 1569 if (!isalnum (argv[idx_8]->arg[0]))
718e3744 1570 {
d0bfb22c
QY
1571 vty_out (vty,
1572 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
718e3744 1573 return CMD_WARNING;
1574 }
1575
1576 if (host.password)
05865c90 1577 XFREE (MTYPE_HOST, host.password);
718e3744 1578 host.password = NULL;
1579
1580 if (host.encrypt)
1581 {
1582 if (host.password_encrypt)
d0bfb22c 1583 XFREE (MTYPE_HOST, host.password_encrypt);
c349116d 1584 host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[idx_8]->arg));
718e3744 1585 }
1586 else
c349116d 1587 host.password = XSTRDUP (MTYPE_HOST, argv[idx_8]->arg);
718e3744 1588
1589 return CMD_SUCCESS;
1590}
1591
718e3744 1592/* VTY enable password set. */
f412b39a
DW
1593DEFUN (config_enable_password,
1594 enable_password_cmd,
98463e0a 1595 "enable password [(8-8)] WORD",
718e3744 1596 "Modify enable password parameters\n"
1597 "Assign the privileged level password\n"
1598 "Specifies a HIDDEN password will follow\n"
718e3744 1599 "The HIDDEN 'enable' password string\n")
1600{
c349116d
DW
1601 int idx_8 = 2;
1602 int idx_word = 3;
58749582 1603
718e3744 1604 /* Crypt type is specified. */
d0bfb22c 1605 if (argc == 4)
718e3744 1606 {
c349116d 1607 if (argv[idx_8]->arg[0] == '8')
d0bfb22c
QY
1608 {
1609 if (host.enable)
1610 XFREE (MTYPE_HOST, host.enable);
1611 host.enable = NULL;
1612
1613 if (host.enable_encrypt)
1614 XFREE (MTYPE_HOST, host.enable_encrypt);
c349116d 1615 host.enable_encrypt = XSTRDUP (MTYPE_HOST, argv[idx_word]->arg);
d0bfb22c
QY
1616
1617 return CMD_SUCCESS;
1618 }
718e3744 1619 else
d0bfb22c
QY
1620 {
1621 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
1622 return CMD_WARNING;
1623 }
718e3744 1624 }
1625
c349116d 1626 if (!isalnum (argv[idx_8]->arg[0]))
718e3744 1627 {
d0bfb22c
QY
1628 vty_out (vty,
1629 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
718e3744 1630 return CMD_WARNING;
1631 }
1632
1633 if (host.enable)
05865c90 1634 XFREE (MTYPE_HOST, host.enable);
718e3744 1635 host.enable = NULL;
1636
1637 /* Plain password input. */
1638 if (host.encrypt)
1639 {
1640 if (host.enable_encrypt)
d0bfb22c 1641 XFREE (MTYPE_HOST, host.enable_encrypt);
c349116d 1642 host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[idx_8]->arg));
718e3744 1643 }
1644 else
c349116d 1645 host.enable = XSTRDUP (MTYPE_HOST, argv[idx_8]->arg);
718e3744 1646
1647 return CMD_SUCCESS;
1648}
1649
718e3744 1650/* VTY enable password delete. */
f412b39a
DW
1651DEFUN (no_config_enable_password,
1652 no_enable_password_cmd,
718e3744 1653 "no enable password",
1654 NO_STR
1655 "Modify enable password parameters\n"
1656 "Assign the privileged level password\n")
1657{
1658 if (host.enable)
05865c90 1659 XFREE (MTYPE_HOST, host.enable);
718e3744 1660 host.enable = NULL;
1661
1662 if (host.enable_encrypt)
05865c90 1663 XFREE (MTYPE_HOST, host.enable_encrypt);
718e3744 1664 host.enable_encrypt = NULL;
1665
1666 return CMD_SUCCESS;
1667}
d0bfb22c 1668
718e3744 1669DEFUN (service_password_encrypt,
1670 service_password_encrypt_cmd,
1671 "service password-encryption",
1672 "Set up miscellaneous service\n"
1673 "Enable encrypted passwords\n")
1674{
1675 if (host.encrypt)
1676 return CMD_SUCCESS;
1677
1678 host.encrypt = 1;
1679
1680 if (host.password)
1681 {
1682 if (host.password_encrypt)
d0bfb22c 1683 XFREE (MTYPE_HOST, host.password_encrypt);
05865c90 1684 host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.password));
718e3744 1685 }
1686 if (host.enable)
1687 {
1688 if (host.enable_encrypt)
d0bfb22c 1689 XFREE (MTYPE_HOST, host.enable_encrypt);
05865c90 1690 host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.enable));
718e3744 1691 }
1692
1693 return CMD_SUCCESS;
1694}
1695
1696DEFUN (no_service_password_encrypt,
1697 no_service_password_encrypt_cmd,
1698 "no service password-encryption",
1699 NO_STR
1700 "Set up miscellaneous service\n"
1701 "Enable encrypted passwords\n")
1702{
1703 if (! host.encrypt)
1704 return CMD_SUCCESS;
1705
1706 host.encrypt = 0;
1707
1708 if (host.password_encrypt)
05865c90 1709 XFREE (MTYPE_HOST, host.password_encrypt);
718e3744 1710 host.password_encrypt = NULL;
1711
1712 if (host.enable_encrypt)
05865c90 1713 XFREE (MTYPE_HOST, host.enable_encrypt);
718e3744 1714 host.enable_encrypt = NULL;
1715
1716 return CMD_SUCCESS;
1717}
1718
f412b39a
DW
1719DEFUN (config_terminal_length,
1720 config_terminal_length_cmd,
d0bfb22c 1721 "terminal length (0-512)",
718e3744 1722 "Set terminal line parameters\n"
1723 "Set number of lines on a screen\n"
1724 "Number of lines on screen (0 for no pausing)\n")
1725{
c349116d 1726 int idx_number = 2;
718e3744 1727 int lines;
1728 char *endptr = NULL;
1729
c349116d 1730 lines = strtol (argv[idx_number]->arg, &endptr, 10);
718e3744 1731 if (lines < 0 || lines > 512 || *endptr != '\0')
1732 {
1733 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
1734 return CMD_WARNING;
1735 }
1736 vty->lines = lines;
1737
1738 return CMD_SUCCESS;
1739}
1740
f412b39a
DW
1741DEFUN (config_terminal_no_length,
1742 config_terminal_no_length_cmd,
718e3744 1743 "terminal no length",
1744 "Set terminal line parameters\n"
1745 NO_STR
1746 "Set number of lines on a screen\n")
1747{
1748 vty->lines = -1;
1749 return CMD_SUCCESS;
1750}
1751
f412b39a
DW
1752DEFUN (service_terminal_length,
1753 service_terminal_length_cmd,
d0bfb22c 1754 "service terminal-length (0-512)",
718e3744 1755 "Set up miscellaneous service\n"
1756 "System wide terminal length configuration\n"
1757 "Number of lines of VTY (0 means no line control)\n")
1758{
c349116d 1759 int idx_number = 2;
718e3744 1760 int lines;
1761 char *endptr = NULL;
1762
c349116d 1763 lines = strtol (argv[idx_number]->arg, &endptr, 10);
718e3744 1764 if (lines < 0 || lines > 512 || *endptr != '\0')
1765 {
1766 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
1767 return CMD_WARNING;
1768 }
1769 host.lines = lines;
1770
1771 return CMD_SUCCESS;
1772}
1773
f412b39a
DW
1774DEFUN (no_service_terminal_length,
1775 no_service_terminal_length_cmd,
d0bfb22c 1776 "no service terminal-length [(0-512)]",
718e3744 1777 NO_STR
1778 "Set up miscellaneous service\n"
1779 "System wide terminal length configuration\n"
1780 "Number of lines of VTY (0 means no line control)\n")
1781{
1782 host.lines = -1;
1783 return CMD_SUCCESS;
1784}
1785
2885f72d 1786DEFUN_HIDDEN (do_echo,
d0bfb22c
QY
1787 echo_cmd,
1788 "echo MESSAGE...",
1789 "Echo a message back to the vty\n"
1790 "The message to echo\n")
2885f72d 1791{
1792 char *message;
1793
58749582 1794 vty_out (vty, "%s%s", ((message = argv_concat (argv, argc, 1)) ? message : ""),
d0bfb22c 1795 VTY_NEWLINE);
f6834d4c 1796 if (message)
1797 XFREE(MTYPE_TMP, message);
2885f72d 1798 return CMD_SUCCESS;
1799}
1800
274a4a44 1801DEFUN (config_logmsg,
1802 config_logmsg_cmd,
199d90a1 1803 "logmsg <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging> MESSAGE...",
274a4a44 1804 "Send a message to enabled logging destinations\n"
1805 LOG_LEVEL_DESC
1806 "The message to send\n")
1807{
c349116d 1808 int idx_log_level = 1;
58749582 1809 int idx_message = 2;
274a4a44 1810 int level;
1811 char *message;
1812
c349116d 1813 if ((level = level_match(argv[idx_log_level]->arg)) == ZLOG_DISABLED)
274a4a44 1814 return CMD_ERR_NO_MATCH;
1815
58749582 1816 zlog(NULL, level, "%s", ((message = argv_concat(argv, argc, idx_message)) ? message : ""));
f6834d4c 1817 if (message)
1818 XFREE(MTYPE_TMP, message);
65efcfce 1819
274a4a44 1820 return CMD_SUCCESS;
1821}
1822
1823DEFUN (show_logging,
1824 show_logging_cmd,
1825 "show logging",
1826 SHOW_STR
1827 "Show current logging configuration\n")
1828{
1829 struct zlog *zl = zlog_default;
1830
1831 vty_out (vty, "Syslog logging: ");
1832 if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED)
1833 vty_out (vty, "disabled");
1834 else
1835 vty_out (vty, "level %s, facility %s, ident %s",
d0bfb22c
QY
1836 zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]],
1837 facility_name(zl->facility), zl->ident);
274a4a44 1838 vty_out (vty, "%s", VTY_NEWLINE);
1839
1840 vty_out (vty, "Stdout logging: ");
1841 if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED)
1842 vty_out (vty, "disabled");
1843 else
1844 vty_out (vty, "level %s",
d0bfb22c 1845 zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
274a4a44 1846 vty_out (vty, "%s", VTY_NEWLINE);
1847
1848 vty_out (vty, "Monitor logging: ");
1849 if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
1850 vty_out (vty, "disabled");
1851 else
1852 vty_out (vty, "level %s",
d0bfb22c 1853 zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
274a4a44 1854 vty_out (vty, "%s", VTY_NEWLINE);
1855
1856 vty_out (vty, "File logging: ");
1857 if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) ||
1858 !zl->fp)
1859 vty_out (vty, "disabled");
1860 else
1861 vty_out (vty, "level %s, filename %s",
d0bfb22c
QY
1862 zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
1863 zl->filename);
274a4a44 1864 vty_out (vty, "%s", VTY_NEWLINE);
1865
1866 vty_out (vty, "Protocol name: %s%s",
d0bfb22c 1867 zlog_proto_names[zl->protocol], VTY_NEWLINE);
274a4a44 1868 vty_out (vty, "Record priority: %s%s",
d0bfb22c 1869 (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE);
1ed72e0b 1870 vty_out (vty, "Timestamp precision: %d%s",
d0bfb22c 1871 zl->timestamp_precision, VTY_NEWLINE);
274a4a44 1872
1873 return CMD_SUCCESS;
1874}
1875
718e3744 1876DEFUN (config_log_stdout,
1877 config_log_stdout_cmd,
6de69f83 1878 "log stdout [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
274a4a44 1879 "Logging control\n"
1880 "Set stdout logging level\n"
1881 LOG_LEVEL_DESC)
1882{
c349116d 1883 int idx_log_level = 2;
58749582
DW
1884
1885 if (argc == idx_log_level)
d0bfb22c
QY
1886 {
1887 zlog_set_level (NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl);
1888 return CMD_SUCCESS;
1889 }
274a4a44 1890 int level;
1891
c349116d 1892 if ((level = level_match(argv[idx_log_level]->arg)) == ZLOG_DISABLED)
274a4a44 1893 return CMD_ERR_NO_MATCH;
1894 zlog_set_level (NULL, ZLOG_DEST_STDOUT, level);
718e3744 1895 return CMD_SUCCESS;
1896}
1897
1898DEFUN (no_config_log_stdout,
1899 no_config_log_stdout_cmd,
6de69f83 1900 "no log stdout [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
718e3744 1901 NO_STR
1902 "Logging control\n"
274a4a44 1903 "Cancel logging to stdout\n"
d0bfb22c 1904 LOG_LEVEL_DESC)
718e3744 1905{
274a4a44 1906 zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED);
718e3744 1907 return CMD_SUCCESS;
1908}
1909
274a4a44 1910DEFUN (config_log_monitor,
1911 config_log_monitor_cmd,
6de69f83 1912 "log monitor [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
274a4a44 1913 "Logging control\n"
1914 "Set terminal line (monitor) logging level\n"
1915 LOG_LEVEL_DESC)
1916{
c349116d 1917 int idx_log_level = 2;
58749582
DW
1918
1919 if (argc == idx_log_level)
d0bfb22c
QY
1920 {
1921 zlog_set_level (NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl);
1922 return CMD_SUCCESS;
1923 }
274a4a44 1924 int level;
1925
c349116d 1926 if ((level = level_match(argv[idx_log_level]->arg)) == ZLOG_DISABLED)
274a4a44 1927 return CMD_ERR_NO_MATCH;
1928 zlog_set_level (NULL, ZLOG_DEST_MONITOR, level);
1929 return CMD_SUCCESS;
1930}
1931
1932DEFUN (no_config_log_monitor,
1933 no_config_log_monitor_cmd,
6de69f83 1934 "no log monitor [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
274a4a44 1935 NO_STR
1936 "Logging control\n"
1937 "Disable terminal line (monitor) logging\n"
d0bfb22c 1938 LOG_LEVEL_DESC)
274a4a44 1939{
1940 zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
1941 return CMD_SUCCESS;
1942}
1943
1944static int
1945set_log_file(struct vty *vty, const char *fname, int loglevel)
718e3744 1946{
1947 int ret;
9035efaa 1948 char *p = NULL;
1949 const char *fullpath;
d0bfb22c 1950
718e3744 1951 /* Path detection. */
274a4a44 1952 if (! IS_DIRECTORY_SEP (*fname))
718e3744 1953 {
9035efaa 1954 char cwd[MAXPATHLEN+1];
1955 cwd[MAXPATHLEN] = '\0';
d0bfb22c 1956
9035efaa 1957 if (getcwd (cwd, MAXPATHLEN) == NULL)
1958 {
1959 zlog_err ("config_log_file: Unable to alloc mem!");
1960 return CMD_WARNING;
1961 }
d0bfb22c 1962
274a4a44 1963 if ( (p = XMALLOC (MTYPE_TMP, strlen (cwd) + strlen (fname) + 2))
9035efaa 1964 == NULL)
1965 {
1966 zlog_err ("config_log_file: Unable to alloc mem!");
1967 return CMD_WARNING;
1968 }
274a4a44 1969 sprintf (p, "%s/%s", cwd, fname);
9035efaa 1970 fullpath = p;
718e3744 1971 }
1972 else
274a4a44 1973 fullpath = fname;
718e3744 1974
274a4a44 1975 ret = zlog_set_file (NULL, fullpath, loglevel);
718e3744 1976
9035efaa 1977 if (p)
1978 XFREE (MTYPE_TMP, p);
1979
718e3744 1980 if (!ret)
1981 {
274a4a44 1982 vty_out (vty, "can't open logfile %s\n", fname);
718e3744 1983 return CMD_WARNING;
1984 }
1985
1986 if (host.logfile)
05865c90 1987 XFREE (MTYPE_HOST, host.logfile);
718e3744 1988
05865c90 1989 host.logfile = XSTRDUP (MTYPE_HOST, fname);
718e3744 1990
c05795b1
SK
1991#if defined(HAVE_CUMULUS)
1992 if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED)
1993 zlog_default->maxlvl[ZLOG_DEST_SYSLOG] = ZLOG_DISABLED;
1994#endif
718e3744 1995 return CMD_SUCCESS;
1996}
1997
274a4a44 1998DEFUN (config_log_file,
1999 config_log_file_cmd,
6de69f83 2000 "log file FILENAME [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
274a4a44 2001 "Logging control\n"
2002 "Logging to file\n"
2003 "Logging filename\n"
2004 LOG_LEVEL_DESC)
2005{
c349116d
DW
2006 int idx_filename = 2;
2007 int idx_log_levels = 3;
d0bfb22c
QY
2008 if (argc == 4)
2009 {
2010 int level;
c349116d 2011 if ((level = level_match(argv[idx_log_levels]->arg)) == ZLOG_DISABLED)
d0bfb22c 2012 return CMD_ERR_NO_MATCH;
c349116d 2013 return set_log_file(vty, argv[idx_filename]->arg, level);
d0bfb22c
QY
2014 }
2015 else
c349116d 2016 return set_log_file(vty, argv[idx_filename]->arg, zlog_default->default_lvl);
274a4a44 2017}
2018
718e3744 2019DEFUN (no_config_log_file,
2020 no_config_log_file_cmd,
d0bfb22c 2021 "no log file [FILENAME [LEVEL]]",
718e3744 2022 NO_STR
2023 "Logging control\n"
2024 "Cancel logging to file\n"
d0bfb22c
QY
2025 "Logging file name\n"
2026 "Logging file name\n"
2027 "Logging level\n")
718e3744 2028{
2029 zlog_reset_file (NULL);
2030
2031 if (host.logfile)
05865c90 2032 XFREE (MTYPE_HOST, host.logfile);
718e3744 2033
2034 host.logfile = NULL;
2035
2036 return CMD_SUCCESS;
2037}
2038
2039DEFUN (config_log_syslog,
2040 config_log_syslog_cmd,
6de69f83 2041 "log syslog [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
12ab19f1 2042 "Logging control\n"
274a4a44 2043 "Set syslog logging level\n"
2044 LOG_LEVEL_DESC)
2045{
c349116d 2046 int idx_log_levels = 2;
d0bfb22c
QY
2047 if (argc == 3)
2048 {
2049 int level;
c349116d 2050 if ((level = level_match (argv[idx_log_levels]->arg)) == ZLOG_DISABLED)
d0bfb22c
QY
2051 return CMD_ERR_NO_MATCH;
2052 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, level);
2053 return CMD_SUCCESS;
2054 }
2055 else
2056 {
2057 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
2058 return CMD_SUCCESS;
2059 }
274a4a44 2060}
2061
2062DEFUN_DEPRECATED (config_log_syslog_facility,
d0bfb22c 2063 config_log_syslog_facility_cmd,
199d90a1 2064 "log syslog facility (kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7)",
d0bfb22c
QY
2065 "Logging control\n"
2066 "Logging goes to syslog\n"
2067 "(Deprecated) Facility parameter for syslog messages\n"
2068 LOG_FACILITY_DESC)
274a4a44 2069{
d0bfb22c 2070 int facility = facility_match(argv[3]->arg);
12ab19f1 2071
274a4a44 2072 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
2073 zlog_default->facility = facility;
718e3744 2074 return CMD_SUCCESS;
2075}
2076
2077DEFUN (no_config_log_syslog,
2078 no_config_log_syslog_cmd,
6de69f83 2079 "no log syslog [<kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>] [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
718e3744 2080 NO_STR
2081 "Logging control\n"
274a4a44 2082 "Cancel logging to syslog\n"
d0bfb22c
QY
2083 LOG_FACILITY_DESC
2084 LOG_LEVEL_DESC)
718e3744 2085{
274a4a44 2086 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
718e3744 2087 return CMD_SUCCESS;
2088}
2089
274a4a44 2090DEFUN (config_log_facility,
2091 config_log_facility_cmd,
9ccf14f7 2092 "log facility <kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>",
718e3744 2093 "Logging control\n"
274a4a44 2094 "Facility parameter for syslog messages\n"
2095 LOG_FACILITY_DESC)
718e3744 2096{
c349116d
DW
2097 int idx_target = 2;
2098 int facility = facility_match(argv[idx_target]->arg);
274a4a44 2099
274a4a44 2100 zlog_default->facility = facility;
2101 return CMD_SUCCESS;
718e3744 2102}
2103
274a4a44 2104DEFUN (no_config_log_facility,
2105 no_config_log_facility_cmd,
9ccf14f7 2106 "no log facility [<kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>]",
718e3744 2107 NO_STR
2108 "Logging control\n"
274a4a44 2109 "Reset syslog facility to default (daemon)\n"
d0bfb22c 2110 LOG_FACILITY_DESC)
274a4a44 2111{
2112 zlog_default->facility = LOG_DAEMON;
2113 return CMD_SUCCESS;
2114}
2115
2116DEFUN_DEPRECATED (config_log_trap,
d0bfb22c 2117 config_log_trap_cmd,
199d90a1 2118 "log trap <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>",
d0bfb22c
QY
2119 "Logging control\n"
2120 "(Deprecated) Set logging level and default for all destinations\n"
2121 LOG_LEVEL_DESC)
274a4a44 2122{
2123 int new_level ;
2124 int i;
d0bfb22c
QY
2125
2126 if ((new_level = level_match(argv[2]->arg)) == ZLOG_DISABLED)
274a4a44 2127 return CMD_ERR_NO_MATCH;
2128
2129 zlog_default->default_lvl = new_level;
2130 for (i = 0; i < ZLOG_NUM_DESTS; i++)
2131 if (zlog_default->maxlvl[i] != ZLOG_DISABLED)
2132 zlog_default->maxlvl[i] = new_level;
2133 return CMD_SUCCESS;
2134}
2135
2136DEFUN_DEPRECATED (no_config_log_trap,
d0bfb22c 2137 no_config_log_trap_cmd,
199d90a1 2138 "no log trap [emergencies|alerts|critical|errors|warnings|notifications|informational|debugging]",
d0bfb22c
QY
2139 NO_STR
2140 "Logging control\n"
2141 "Permit all logging information\n"
2142 LOG_LEVEL_DESC)
718e3744 2143{
274a4a44 2144 zlog_default->default_lvl = LOG_DEBUG;
718e3744 2145 return CMD_SUCCESS;
2146}
2147
2148DEFUN (config_log_record_priority,
2149 config_log_record_priority_cmd,
2150 "log record-priority",
2151 "Logging control\n"
2152 "Log the priority of the message within the message\n")
2153{
2154 zlog_default->record_priority = 1 ;
2155 return CMD_SUCCESS;
2156}
2157
2158DEFUN (no_config_log_record_priority,
2159 no_config_log_record_priority_cmd,
2160 "no log record-priority",
2161 NO_STR
2162 "Logging control\n"
2163 "Do not log the priority of the message within the message\n")
2164{
2165 zlog_default->record_priority = 0 ;
2166 return CMD_SUCCESS;
2167}
2168
1ed72e0b
AS
2169DEFUN (config_log_timestamp_precision,
2170 config_log_timestamp_precision_cmd,
6147e2c6 2171 "log timestamp precision (0-6)",
1ed72e0b
AS
2172 "Logging control\n"
2173 "Timestamp configuration\n"
2174 "Set the timestamp precision\n"
2175 "Number of subsecond digits\n")
2176{
c349116d 2177 int idx_number = 3;
1ed72e0b 2178 VTY_GET_INTEGER_RANGE("Timestamp Precision",
c349116d 2179 zlog_default->timestamp_precision, argv[idx_number]->arg, 0, 6);
1ed72e0b
AS
2180 return CMD_SUCCESS;
2181}
2182
2183DEFUN (no_config_log_timestamp_precision,
2184 no_config_log_timestamp_precision_cmd,
2185 "no log timestamp precision",
2186 NO_STR
2187 "Logging control\n"
2188 "Timestamp configuration\n"
2189 "Reset the timestamp precision to the default value of 0\n")
2190{
2191 zlog_default->timestamp_precision = 0 ;
2192 return CMD_SUCCESS;
2193}
2194
7cfc61d3
DS
2195int
2196cmd_banner_motd_file (const char *file)
2197{
1ee08155
DS
2198 int success = CMD_SUCCESS;
2199 char p[PATH_MAX];
2200 char *rpath;
2201 char *in;
7cfc61d3 2202
1ee08155
DS
2203 rpath = realpath (file, p);
2204 if (!rpath)
2205 return CMD_ERR_NO_FILE;
2206 in = strstr (rpath, SYSCONFDIR);
2207 if (in == rpath)
2208 {
2209 if (host.motdfile)
844ec28c 2210 XFREE (MTYPE_HOST, host.motdfile);
1ee08155
DS
2211 host.motdfile = XSTRDUP (MTYPE_HOST, file);
2212 }
2213 else
2214 success = CMD_WARNING;
2215
2216 return success;
7cfc61d3
DS
2217}
2218
3b0c5d9a 2219DEFUN (banner_motd_file,
2220 banner_motd_file_cmd,
4d833e55 2221 "banner motd file FILE",
3b0c5d9a 2222 "Set banner\n"
2223 "Banner for motd\n"
2224 "Banner from a file\n"
2225 "Filename\n")
2226{
c349116d
DW
2227 int idx_file = 3;
2228 const char *filename = argv[idx_file]->arg;
97e5b7c0 2229 int cmd = cmd_banner_motd_file (filename);
1ee08155
DS
2230
2231 if (cmd == CMD_ERR_NO_FILE)
97e5b7c0 2232 vty_out (vty, "%s does not exist", filename);
1ee08155 2233 else if (cmd == CMD_WARNING)
97e5b7c0 2234 vty_out (vty, "%s must be in %s", filename, SYSCONFDIR);
1ee08155
DS
2235
2236 return cmd;
3b0c5d9a 2237}
718e3744 2238
2239DEFUN (banner_motd_default,
2240 banner_motd_default_cmd,
2241 "banner motd default",
2242 "Set banner string\n"
2243 "Strings for motd\n"
2244 "Default string\n")
2245{
2246 host.motd = default_motd;
2247 return CMD_SUCCESS;
2248}
2249
2250DEFUN (no_banner_motd,
2251 no_banner_motd_cmd,
2252 "no banner motd",
2253 NO_STR
2254 "Set banner string\n"
2255 "Strings for motd\n")
2256{
2257 host.motd = NULL;
d0bfb22c 2258 if (host.motdfile)
05865c90 2259 XFREE (MTYPE_HOST, host.motdfile);
3b0c5d9a 2260 host.motdfile = NULL;
718e3744 2261 return CMD_SUCCESS;
2262}
2263
2264/* Set config filename. Called from vty.c */
2265void
c0e8c16f 2266host_config_set (const char *filename)
718e3744 2267{
228da428
CC
2268 if (host.config)
2269 XFREE (MTYPE_HOST, host.config);
05865c90 2270 host.config = XSTRDUP (MTYPE_HOST, filename);
718e3744 2271}
2272
57387fb2
CF
2273const char *
2274host_config_get (void)
2275{
2276 return host.config;
2277}
2278
718e3744 2279void
2280install_default (enum node_type node)
2281{
2282 install_element (node, &config_exit_cmd);
d862bffb 2283 install_element (node, &config_quit_cmd);
718e3744 2284 install_element (node, &config_end_cmd);
2285 install_element (node, &config_help_cmd);
2286 install_element (node, &config_list_cmd);
2287
718e3744 2288 install_element (node, &config_write_cmd);
d862bffb 2289 install_element (node, &show_running_config_cmd);
718e3744 2290}
2291
87f44e2f
DL
2292/* Initialize command interface. Install basic nodes and commands.
2293 *
2294 * terminal = 0 -- vtysh / no logging, no config control
2295 * terminal = 1 -- normal daemon
2296 * terminal = -1 -- watchquagga / no logging, but minimal config control */
718e3744 2297void
2298cmd_init (int terminal)
2299{
1bf9f027
DL
2300 qobj_init ();
2301
718e3744 2302 /* Allocate initial top vector of commands. */
2303 cmdvec = vector_init (VECTOR_MIN_SIZE);
2304
2305 /* Default host value settings. */
2306 host.name = NULL;
2307 host.password = NULL;
2308 host.enable = NULL;
2309 host.logfile = NULL;
2310 host.config = NULL;
87f44e2f 2311 host.noconfig = (terminal < 0);
718e3744 2312 host.lines = -1;
2313 host.motd = default_motd;
3b0c5d9a 2314 host.motdfile = NULL;
718e3744 2315
2316 /* Install top nodes. */
2317 install_node (&view_node, NULL);
2318 install_node (&enable_node, NULL);
2319 install_node (&auth_node, NULL);
2320 install_node (&auth_enable_node, NULL);
2321 install_node (&config_node, config_write_host);
2322
2323 /* Each node's basic commands. */
2324 install_element (VIEW_NODE, &show_version_cmd);
2325 if (terminal)
2326 {
2327 install_element (VIEW_NODE, &config_list_cmd);
2328 install_element (VIEW_NODE, &config_exit_cmd);
d862bffb 2329 install_element (VIEW_NODE, &config_quit_cmd);
718e3744 2330 install_element (VIEW_NODE, &config_help_cmd);
2331 install_element (VIEW_NODE, &config_enable_cmd);
2332 install_element (VIEW_NODE, &config_terminal_length_cmd);
2333 install_element (VIEW_NODE, &config_terminal_no_length_cmd);
274a4a44 2334 install_element (VIEW_NODE, &show_logging_cmd);
bcd9fa7f 2335 install_element (VIEW_NODE, &show_commandtree_cmd);
2885f72d 2336 install_element (VIEW_NODE, &echo_cmd);
718e3744 2337 }
2338
2339 if (terminal)
2340 {
6694f68c 2341 install_element (ENABLE_NODE, &config_end_cmd);
718e3744 2342 install_element (ENABLE_NODE, &config_disable_cmd);
2343 install_element (ENABLE_NODE, &config_terminal_cmd);
d862bffb 2344 install_element (ENABLE_NODE, &copy_runningconf_startupconf_cmd);
6694f68c
RW
2345 install_element (ENABLE_NODE, &config_write_cmd);
2346 install_element (ENABLE_NODE, &show_running_config_cmd);
718e3744 2347 }
2348 install_element (ENABLE_NODE, &show_startup_config_cmd);
718e3744 2349
718e3744 2350 if (terminal)
2351 {
274a4a44 2352 install_element (ENABLE_NODE, &config_logmsg_cmd);
e7168df4 2353 install_default (CONFIG_NODE);
87f44e2f
DL
2354
2355 install_element (VIEW_NODE, &show_thread_cpu_cmd);
2356 install_element (ENABLE_NODE, &clear_thread_cpu_cmd);
2357
2358 install_element (VIEW_NODE, &show_work_queues_cmd);
ea8e9d97 2359 }
d0bfb22c 2360
ea8e9d97 2361 install_element (CONFIG_NODE, &hostname_cmd);
2362 install_element (CONFIG_NODE, &no_hostname_cmd);
e7168df4 2363
87f44e2f 2364 if (terminal > 0)
ea8e9d97 2365 {
e7168df4 2366 install_element (CONFIG_NODE, &password_cmd);
e7168df4 2367 install_element (CONFIG_NODE, &enable_password_cmd);
e7168df4 2368 install_element (CONFIG_NODE, &no_enable_password_cmd);
2369
718e3744 2370 install_element (CONFIG_NODE, &config_log_stdout_cmd);
2371 install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
274a4a44 2372 install_element (CONFIG_NODE, &config_log_monitor_cmd);
274a4a44 2373 install_element (CONFIG_NODE, &no_config_log_monitor_cmd);
718e3744 2374 install_element (CONFIG_NODE, &config_log_file_cmd);
2375 install_element (CONFIG_NODE, &no_config_log_file_cmd);
2376 install_element (CONFIG_NODE, &config_log_syslog_cmd);
2377 install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
274a4a44 2378 install_element (CONFIG_NODE, &config_log_facility_cmd);
2379 install_element (CONFIG_NODE, &no_config_log_facility_cmd);
718e3744 2380 install_element (CONFIG_NODE, &config_log_trap_cmd);
2381 install_element (CONFIG_NODE, &no_config_log_trap_cmd);
2382 install_element (CONFIG_NODE, &config_log_record_priority_cmd);
2383 install_element (CONFIG_NODE, &no_config_log_record_priority_cmd);
1ed72e0b
AS
2384 install_element (CONFIG_NODE, &config_log_timestamp_precision_cmd);
2385 install_element (CONFIG_NODE, &no_config_log_timestamp_precision_cmd);
718e3744 2386 install_element (CONFIG_NODE, &service_password_encrypt_cmd);
2387 install_element (CONFIG_NODE, &no_service_password_encrypt_cmd);
2388 install_element (CONFIG_NODE, &banner_motd_default_cmd);
3b0c5d9a 2389 install_element (CONFIG_NODE, &banner_motd_file_cmd);
718e3744 2390 install_element (CONFIG_NODE, &no_banner_motd_cmd);
2391 install_element (CONFIG_NODE, &service_terminal_length_cmd);
2392 install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
718e3744 2393
19dc275e 2394 vrf_install_commands ();
9ab6812d 2395 }
b06fd125 2396 srandom(time(NULL));
718e3744 2397}
228da428 2398
d0bfb22c 2399struct cmd_token *
ce882f81 2400new_cmd_token (enum cmd_token_type type, u_char attr, char *text, char *desc)
cd40b329 2401{
d0bfb22c
QY
2402 struct cmd_token *token = XMALLOC (MTYPE_CMD_TOKENS, sizeof (struct cmd_token));
2403 token->type = type;
ce882f81 2404 token->attr = attr;
d0bfb22c
QY
2405 token->text = text;
2406 token->desc = desc;
2407 token->arg = NULL;
cd40b329 2408
d0bfb22c
QY
2409 return token;
2410}
cd40b329 2411
d0bfb22c
QY
2412void
2413del_cmd_token (struct cmd_token *token)
2414{
2415 if (!token) return;
cd40b329 2416
d0bfb22c 2417 if (token->text)
17aca20b 2418 XFREE (MTYPE_CMD_TOKENS, token->text);
d0bfb22c 2419 if (token->desc)
17aca20b 2420 XFREE (MTYPE_CMD_TOKENS, token->desc);
d0bfb22c 2421 if (token->arg)
17aca20b 2422 XFREE (MTYPE_CMD_TOKENS, token->arg);
cd40b329 2423
17aca20b 2424 XFREE (MTYPE_CMD_TOKENS, token);
cd40b329
CF
2425}
2426
d0bfb22c
QY
2427struct cmd_token *
2428copy_cmd_token (struct cmd_token *token)
cd40b329 2429{
ce882f81 2430 struct cmd_token *copy = new_cmd_token (token->type, token->attr, NULL, NULL);
d0bfb22c
QY
2431 copy->max = token->max;
2432 copy->min = token->min;
2433 copy->text = token->text ? XSTRDUP (MTYPE_CMD_TOKENS, token->text) : NULL;
2434 copy->desc = token->desc ? XSTRDUP (MTYPE_CMD_TOKENS, token->desc) : NULL;
2435 copy->arg = token->arg ? XSTRDUP (MTYPE_CMD_TOKENS, token->arg) : NULL;
cd40b329 2436
d0bfb22c 2437 return copy;
cd40b329
CF
2438}
2439
de9d7e4f 2440void
1eb5e8dc 2441del_cmd_element(struct cmd_element *cmd)
de9d7e4f
QY
2442{
2443 if (!cmd) return;
97e5b7c0
QY
2444 free ((char *) cmd->string);
2445 free ((char *) cmd->doc);
2446 free (cmd);
de9d7e4f
QY
2447}
2448
2449struct cmd_element *
17aca20b 2450copy_cmd_element(const struct cmd_element *cmd)
de9d7e4f
QY
2451{
2452 struct cmd_element *el = XMALLOC(MTYPE_CMD_TOKENS, sizeof (struct cmd_element));
2453 el->string = cmd->string ? XSTRDUP(MTYPE_CMD_TOKENS, cmd->string) : NULL;
2454 el->func = cmd->func;
2455 el->doc = cmd->doc ? XSTRDUP(MTYPE_CMD_TOKENS, cmd->doc) : NULL;
2456 el->daemon = cmd->daemon;
de9d7e4f 2457 el->attr = cmd->attr;
de9d7e4f
QY
2458 return el;
2459}
2460
228da428
CC
2461void
2462cmd_terminate ()
2463{
228da428 2464 struct cmd_node *cmd_node;
228da428
CC
2465
2466 if (cmdvec)
2467 {
d0bfb22c 2468 for (unsigned int i = 0; i < vector_active (cmdvec); i++)
228da428 2469 if ((cmd_node = vector_slot (cmdvec, i)) != NULL)
d0bfb22c
QY
2470 {
2471 // deleting the graph delets the cmd_element as well
2472 graph_delete_graph (cmd_node->cmdgraph);
2473 vector_free (cmd_node->cmd_vector);
39e92c06
QY
2474 hash_clean (cmd_node->cmd_hash, NULL);
2475 hash_free (cmd_node->cmd_hash);
2476 cmd_node->cmd_hash = NULL;
d0bfb22c 2477 }
228da428
CC
2478
2479 vector_free (cmdvec);
2480 cmdvec = NULL;
2481 }
2482
228da428
CC
2483 if (host.name)
2484 XFREE (MTYPE_HOST, host.name);
2485 if (host.password)
2486 XFREE (MTYPE_HOST, host.password);
2487 if (host.password_encrypt)
2488 XFREE (MTYPE_HOST, host.password_encrypt);
2489 if (host.enable)
2490 XFREE (MTYPE_HOST, host.enable);
2491 if (host.enable_encrypt)
2492 XFREE (MTYPE_HOST, host.enable_encrypt);
2493 if (host.logfile)
2494 XFREE (MTYPE_HOST, host.logfile);
2495 if (host.motdfile)
2496 XFREE (MTYPE_HOST, host.motdfile);
2497 if (host.config)
2498 XFREE (MTYPE_HOST, host.config);
2499}