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