Project

General

Profile

Download (75.8 KB) Statistics
| Branch: | Tag: | Revision:
1 13da9a6f (no author)
/*
2
   $Id: command.c,v 1.47 2005/04/25 16:26:42 paul Exp $
3
 
4
   Command interpreter routine for virtual terminal [aka TeletYpe]
5
   Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
6
7
This file is part of GNU Zebra.
8
 
9
GNU Zebra is free software; you can redistribute it and/or modify
10
it under the terms of the GNU General Public License as published
11
by the Free Software Foundation; either version 2, or (at your
12
option) any later version.
13
14
GNU Zebra is distributed in the hope that it will be useful, but
15
WITHOUT ANY WARRANTY; without even the implied warranty of
16
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
General Public License for more details.
18
19
You should have received a copy of the GNU General Public License
20
along with GNU Zebra; see the file COPYING.  If not, write to the
21
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22
Boston, MA 02111-1307, USA.  */
23
24
#include "zebvty.h"
25
26
#include <stdio.h>
27
#include <stdlib.h>
28
#include <string.h>
29
#include <syslog.h>
30
#include <errno.h>
31
#define _XOPEN_SOURCE
32
#include <unistd.h>
33
#include <assert.h>
34
#include <ctype.h>
35
#include <time.h>
36
#include <sys/time.h>
37
38
//#include "memory.h"
39
//#include "log.h"
40
//#include <lib/version.h>
41
//#include "thread.h"
42
#include "vector.h"
43
#include "vty.h"
44
#include "command.h"
45
//#include "workqueue.h"
46
47
/* Command vector which includes some level of command lists. Normally
48
   each daemon maintains each own cmdvec. */
49
vector cmdvec;
50
51
/* Host information structure. */
52
struct host host;
53
54
/* Standard command node structures. */
55
struct cmd_node auth_node = {
56
	AUTH_NODE,
57
	"Password: ",
58
};
59
60
struct cmd_node view_node = {
61
	VIEW_NODE,
62
	"%s> ",
63
};
64
65
struct cmd_node auth_enable_node = {
66
	AUTH_ENABLE_NODE,
67
	"Password: ",
68
};
69
70
struct cmd_node enable_node = {
71
	ENABLE_NODE,
72
	"%s# ",
73
};
74
75
struct cmd_node config_node = {
76
	CONFIG_NODE,
77
	"%s(config)# ",
78
	1
79
};
80
81
/* Default motd string. */
82
const char *default_motd = "\r\n\
83
Hello, this is " QUAGGA_PROGNAME " (version " QUAGGA_VERSION ").\r\n\
84
" QUAGGA_COPYRIGHT "\r\n\
85
\r\n";
86
87
#if 0
88
static struct facility_map {
89
	int facility;
90
	const char *name;
91
	size_t match;
92
} syslog_facilities[] = {
93
	{
94
	LOG_KERN, "kern", 1}, {
95
	LOG_USER, "user", 2}, {
96
	LOG_MAIL, "mail", 1}, {
97
	LOG_DAEMON, "daemon", 1}, {
98
	LOG_AUTH, "auth", 1}, {
99
	LOG_SYSLOG, "syslog", 1}, {
100
	LOG_LPR, "lpr", 2}, {
101
	LOG_NEWS, "news", 1}, {
102
	LOG_UUCP, "uucp", 2}, {
103
	LOG_CRON, "cron", 1},
104
#ifdef LOG_FTP
105
	{
106
	LOG_FTP, "ftp", 1},
107
#endif
108
	{
109
	LOG_LOCAL0, "local0", 6}, {
110
	LOG_LOCAL1, "local1", 6}, {
111
	LOG_LOCAL2, "local2", 6}, {
112
	LOG_LOCAL3, "local3", 6}, {
113
	LOG_LOCAL4, "local4", 6}, {
114
	LOG_LOCAL5, "local5", 6}, {
115
	LOG_LOCAL6, "local6", 6}, {
116
	LOG_LOCAL7, "local7", 6}, {
117
0, NULL, 0},};
118
119
static const char *facility_name(int facility)
120
{
121
	struct facility_map *fm;
122
123
	for (fm = syslog_facilities; fm->name; fm++)
124
		if (fm->facility == facility)
125
			return fm->name;
126
	return "";
127
}
128
129
static int facility_match(const char *str)
130
{
131
	struct facility_map *fm;
132
133
	for (fm = syslog_facilities; fm->name; fm++)
134
		if (!strncmp(str, fm->name, fm->match))
135
			return fm->facility;
136
	return -1;
137
}
138
139
static int level_match(const char *s)
140
{
141
	int level;
142
143
	for (level = 0; zlog_priority[level] != NULL; level++)
144
		if (!strncmp(s, zlog_priority[level], 2))
145
			return level;
146
	return ZLOG_DISABLED;
147
}
148
#endif
149
150
/* This is called from main when a daemon is invoked with -v or --version. */
151
void print_version(const char *progname)
152
{
153
	printf("%s version %s\n", progname, QUAGGA_VERSION);
154
	printf("%s\n", QUAGGA_COPYRIGHT);
155
}
156

157
/* Utility function to concatenate argv argument into a single string
158
   with inserting ' ' character between each argument.  */
159
char *argv_concat(const char **argv, int argc, int shift)
160
{
161
	int i;
162
	size_t len;
163
	char *str;
164
	char *p;
165
166
	len = 0;
167
	for (i = shift; i < argc; i++)
168
		len += strlen(argv[i]) + 1;
169
	if (!len)
170
		return NULL;
171
	p = str = malloc(len);
172
	for (i = shift; i < argc; i++) {
173
		size_t arglen;
174
		memcpy(p, argv[i], (arglen = strlen(argv[i])));
175
		p += arglen;
176
		*p++ = ' ';
177
	}
178
	*(p - 1) = '\0';
179
	return str;
180
}
181
182
/* Install top node of command vector. */
183
void install_node(struct cmd_node *node, int (*func) (struct vty *))
184
{
185
	vector_set_index(cmdvec, node->node, node);
186
	node->func = func;
187
	node->cmd_vector = vector_init(VECTOR_MIN_SIZE);
188
}
189
190
/* Compare two command's string.  Used in sort_node (). */
191
static int cmp_node(const void *p, const void *q)
192
{
193
	struct cmd_element *a = *(struct cmd_element **)p;
194
	struct cmd_element *b = *(struct cmd_element **)q;
195
196
	return strcmp(a->string, b->string);
197
}
198
199
static int cmp_desc(const void *p, const void *q)
200
{
201
	struct desc *a = *(struct desc **)p;
202
	struct desc *b = *(struct desc **)q;
203
204
	return strcmp(a->cmd, b->cmd);
205
}
206
207
/* Sort each node's command element according to command string. */
208
void sort_node()
209
{
210
	unsigned int i, j;
211
	struct cmd_node *cnode;
212
	vector descvec;
213
	struct cmd_element *cmd_element;
214
215
	for (i = 0; i < vector_active(cmdvec); i++)
216
		if ((cnode = vector_slot(cmdvec, i)) != NULL) {
217
			vector cmd_vector = cnode->cmd_vector;
218
			qsort(cmd_vector->index, vector_active(cmd_vector),
219
			      sizeof(void *), cmp_node);
220
221
			for (j = 0; j < vector_active(cmd_vector); j++)
222
				if ((cmd_element =
223
				     vector_slot(cmd_vector, j)) != NULL
224
				    && vector_active(cmd_element->strvec)) {
225
					descvec =
226
					    vector_slot(cmd_element->strvec,
227
							vector_active
228
							(cmd_element->strvec) -
229
							1);
230
					qsort(descvec->index,
231
					      vector_active(descvec),
232
					      sizeof(void *), cmp_desc);
233
				}
234
		}
235
}
236
237
/* Breaking up string into each command piece. I assume given
238
   character is separated by a space character. Return value is a
239
   vector which includes char ** data element. */
240
vector cmd_make_strvec(const char *string)
241
{
242
	const char *cp, *start;
243
	char *token;
244
	int strlen;
245
	vector strvec;
246
247
	if (string == NULL)
248
		return NULL;
249
250
	cp = string;
251
252
	/* Skip white spaces. */
253
	while (isspace((int)*cp) && *cp != '\0')
254
		cp++;
255
256
	/* Return if there is only white spaces */
257
	if (*cp == '\0')
258
		return NULL;
259
260
	if (*cp == '!' || *cp == '#')
261
		return NULL;
262
263
	/* Prepare return vector. */
264
	strvec = vector_init(VECTOR_MIN_SIZE);
265
266
	/* Copy each command piece and set into vector. */
267
	while (1) {
268
		start = cp;
269
		while (!(isspace((int)*cp) || *cp == '\r' || *cp == '\n') &&
270
		       *cp != '\0')
271
			cp++;
272
		strlen = cp - start;
273
		token = malloc(strlen + 1);
274
		memcpy(token, start, strlen);
275
		*(token + strlen) = '\0';
276
		vector_set(strvec, token);
277
278
		while ((isspace((int)*cp) || *cp == '\n' || *cp == '\r') &&
279
		       *cp != '\0')
280
			cp++;
281
282
		if (*cp == '\0')
283
			return strvec;
284
	}
285
}
286
287
/* Free allocated string vector. */
288
void cmd_free_strvec(vector v)
289
{
290
	unsigned int i;
291
	char *cp;
292
293
	if (!v)
294
		return;
295
296
	for (i = 0; i < vector_active(v); i++)
297
		if ((cp = vector_slot(v, i)) != NULL)
298
			free(cp);
299
300
	vector_free(v);
301
}
302
303
/* Fetch next description.  Used in cmd_make_descvec(). */
304
static char *cmd_desc_str(const char **string)
305
{
306
	const char *cp, *start;
307
	char *token;
308
	int strlen;
309
310
	cp = *string;
311
312
	if (cp == NULL)
313
		return NULL;
314
315
	/* Skip white spaces. */
316
	while (isspace((int)*cp) && *cp != '\0')
317
		cp++;
318
319
	/* Return if there is only white spaces */
320
	if (*cp == '\0')
321
		return NULL;
322
323
	start = cp;
324
325
	while (!(*cp == '\r' || *cp == '\n') && *cp != '\0')
326
		cp++;
327
328
	strlen = cp - start;
329
	token = malloc(strlen + 1);
330
	memcpy(token, start, strlen);
331
	*(token + strlen) = '\0';
332
333
	*string = cp;
334
335
	return token;
336
}
337
338
/* New string vector. */
339
static vector cmd_make_descvec(const char *string, const char *descstr)
340
{
341
	int multiple = 0;
342
	const char *sp;
343
	char *token;
344
	int len;
345
	const char *cp;
346
	const char *dp;
347
	vector allvec;
348
	vector strvec = NULL;
349
	struct desc *desc;
350
351
	cp = string;
352
	dp = descstr;
353
354
	if (cp == NULL)
355
		return NULL;
356
357
	allvec = vector_init(VECTOR_MIN_SIZE);
358
359
	while (1) {
360
		while (isspace((int)*cp) && *cp != '\0')
361
			cp++;
362
363
		if (*cp == '(') {
364
			multiple = 1;
365
			cp++;
366
		}
367
		if (*cp == ')') {
368
			multiple = 0;
369
			cp++;
370
		}
371
		if (*cp == '|') {
372
			if (!multiple) {
373
				fprintf(stderr, "Command parse error!: %s\n",
374
					string);
375
				exit(1);
376
			}
377
			cp++;
378
		}
379
380
		while (isspace((int)*cp) && *cp != '\0')
381
			cp++;
382
383
		if (*cp == '(') {
384
			multiple = 1;
385
			cp++;
386
		}
387
388
		if (*cp == '\0')
389
			return allvec;
390
391
		sp = cp;
392
393
		while (!
394
		       (isspace((int)*cp) || *cp == '\r' || *cp == '\n'
395
			|| *cp == ')' || *cp == '|') && *cp != '\0')
396
			cp++;
397
398
		len = cp - sp;
399
400
		token = malloc(len + 1);
401
		memcpy(token, sp, len);
402
		*(token + len) = '\0';
403
404
		desc = calloc(1, sizeof(struct desc));
405
		desc->cmd = token;
406
		desc->str = cmd_desc_str(&dp);
407
408
		if (multiple) {
409
			if (multiple == 1) {
410
				strvec = vector_init(VECTOR_MIN_SIZE);
411
				vector_set(allvec, strvec);
412
			}
413
			multiple++;
414
		} else {
415
			strvec = vector_init(VECTOR_MIN_SIZE);
416
			vector_set(allvec, strvec);
417
		}
418
		vector_set(strvec, desc);
419
	}
420
}
421
422
/* Count mandantory string vector size.  This is to determine inputed
423
   command has enough command length. */
424
static int cmd_cmdsize(vector strvec)
425
{
426
	unsigned int i;
427
	int size = 0;
428
	vector descvec;
429
	struct desc *desc;
430
431
	for (i = 0; i < vector_active(strvec); i++)
432
		if ((descvec = vector_slot(strvec, i)) != NULL) {
433
			if ((vector_active(descvec)) == 1
434
			    && (desc = vector_slot(descvec, 0)) != NULL) {
435
				if (desc->cmd == NULL || CMD_OPTION(desc->cmd))
436
					return size;
437
				else
438
					size++;
439
			} else
440
				size++;
441
		}
442
	return size;
443
}
444
445
/* Return prompt character of specified node. */
446
const char *cmd_prompt(enum node_type node)
447
{
448
	struct cmd_node *cnode;
449
450
	cnode = vector_slot(cmdvec, node);
451
	return cnode->prompt;
452
}
453
454
/* Install a command into a node. */
455
void install_element(enum node_type ntype, struct cmd_element *cmd)
456
{
457
	struct cmd_node *cnode;
458
459
	cnode = vector_slot(cmdvec, ntype);
460
461
	if (cnode == NULL) {
462
		fprintf(stderr,
463
			"Command node %d doesn't exist, please check it\n",
464
			ntype);
465
		exit(1);
466
	}
467
468
	vector_set(cnode->cmd_vector, cmd);
469
470
	cmd->strvec = cmd_make_descvec(cmd->string, cmd->doc);
471
	cmd->cmdsize = cmd_cmdsize(cmd->strvec);
472
}
473
474
static unsigned char itoa64[] =
475
    "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
476
477
static void to64(char *s, long v, int n)
478
{
479
	while (--n >= 0) {
480
		*s++ = itoa64[v & 0x3f];
481
		v >>= 6;
482
	}
483
}
484
485
static char *zencrypt(const char *passwd)
486
{
487
	char salt[6];
488
	struct timeval tv;
489
	char *crypt(const char *, const char *);
490
491
	gettimeofday(&tv, 0);
492
493
	to64(&salt[0], random(), 3);
494
	to64(&salt[3], tv.tv_usec, 3);
495
	salt[5] = '\0';
496
497
	return crypt(passwd, salt);
498
}
499
500
/* This function write configuration of this host. */
501
static int config_write_host(struct vty *vty)
502
{
503
#if 0
504
	if (host.name)
505
		vty_out(vty, "hostname %s%s", host.name, VTY_NEWLINE);
506
507
	if (host.encrypt) {
508
		if (host.password_encrypt)
509
			vty_out(vty, "password 8 %s%s", host.password_encrypt,
510
				VTY_NEWLINE);
511
		if (host.enable_encrypt)
512
			vty_out(vty, "enable password 8 %s%s",
513
				host.enable_encrypt, VTY_NEWLINE);
514
	} else {
515
		if (host.password)
516
			vty_out(vty, "password %s%s", host.password,
517
				VTY_NEWLINE);
518
		if (host.enable)
519
			vty_out(vty, "enable password %s%s", host.enable,
520
				VTY_NEWLINE);
521
	}
522
523
	if (zlog_default->default_lvl != LOG_DEBUG) {
524
		vty_out(vty, "! N.B. The 'log trap' command is deprecated.%s",
525
			VTY_NEWLINE);
526
		vty_out(vty, "log trap %s%s",
527
			zlog_priority[zlog_default->default_lvl], VTY_NEWLINE);
528
	}
529
530
	if (host.logfile
531
	    && (zlog_default->maxlvl[ZLOG_DEST_FILE] != ZLOG_DISABLED)) {
532
		vty_out(vty, "log file %s", host.logfile);
533
		if (zlog_default->maxlvl[ZLOG_DEST_FILE] !=
534
		    zlog_default->default_lvl)
535
			vty_out(vty, " %s",
536
				zlog_priority[zlog_default->
537
					      maxlvl[ZLOG_DEST_FILE]]);
538
		vty_out(vty, "%s", VTY_NEWLINE);
539
	}
540
541
	if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != ZLOG_DISABLED) {
542
		vty_out(vty, "log stdout");
543
		if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] !=
544
		    zlog_default->default_lvl)
545
			vty_out(vty, " %s",
546
				zlog_priority[zlog_default->
547
					      maxlvl[ZLOG_DEST_STDOUT]]);
548
		vty_out(vty, "%s", VTY_NEWLINE);
549
	}
550
551
	if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
552
		vty_out(vty, "no log monitor%s", VTY_NEWLINE);
553
	else if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] !=
554
		 zlog_default->default_lvl)
555
		vty_out(vty, "log monitor %s%s",
556
			zlog_priority[zlog_default->maxlvl[ZLOG_DEST_MONITOR]],
557
			VTY_NEWLINE);
558
559
	if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED) {
560
		vty_out(vty, "log syslog");
561
		if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] !=
562
		    zlog_default->default_lvl)
563
			vty_out(vty, " %s",
564
				zlog_priority[zlog_default->
565
					      maxlvl[ZLOG_DEST_SYSLOG]]);
566
		vty_out(vty, "%s", VTY_NEWLINE);
567
	}
568
569
	if (zlog_default->facility != LOG_DAEMON)
570
		vty_out(vty, "log facility %s%s",
571
			facility_name(zlog_default->facility), VTY_NEWLINE);
572
573
	if (zlog_default->record_priority == 1)
574
		vty_out(vty, "log record-priority%s", VTY_NEWLINE);
575
576
	if (host.advanced)
577
		vty_out(vty, "service advanced-vty%s", VTY_NEWLINE);
578
579
	if (host.encrypt)
580
		vty_out(vty, "service password-encryption%s", VTY_NEWLINE);
581
582
	if (host.lines >= 0)
583
		vty_out(vty, "service terminal-length %d%s", host.lines,
584
			VTY_NEWLINE);
585
586
	if (host.motdfile)
587
		vty_out(vty, "banner motd file %s%s", host.motdfile,
588
			VTY_NEWLINE);
589
	else if (!host.motd)
590
		vty_out(vty, "no banner motd%s", VTY_NEWLINE);
591
592
#endif
593
	return 1;
594
}
595
596
/* Utility function for getting command vector. */
597
static vector cmd_node_vector(vector v, enum node_type ntype)
598
{
599
	struct cmd_node *cnode = vector_slot(v, ntype);
600
	return cnode->cmd_vector;
601
}
602
603
#if 0
604
/* Filter command vector by symbol.  This function is not actually used;
605
 * should it be deleted? */
606
static int cmd_filter_by_symbol(char *command, char *symbol)
607
{
608
	int i, lim;
609
610
	if (strcmp(symbol, "IPV4_ADDRESS") == 0) {
611
		i = 0;
612
		lim = strlen(command);
613
		while (i < lim) {
614
			if (!
615
			    (isdigit((int)command[i]) || command[i] == '.'
616
			     || command[i] == '/'))
617
				return 1;
618
			i++;
619
		}
620
		return 0;
621
	}
622
	if (strcmp(symbol, "STRING") == 0) {
623
		i = 0;
624
		lim = strlen(command);
625
		while (i < lim) {
626
			if (!
627
			    (isalpha((int)command[i]) || command[i] == '_'
628
			     || command[i] == '-'))
629
				return 1;
630
			i++;
631
		}
632
		return 0;
633
	}
634
	if (strcmp(symbol, "IFNAME") == 0) {
635
		i = 0;
636
		lim = strlen(command);
637
		while (i < lim) {
638
			if (!isalnum((int)command[i]))
639
				return 1;
640
			i++;
641
		}
642
		return 0;
643
	}
644
	return 0;
645
}
646
#endif
647
648
/* Completion match types. */
649
enum match_type {
650
	no_match,
651
	extend_match,
652
	ipv4_prefix_match,
653
	ipv4_match,
654
	ipv6_prefix_match,
655
	ipv6_match,
656
	range_match,
657
	vararg_match,
658
	partly_match,
659
	exact_match
660
};
661
662
static enum match_type cmd_ipv4_match(const char *str)
663
{
664
	const char *sp;
665
	int dots = 0, nums = 0;
666
	char buf[4];
667
668
	if (str == NULL)
669
		return partly_match;
670
671
	for (;;) {
672
		memset(buf, 0, sizeof(buf));
673
		sp = str;
674
		while (*str != '\0') {
675
			if (*str == '.') {
676
				if (dots >= 3)
677
					return no_match;
678
679
				if (*(str + 1) == '.')
680
					return no_match;
681
682
				if (*(str + 1) == '\0')
683
					return partly_match;
684
685
				dots++;
686
				break;
687
			}
688
			if (!isdigit((int)*str))
689
				return no_match;
690
691
			str++;
692
		}
693
694
		if (str - sp > 3)
695
			return no_match;
696
697
		strncpy(buf, sp, str - sp);
698
		if (atoi(buf) > 255)
699
			return no_match;
700
701
		nums++;
702
703
		if (*str == '\0')
704
			break;
705
706
		str++;
707
	}
708
709
	if (nums < 4)
710
		return partly_match;
711
712
	return exact_match;
713
}
714
715
static enum match_type cmd_ipv4_prefix_match(const char *str)
716
{
717
	const char *sp;
718
	int dots = 0;
719
	char buf[4];
720
721
	if (str == NULL)
722
		return partly_match;
723
724
	for (;;) {
725
		memset(buf, 0, sizeof(buf));
726
		sp = str;
727
		while (*str != '\0' && *str != '/') {
728
			if (*str == '.') {
729
				if (dots == 3)
730
					return no_match;
731
732
				if (*(str + 1) == '.' || *(str + 1) == '/')
733
					return no_match;
734
735
				if (*(str + 1) == '\0')
736
					return partly_match;
737
738
				dots++;
739
				break;
740
			}
741
742
			if (!isdigit((int)*str))
743
				return no_match;
744
745
			str++;
746
		}
747
748
		if (str - sp > 3)
749
			return no_match;
750
751
		strncpy(buf, sp, str - sp);
752
		if (atoi(buf) > 255)
753
			return no_match;
754
755
		if (dots == 3) {
756
			if (*str == '/') {
757
				if (*(str + 1) == '\0')
758
					return partly_match;
759
760
				str++;
761
				break;
762
			} else if (*str == '\0')
763
				return partly_match;
764
		}
765
766
		if (*str == '\0')
767
			return partly_match;
768
769
		str++;
770
	}
771
772
	sp = str;
773
	while (*str != '\0') {
774
		if (!isdigit((int)*str))
775
			return no_match;
776
777
		str++;
778
	}
779
780
	if (atoi(sp) > 32)
781
		return no_match;
782
783
	return exact_match;
784
}
785
786
#define IPV6_ADDR_STR		"0123456789abcdefABCDEF:.%"
787
#define IPV6_PREFIX_STR		"0123456789abcdefABCDEF:.%/"
788
#define STATE_START		1
789
#define STATE_COLON		2
790
#define STATE_DOUBLE		3
791
#define STATE_ADDR		4
792
#define STATE_DOT               5
793
#define STATE_SLASH		6
794
#define STATE_MASK		7
795
796
#ifdef HAVE_IPV6
797
798
static enum match_type cmd_ipv6_match(const char *str)
799
{
800
	int state = STATE_START;
801
	int colons = 0, nums = 0, double_colon = 0;
802
	const char *sp = NULL;
803
	struct sockaddr_in6 sin6_dummy;
804
	int ret;
805
806
	if (str == NULL)
807
		return partly_match;
808
809
	if (strspn(str, IPV6_ADDR_STR) != strlen(str))
810
		return no_match;
811
812
	/* use inet_pton that has a better support,
813
	 * for example inet_pton can support the automatic addresses:
814
	 *  ::1.2.3.4
815
	 */
816
	ret = inet_pton(AF_INET6, str, &sin6_dummy.sin6_addr);
817
818
	if (ret == 1)
819
		return exact_match;
820
821
	while (*str != '\0') {
822
		switch (state) {
823
		case STATE_START:
824
			if (*str == ':') {
825
				if (*(str + 1) != ':' && *(str + 1) != '\0')
826
					return no_match;
827
				colons--;
828
				state = STATE_COLON;
829
			} else {
830
				sp = str;
831
				state = STATE_ADDR;
832
			}
833
834
			continue;
835
		case STATE_COLON:
836
			colons++;
837
			if (*(str + 1) == ':')
838
				state = STATE_DOUBLE;
839
			else {
840
				sp = str + 1;
841
				state = STATE_ADDR;
842
			}
843
			break;
844
		case STATE_DOUBLE:
845
			if (double_colon)
846
				return no_match;
847
848
			if (*(str + 1) == ':')
849
				return no_match;
850
			else {
851
				if (*(str + 1) != '\0')
852
					colons++;
853
				sp = str + 1;
854
				state = STATE_ADDR;
855
			}
856
857
			double_colon++;
858
			nums++;
859
			break;
860
		case STATE_ADDR:
861
			if (*(str + 1) == ':' || *(str + 1) == '\0') {
862
				if (str - sp > 3)
863
					return no_match;
864
865
				nums++;
866
				state = STATE_COLON;
867
			}
868
			if (*(str + 1) == '.')
869
				state = STATE_DOT;
870
			break;
871
		case STATE_DOT:
872
			state = STATE_ADDR;
873
			break;
874
		default:
875
			break;
876
		}
877
878
		if (nums > 8)
879
			return no_match;
880
881
		if (colons > 7)
882
			return no_match;
883
884
		str++;
885
	}
886
887
#if 0
888
	if (nums < 11)
889
		return partly_match;
890
#endif				/* 0 */
891
892
	return exact_match;
893
}
894
895
static enum match_type cmd_ipv6_prefix_match(const char *str)
896
{
897
	int state = STATE_START;
898
	int colons = 0, nums = 0, double_colon = 0;
899
	int mask;
900
	const char *sp = NULL;
901
	char *endptr = NULL;
902
903
	if (str == NULL)
904
		return partly_match;
905
906
	if (strspn(str, IPV6_PREFIX_STR) != strlen(str))
907
		return no_match;
908
909
	while (*str != '\0' && state != STATE_MASK) {
910
		switch (state) {
911
		case STATE_START:
912
			if (*str == ':') {
913
				if (*(str + 1) != ':' && *(str + 1) != '\0')
914
					return no_match;
915
				colons--;
916
				state = STATE_COLON;
917
			} else {
918
				sp = str;
919
				state = STATE_ADDR;
920
			}
921
922
			continue;
923
		case STATE_COLON:
924
			colons++;
925
			if (*(str + 1) == '/')
926
				return no_match;
927
			else if (*(str + 1) == ':')
928
				state = STATE_DOUBLE;
929
			else {
930
				sp = str + 1;
931
				state = STATE_ADDR;
932
			}
933
			break;
934
		case STATE_DOUBLE:
935
			if (double_colon)
936
				return no_match;
937
938
			if (*(str + 1) == ':')
939
				return no_match;
940
			else {
941
				if (*(str + 1) != '\0' && *(str + 1) != '/')
942
					colons++;
943
				sp = str + 1;
944
945
				if (*(str + 1) == '/')
946
					state = STATE_SLASH;
947
				else
948
					state = STATE_ADDR;
949
			}
950
951
			double_colon++;
952
			nums += 1;
953
			break;
954
		case STATE_ADDR:
955
			if (*(str + 1) == ':' || *(str + 1) == '.'
956
			    || *(str + 1) == '\0' || *(str + 1) == '/') {
957
				if (str - sp > 3)
958
					return no_match;
959
960
				for (; sp <= str; sp++)
961
					if (*sp == '/')
962
						return no_match;
963
964
				nums++;
965
966
				if (*(str + 1) == ':')
967
					state = STATE_COLON;
968
				else if (*(str + 1) == '.')
969
					state = STATE_DOT;
970
				else if (*(str + 1) == '/')
971
					state = STATE_SLASH;
972
			}
973
			break;
974
		case STATE_DOT:
975
			state = STATE_ADDR;
976
			break;
977
		case STATE_SLASH:
978
			if (*(str + 1) == '\0')
979
				return partly_match;
980
981
			state = STATE_MASK;
982
			break;
983
		default:
984
			break;
985
		}
986
987
		if (nums > 11)
988
			return no_match;
989
990
		if (colons > 7)
991
			return no_match;
992
993
		str++;
994
	}
995
996
	if (state < STATE_MASK)
997
		return partly_match;
998
999
	mask = strtol(str, &endptr, 10);
1000
	if (*endptr != '\0')
1001
		return no_match;
1002
1003
	if (mask < 0 || mask > 128)
1004
		return no_match;
1005
1006
/* I don't know why mask < 13 makes command match partly.
1007
   Forgive me to make this comments. I Want to set static default route
1008
   because of lack of function to originate default in ospf6d; sorry
1009
       yasu
1010
  if (mask < 13)
1011
    return partly_match;
1012
*/
1013
1014
	return exact_match;
1015
}
1016
1017
#endif				/* HAVE_IPV6  */
1018
1019
#define DECIMAL_STRLEN_MAX 10
1020
1021
static int cmd_range_match(const char *range, const char *str)
1022
{
1023
	char *p;
1024
	char buf[DECIMAL_STRLEN_MAX + 1];
1025
	char *endptr = NULL;
1026
	unsigned long min, max, val;
1027
1028
	if (str == NULL)
1029
		return 1;
1030
1031
	val = strtoul(str, &endptr, 10);
1032
	if (*endptr != '\0')
1033
		return 0;
1034
1035
	range++;
1036
	p = strchr(range, '-');
1037
	if (p == NULL)
1038
		return 0;
1039
	if (p - range > DECIMAL_STRLEN_MAX)
1040
		return 0;
1041
	strncpy(buf, range, p - range);
1042
	buf[p - range] = '\0';
1043
	min = strtoul(buf, &endptr, 10);
1044
	if (*endptr != '\0')
1045
		return 0;
1046
1047
	range = p + 1;
1048
	p = strchr(range, '>');
1049
	if (p == NULL)
1050
		return 0;
1051
	if (p - range > DECIMAL_STRLEN_MAX)
1052
		return 0;
1053
	strncpy(buf, range, p - range);
1054
	buf[p - range] = '\0';
1055
	max = strtoul(buf, &endptr, 10);
1056
	if (*endptr != '\0')
1057
		return 0;
1058
1059
	if (val < min || val > max)
1060
		return 0;
1061
1062
	return 1;
1063
}
1064
1065
/* Make completion match and return match type flag. */
1066
static enum match_type
1067
cmd_filter_by_completion(char *command, vector v, unsigned int index)
1068
{
1069
	unsigned int i;
1070
	const char *str;
1071
	struct cmd_element *cmd_element;
1072
	enum match_type match_type;
1073
	vector descvec;
1074
	struct desc *desc;
1075
1076
	match_type = no_match;
1077
1078
	/* If command and cmd_element string does not match set NULL to vector */
1079
	for (i = 0; i < vector_active(v); i++)
1080
		if ((cmd_element = vector_slot(v, i)) != NULL) {
1081
			if (index >= vector_active(cmd_element->strvec))
1082
				vector_slot(v, i) = NULL;
1083
			else {
1084
				unsigned int j;
1085
				int matched = 0;
1086
1087
				descvec =
1088
				    vector_slot(cmd_element->strvec, index);
1089
1090
				for (j = 0; j < vector_active(descvec); j++)
1091
					if ((desc = vector_slot(descvec, j))) {
1092
						str = desc->cmd;
1093
1094
						if (CMD_VARARG(str)) {
1095
							if (match_type <
1096
							    vararg_match)
1097
								match_type =
1098
								    vararg_match;
1099
							matched++;
1100
						} else if (CMD_RANGE(str)) {
1101
							if (cmd_range_match
1102
							    (str, command)) {
1103
								if (match_type <
1104
								    range_match)
1105
									match_type
1106
									    =
1107
									    range_match;
1108
1109
								matched++;
1110
							}
1111
						}
1112
#ifdef HAVE_IPV6
1113
						else if (CMD_IPV6(str)) {
1114
							if (cmd_ipv6_match
1115
							    (command)) {
1116
								if (match_type <
1117
								    ipv6_match)
1118
									match_type
1119
									    =
1120
									    ipv6_match;
1121
1122
								matched++;
1123
							}
1124
						} else if (CMD_IPV6_PREFIX(str)) {
1125
							if (cmd_ipv6_prefix_match(command)) {
1126
								if (match_type <
1127
								    ipv6_prefix_match)
1128
									match_type
1129
									    =
1130
									    ipv6_prefix_match;
1131
1132
								matched++;
1133
							}
1134
						}
1135
#endif				/* HAVE_IPV6  */
1136
						else if (CMD_IPV4(str)) {
1137
							if (cmd_ipv4_match
1138
							    (command)) {
1139
								if (match_type <
1140
								    ipv4_match)
1141
									match_type
1142
									    =
1143
									    ipv4_match;
1144
1145
								matched++;
1146
							}
1147
						} else if (CMD_IPV4_PREFIX(str)) {
1148
							if (cmd_ipv4_prefix_match(command)) {
1149
								if (match_type <
1150
								    ipv4_prefix_match)
1151
									match_type
1152
									    =
1153
									    ipv4_prefix_match;
1154
								matched++;
1155
							}
1156
						} else
1157
							/* Check is this point's argument optional ? */
1158
						if (CMD_OPTION(str)
1159
							    ||
1160
							    CMD_VARIABLE(str)) {
1161
							if (match_type <
1162
							    extend_match)
1163
								match_type =
1164
								    extend_match;
1165
							matched++;
1166
						} else
1167
						    if (strncmp
1168
							(command, str,
1169
							 strlen(command)) ==
1170
							0) {
1171
							if (strcmp(command, str)
1172
							    == 0)
1173
								match_type =
1174
								    exact_match;
1175
							else {
1176
								if (match_type <
1177
								    partly_match)
1178
									match_type
1179
									    =
1180
									    partly_match;
1181
							}
1182
							matched++;
1183
						}
1184
					}
1185
				if (!matched)
1186
					vector_slot(v, i) = NULL;
1187
			}
1188
		}
1189
	return match_type;
1190
}
1191
1192
/* Filter vector by command character with index. */
1193
static enum match_type
1194
cmd_filter_by_string(char *command, vector v, unsigned int index)
1195
{
1196
	unsigned int i;
1197
	const char *str;
1198
	struct cmd_element *cmd_element;
1199
	enum match_type match_type;
1200
	vector descvec;
1201
	struct desc *desc;
1202
1203
	match_type = no_match;
1204
1205
	/* If command and cmd_element string does not match set NULL to vector */
1206
	for (i = 0; i < vector_active(v); i++)
1207
		if ((cmd_element = vector_slot(v, i)) != NULL) {
1208
			/* If given index is bigger than max string vector of command,
1209
			   set NULL */
1210
			if (index >= vector_active(cmd_element->strvec))
1211
				vector_slot(v, i) = NULL;
1212
			else {
1213
				unsigned int j;
1214
				int matched = 0;
1215
1216
				descvec =
1217
				    vector_slot(cmd_element->strvec, index);
1218
1219
				for (j = 0; j < vector_active(descvec); j++)
1220
					if ((desc = vector_slot(descvec, j))) {
1221
						str = desc->cmd;
1222
1223
						if (CMD_VARARG(str)) {
1224
							if (match_type <
1225
							    vararg_match)
1226
								match_type =
1227
								    vararg_match;
1228
							matched++;
1229
						} else if (CMD_RANGE(str)) {
1230
							if (cmd_range_match
1231
							    (str, command)) {
1232
								if (match_type <
1233
								    range_match)
1234
									match_type
1235
									    =
1236
									    range_match;
1237
								matched++;
1238
							}
1239
						}
1240
#ifdef HAVE_IPV6
1241
						else if (CMD_IPV6(str)) {
1242
							if (cmd_ipv6_match
1243
							    (command) ==
1244
							    exact_match) {
1245
								if (match_type <
1246
								    ipv6_match)
1247
									match_type
1248
									    =
1249
									    ipv6_match;
1250
								matched++;
1251
							}
1252
						} else if (CMD_IPV6_PREFIX(str)) {
1253
							if (cmd_ipv6_prefix_match(command) == exact_match) {
1254
								if (match_type <
1255
								    ipv6_prefix_match)
1256
									match_type
1257
									    =
1258
									    ipv6_prefix_match;
1259
								matched++;
1260
							}
1261
						}
1262
#endif				/* HAVE_IPV6  */
1263
						else if (CMD_IPV4(str)) {
1264
							if (cmd_ipv4_match
1265
							    (command) ==
1266
							    exact_match) {
1267
								if (match_type <
1268
								    ipv4_match)
1269
									match_type
1270
									    =
1271
									    ipv4_match;
1272
								matched++;
1273
							}
1274
						} else if (CMD_IPV4_PREFIX(str)) {
1275
							if (cmd_ipv4_prefix_match(command) == exact_match) {
1276
								if (match_type <
1277
								    ipv4_prefix_match)
1278
									match_type
1279
									    =
1280
									    ipv4_prefix_match;
1281
								matched++;
1282
							}
1283
						} else if (CMD_OPTION(str)
1284
							   || CMD_VARIABLE(str))
1285
						{
1286
							if (match_type <
1287
							    extend_match)
1288
								match_type =
1289
								    extend_match;
1290
							matched++;
1291
						} else {
1292
							if (strcmp(command, str)
1293
							    == 0) {
1294
								match_type =
1295
								    exact_match;
1296
								matched++;
1297
							}
1298
						}
1299
					}
1300
				if (!matched)
1301
					vector_slot(v, i) = NULL;
1302
			}
1303
		}
1304
	return match_type;
1305
}
1306
1307
/* Check ambiguous match */
1308
static int
1309
is_cmd_ambiguous(char *command, vector v, int index, enum match_type type)
1310
{
1311
	unsigned int i;
1312
	unsigned int j;
1313
	const char *str = NULL;
1314
	struct cmd_element *cmd_element;
1315
	const char *matched = NULL;
1316
	vector descvec;
1317
	struct desc *desc;
1318
1319
	for (i = 0; i < vector_active(v); i++)
1320
		if ((cmd_element = vector_slot(v, i)) != NULL) {
1321
			int match = 0;
1322
1323
			descvec = vector_slot(cmd_element->strvec, index);
1324
1325
			for (j = 0; j < vector_active(descvec); j++)
1326
				if ((desc = vector_slot(descvec, j))) {
1327
					enum match_type ret;
1328
1329
					str = desc->cmd;
1330
1331
					switch (type) {
1332
					case exact_match:
1333
						if (!
1334
						    (CMD_OPTION(str)
1335
						     || CMD_VARIABLE(str))
1336
&& strcmp(command, str) == 0)
1337
							match++;
1338
						break;
1339
					case partly_match:
1340
						if (!
1341
						    (CMD_OPTION(str)
1342
						     || CMD_VARIABLE(str))
1343
&& strncmp(command, str, strlen(command)) == 0) {
1344
							if (matched
1345
							    && strcmp(matched,
1346
								      str) != 0)
1347
								return 1;	/* There is ambiguous match. */
1348
							else
1349
								matched = str;
1350
							match++;
1351
						}
1352
						break;
1353
					case range_match:
1354
						if (cmd_range_match
1355
						    (str, command)) {
1356
							if (matched
1357
							    && strcmp(matched,
1358
								      str) != 0)
1359
								return 1;
1360
							else
1361
								matched = str;
1362
							match++;
1363
						}
1364
						break;
1365
#ifdef HAVE_IPV6
1366
					case ipv6_match:
1367
						if (CMD_IPV6(str))
1368
							match++;
1369
						break;
1370
					case ipv6_prefix_match:
1371
						if ((ret =
1372
						     cmd_ipv6_prefix_match
1373
						     (command)) != no_match) {
1374
							if (ret == partly_match)
1375
								return 2;	/* There is incomplete match. */
1376
1377
							match++;
1378
						}
1379
						break;
1380
#endif				/* HAVE_IPV6 */
1381
					case ipv4_match:
1382
						if (CMD_IPV4(str))
1383
							match++;
1384
						break;
1385
					case ipv4_prefix_match:
1386
						if ((ret =
1387
						     cmd_ipv4_prefix_match
1388
						     (command)) != no_match) {
1389
							if (ret == partly_match)
1390
								return 2;	/* There is incomplete match. */
1391
1392
							match++;
1393
						}
1394
						break;
1395
					case extend_match:
1396
						if (CMD_OPTION(str)
1397
						    || CMD_VARIABLE(str))
1398
							match++;
1399
						break;
1400
					case no_match:
1401
					default:
1402
						break;
1403
					}
1404
				}
1405
			if (!match)
1406
				vector_slot(v, i) = NULL;
1407
		}
1408
	return 0;
1409
}
1410
1411
/* If src matches dst return dst string, otherwise return NULL */
1412
static const char *cmd_entry_function(const char *src, const char *dst)
1413
{
1414
	/* Skip variable arguments. */
1415
	if (CMD_OPTION(dst) || CMD_VARIABLE(dst) || CMD_VARARG(dst) ||
1416
	    CMD_IPV4(dst) || CMD_IPV4_PREFIX(dst) || CMD_RANGE(dst))
1417
		return NULL;
1418
1419
	/* In case of 'command \t', given src is NULL string. */
1420
	if (src == NULL)
1421
		return dst;
1422
1423
	/* Matched with input string. */
1424
	if (strncmp(src, dst, strlen(src)) == 0)
1425
		return dst;
1426
1427
	return NULL;
1428
}
1429
1430
/* If src matches dst return dst string, otherwise return NULL */
1431
/* This version will return the dst string always if it is
1432
   CMD_VARIABLE for '?' key processing */
1433
static const char *cmd_entry_function_desc(const char *src, const char *dst)
1434
{
1435
	if (CMD_VARARG(dst))
1436
		return dst;
1437
1438
	if (CMD_RANGE(dst)) {
1439
		if (cmd_range_match(dst, src))
1440
			return dst;
1441
		else
1442
			return NULL;
1443
	}
1444
#ifdef HAVE_IPV6
1445
	if (CMD_IPV6(dst)) {
1446
		if (cmd_ipv6_match(src))
1447
			return dst;
1448
		else
1449
			return NULL;
1450
	}
1451
1452
	if (CMD_IPV6_PREFIX(dst)) {
1453
		if (cmd_ipv6_prefix_match(src))
1454
			return dst;
1455
		else
1456
			return NULL;
1457
	}
1458
#endif				/* HAVE_IPV6 */
1459
1460
	if (CMD_IPV4(dst)) {
1461
		if (cmd_ipv4_match(src))
1462
			return dst;
1463
		else
1464
			return NULL;
1465
	}
1466
1467
	if (CMD_IPV4_PREFIX(dst)) {
1468
		if (cmd_ipv4_prefix_match(src))
1469
			return dst;
1470
		else
1471
			return NULL;
1472
	}
1473
1474
	/* Optional or variable commands always match on '?' */
1475
	if (CMD_OPTION(dst) || CMD_VARIABLE(dst))
1476
		return dst;
1477
1478
	/* In case of 'command \t', given src is NULL string. */
1479
	if (src == NULL)
1480
		return dst;
1481
1482
	if (strncmp(src, dst, strlen(src)) == 0)
1483
		return dst;
1484
	else
1485
		return NULL;
1486
}
1487
1488
/* Check same string element existence.  If it isn't there return
1489
    1. */
1490
static int cmd_unique_string(vector v, const char *str)
1491
{
1492
	unsigned int i;
1493
	char *match;
1494
1495
	for (i = 0; i < vector_active(v); i++)
1496
		if ((match = vector_slot(v, i)) != NULL)
1497
			if (strcmp(match, str) == 0)
1498
				return 0;
1499
	return 1;
1500
}
1501
1502
/* Compare string to description vector.  If there is same string
1503
   return 1 else return 0. */
1504
static int desc_unique_string(vector v, const char *str)
1505
{
1506
	unsigned int i;
1507
	struct desc *desc;
1508
1509
	for (i = 0; i < vector_active(v); i++)
1510
		if ((desc = vector_slot(v, i)) != NULL)
1511
			if (strcmp(desc->cmd, str) == 0)
1512
				return 1;
1513
	return 0;
1514
}
1515
1516
static int cmd_try_do_shortcut(enum node_type node, char *first_word)
1517
{
1518
	if (first_word != NULL &&
1519
	    node != AUTH_NODE &&
1520
	    node != VIEW_NODE &&
1521
	    node != AUTH_ENABLE_NODE &&
1522
	    node != ENABLE_NODE && 0 == strcmp("do", first_word))
1523
		return 1;
1524
	return 0;
1525
}
1526
1527
/* '?' describe command support. */
1528
static vector
1529
cmd_describe_command_real(vector vline, struct vty *vty, int *status)
1530
{
1531
	unsigned int i;
1532
	vector cmd_vector;
1533
#define INIT_MATCHVEC_SIZE 10
1534
	vector matchvec;
1535
	struct cmd_element *cmd_element;
1536
	unsigned int index;
1537
	int ret;
1538
	enum match_type match;
1539
	char *command;
1540
	static struct desc desc_cr = { "<cr>", "" };
1541
1542
	/* Set index. */
1543
	if (vector_active(vline) == 0) {
1544
		*status = CMD_ERR_NO_MATCH;
1545
		return NULL;
1546
	} else
1547
		index = vector_active(vline) - 1;
1548
1549
	/* Make copy vector of current node's command vector. */
1550
	cmd_vector = vector_copy(cmd_node_vector(cmdvec, vty->node));
1551
1552
	/* Prepare match vector */
1553
	matchvec = vector_init(INIT_MATCHVEC_SIZE);
1554
1555
	/* Filter commands. */
1556
	/* Only words precedes current word will be checked in this loop. */
1557
	for (i = 0; i < index; i++)
1558
		if ((command = vector_slot(vline, i))) {
1559
			match =
1560
			    cmd_filter_by_completion(command, cmd_vector, i);
1561
1562
			if (match == vararg_match) {
1563
				struct cmd_element *cmd_element;
1564
				vector descvec;
1565
				unsigned int j, k;
1566
1567
				for (j = 0; j < vector_active(cmd_vector); j++)
1568
					if ((cmd_element =
1569
					     vector_slot(cmd_vector, j)) != NULL
1570
					    &&
1571
					    (vector_active
1572
					     (cmd_element->strvec))) {
1573
						descvec =
1574
						    vector_slot(cmd_element->
1575
								strvec,
1576
								vector_active
1577
								(cmd_element->
1578
								 strvec) - 1);
1579
						for (k = 0;
1580
						     k < vector_active(descvec);
1581
						     k++) {
1582
							struct desc *desc =
1583
							    vector_slot(descvec,
1584
									k);
1585
							vector_set(matchvec,
1586
								   desc);
1587
						}
1588
					}
1589
1590
				vector_set(matchvec, &desc_cr);
1591
				vector_free(cmd_vector);
1592
1593
				return matchvec;
1594
			}
1595
1596
			if ((ret =
1597
			     is_cmd_ambiguous(command, cmd_vector, i,
1598
					      match)) == 1) {
1599
				vector_free(cmd_vector);
1600
				*status = CMD_ERR_AMBIGUOUS;
1601
				return NULL;
1602
			} else if (ret == 2) {
1603
				vector_free(cmd_vector);
1604
				*status = CMD_ERR_NO_MATCH;
1605
				return NULL;
1606
			}
1607
		}
1608
1609
	/* Prepare match vector */
1610
	/*  matchvec = vector_init (INIT_MATCHVEC_SIZE); */
1611
1612
	/* Make sure that cmd_vector is filtered based on current word */
1613
	command = vector_slot(vline, index);
1614
	if (command)
1615
		match = cmd_filter_by_completion(command, cmd_vector, index);
1616
1617
	/* Make description vector. */
1618
	for (i = 0; i < vector_active(cmd_vector); i++)
1619
		if ((cmd_element = vector_slot(cmd_vector, i)) != NULL) {
1620
			const char *string = NULL;
1621
			vector strvec = cmd_element->strvec;
1622
1623
			/* if command is NULL, index may be equal to vector_active */
1624
			if (command && index >= vector_active(strvec))
1625
				vector_slot(cmd_vector, i) = NULL;
1626
			else {
1627
				/* Check if command is completed. */
1628
				if (command == NULL
1629
				    && index == vector_active(strvec)) {
1630
					string = "<cr>";
1631
					if (!desc_unique_string
1632
					    (matchvec, string))
1633
						vector_set(matchvec, &desc_cr);
1634
				} else {
1635
					unsigned int j;
1636
					vector descvec =
1637
					    vector_slot(strvec, index);
1638
					struct desc *desc;
1639
1640
					for (j = 0; j < vector_active(descvec);
1641
					     j++)
1642
						if ((desc =
1643
						     vector_slot(descvec, j))) {
1644
							string =
1645
							    cmd_entry_function_desc
1646
							    (command,
1647
							     desc->cmd);
1648
							if (string) {
1649
								/* Uniqueness check */
1650
								if (!desc_unique_string(matchvec, string))
1651
									vector_set
1652
									    (matchvec,
1653
									     desc);
1654
							}
1655
						}
1656
				}
1657
			}
1658
		}
1659
	vector_free(cmd_vector);
1660
1661
	if (vector_slot(matchvec, 0) == NULL) {
1662
		vector_free(matchvec);
1663
		*status = CMD_ERR_NO_MATCH;
1664
	} else
1665
		*status = CMD_SUCCESS;
1666
1667
	return matchvec;
1668
}
1669
1670
vector cmd_describe_command(vector vline, struct vty * vty, int *status)
1671
{
1672
	vector ret;
1673
1674
	if (cmd_try_do_shortcut(vty->node, vector_slot(vline, 0))) {
1675
		enum node_type onode;
1676
		vector shifted_vline;
1677
		unsigned int index;
1678
1679
		onode = vty->node;
1680
		vty->node = ENABLE_NODE;
1681
		/* We can try it on enable node, cos' the vty is authenticated */
1682
1683
		shifted_vline = vector_init(vector_count(vline));
1684
		/* use memcpy? */
1685
		for (index = 1; index < vector_active(vline); index++) {
1686
			vector_set_index(shifted_vline, index - 1,
1687
					 vector_lookup(vline, index));
1688
		}
1689
1690
		ret = cmd_describe_command_real(shifted_vline, vty, status);
1691
1692
		vector_free(shifted_vline);
1693
		vty->node = onode;
1694
		return ret;
1695
	}
1696
1697
	return cmd_describe_command_real(vline, vty, status);
1698
}
1699
1700
/* Check LCD of matched command. */
1701
static int cmd_lcd(char **matched)
1702
{
1703
	int i;
1704
	int j;
1705
	int lcd = -1;
1706
	char *s1, *s2;
1707
	char c1, c2;
1708
1709
	if (matched[0] == NULL || matched[1] == NULL)
1710
		return 0;
1711
1712
	for (i = 1; matched[i] != NULL; i++) {
1713
		s1 = matched[i - 1];
1714
		s2 = matched[i];
1715
1716
		for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
1717
			if (c1 != c2)
1718
				break;
1719
1720
		if (lcd < 0)
1721
			lcd = j;
1722
		else {
1723
			if (lcd > j)
1724
				lcd = j;
1725
		}
1726
	}
1727
	return lcd;
1728
}
1729
1730
/* Command line completion support. */
1731
static char **cmd_complete_command_real(vector vline, struct vty *vty,
1732
					int *status)
1733
{
1734
	unsigned int i;
1735
	vector cmd_vector = vector_copy(cmd_node_vector(cmdvec, vty->node));
1736
#define INIT_MATCHVEC_SIZE 10
1737
	vector matchvec;
1738
	struct cmd_element *cmd_element;
1739
	unsigned int index;
1740
	char **match_str;
1741
	struct desc *desc;
1742
	vector descvec;
1743
	char *command;
1744
	int lcd;
1745
1746
	if (vector_active(vline) == 0) {
1747
		*status = CMD_ERR_NO_MATCH;
1748
		return NULL;
1749
	} else
1750
		index = vector_active(vline) - 1;
1751
1752
	/* First, filter by preceeding command string */
1753
	for (i = 0; i < index; i++)
1754
		if ((command = vector_slot(vline, i))) {
1755
			enum match_type match;
1756
			int ret;
1757
1758
			/* First try completion match, if there is exactly match return 1 */
1759
			match =
1760
			    cmd_filter_by_completion(command, cmd_vector, i);
1761
1762
			/* If there is exact match then filter ambiguous match else check
1763
			   ambiguousness. */
1764
			if ((ret =
1765
			     is_cmd_ambiguous(command, cmd_vector, i,
1766
					      match)) == 1) {
1767
				vector_free(cmd_vector);
1768
				*status = CMD_ERR_AMBIGUOUS;
1769
				return NULL;
1770
			}
1771
			/*
1772
			   else if (ret == 2)
1773
			   {
1774
			   vector_free (cmd_vector);
1775
			   *status = CMD_ERR_NO_MATCH;
1776
			   return NULL;
1777
			   }
1778
			 */
1779
		}
1780
1781
	/* Prepare match vector. */
1782
	matchvec = vector_init(INIT_MATCHVEC_SIZE);
1783
1784
	/* Now we got into completion */
1785
	for (i = 0; i < vector_active(cmd_vector); i++)
1786
		if ((cmd_element = vector_slot(cmd_vector, i))) {
1787
			const char *string;
1788
			vector strvec = cmd_element->strvec;
1789
1790
			/* Check field length */
1791
			if (index >= vector_active(strvec))
1792
				vector_slot(cmd_vector, i) = NULL;
1793
			else {
1794
				unsigned int j;
1795
1796
				descvec = vector_slot(strvec, index);
1797
				for (j = 0; j < vector_active(descvec); j++)
1798
					if ((desc = vector_slot(descvec, j))) {
1799
						if ((string =
1800
						     cmd_entry_function
1801
						     (vector_slot(vline, index),
1802
						      desc->cmd)))
1803
							if (cmd_unique_string
1804
							    (matchvec, string))
1805
								vector_set
1806
								    (matchvec,
1807
								     strdup
1808
								     (string));
1809
					}
1810
			}
1811
		}
1812
1813
	/* We don't need cmd_vector any more. */
1814
	vector_free(cmd_vector);
1815
1816
	/* No matched command */
1817
	if (vector_slot(matchvec, 0) == NULL) {
1818
		vector_free(matchvec);
1819
1820
		/* In case of 'command \t' pattern.  Do you need '?' command at
1821
		   the end of the line. */
1822
		if (vector_slot(vline, index) == '\0')
1823
			*status = CMD_ERR_NOTHING_TODO;
1824
		else
1825
			*status = CMD_ERR_NO_MATCH;
1826
		return NULL;
1827
	}
1828
1829
	/* Only one matched */
1830
	if (vector_slot(matchvec, 1) == NULL) {
1831
		match_str = (char **)matchvec->index;
1832
		vector_only_wrapper_free(matchvec);
1833
		*status = CMD_COMPLETE_FULL_MATCH;
1834
		return match_str;
1835
	}
1836
	/* Make it sure last element is NULL. */
1837
	vector_set(matchvec, NULL);
1838
1839
	/* Check LCD of matched strings. */
1840
	if (vector_slot(vline, index) != NULL) {
1841
		lcd = cmd_lcd((char **)matchvec->index);
1842
1843
		if (lcd) {
1844
			int len = strlen(vector_slot(vline, index));
1845
1846
			if (len < lcd) {
1847
				char *lcdstr;
1848
1849
				lcdstr = malloc(lcd + 1);
1850
				memcpy(lcdstr, matchvec->index[0], lcd);
1851
				lcdstr[lcd] = '\0';
1852
1853
				/* match_str = (char **) &lcdstr; */
1854
1855
				/* Free matchvec. */
1856
				for (i = 0; i < vector_active(matchvec); i++) {
1857
					if (vector_slot(matchvec, i))
1858
						free(vector_slot(matchvec, i));
1859
				}
1860
				vector_free(matchvec);
1861
1862
				/* Make new matchvec. */
1863
				matchvec = vector_init(INIT_MATCHVEC_SIZE);
1864
				vector_set(matchvec, lcdstr);
1865
				match_str = (char **)matchvec->index;
1866
				vector_only_wrapper_free(matchvec);
1867
1868
				*status = CMD_COMPLETE_MATCH;
1869
				return match_str;
1870
			}
1871
		}
1872
	}
1873
1874
	match_str = (char **)matchvec->index;
1875
	vector_only_wrapper_free(matchvec);
1876
	*status = CMD_COMPLETE_LIST_MATCH;
1877
	return match_str;
1878
}
1879
1880
char **cmd_complete_command(vector vline, struct vty *vty, int *status)
1881
{
1882
	char **ret;
1883
1884
	if (cmd_try_do_shortcut(vty->node, vector_slot(vline, 0))) {
1885
		enum node_type onode;
1886
		vector shifted_vline;
1887
		unsigned int index;
1888
1889
		onode = vty->node;
1890
		vty->node = ENABLE_NODE;
1891
		/* We can try it on enable node, cos' the vty is authenticated */
1892
1893
		shifted_vline = vector_init(vector_count(vline));
1894
		/* use memcpy? */
1895
		for (index = 1; index < vector_active(vline); index++) {
1896
			vector_set_index(shifted_vline, index - 1,
1897
					 vector_lookup(vline, index));
1898
		}
1899
1900
		ret = cmd_complete_command_real(shifted_vline, vty, status);
1901
1902
		vector_free(shifted_vline);
1903
		vty->node = onode;
1904
		return ret;
1905
	}
1906
1907
	return cmd_complete_command_real(vline, vty, status);
1908
}
1909
1910
/* return parent node */
1911
/* MUST eventually converge on CONFIG_NODE */
1912
enum node_type node_parent(enum node_type node)
1913
{
1914
	enum node_type ret;
1915
1916
	assert(node > CONFIG_NODE);
1917
1918
	switch (node) {
1919
	case BGP_VPNV4_NODE:
1920
	case BGP_IPV4_NODE:
1921
	case BGP_IPV4M_NODE:
1922
	case BGP_IPV6_NODE:
1923
		ret = BGP_NODE;
1924
		break;
1925
	case KEYCHAIN_KEY_NODE:
1926
		ret = KEYCHAIN_NODE;
1927
		break;
1928
	default:
1929
		ret = CONFIG_NODE;
1930
	}
1931
1932
	return ret;
1933
}
1934
1935
/* Execute command by argument vline vector. */
1936
static int
1937
cmd_execute_command_real(vector vline, struct vty *vty,
1938
			 struct cmd_element **cmd)
1939
{
1940
	unsigned int i;
1941
	unsigned int index;
1942
	vector cmd_vector;
1943
	struct cmd_element *cmd_element;
1944
	struct cmd_element *matched_element;
1945
	unsigned int matched_count, incomplete_count;
1946
	int argc;
1947
	const char *argv[CMD_ARGC_MAX];
1948
	enum match_type match = 0;
1949
	int varflag;
1950
	char *command;
1951
1952
	/* Make copy of command elements. */
1953
	cmd_vector = vector_copy(cmd_node_vector(cmdvec, vty->node));
1954
1955
	for (index = 0; index < vector_active(vline); index++)
1956
		if ((command = vector_slot(vline, index))) {
1957
			int ret;
1958
1959
			match =
1960
			    cmd_filter_by_completion(command, cmd_vector,
1961
						     index);
1962
1963
			if (match == vararg_match)
1964
				break;
1965
1966
			ret =
1967
			    is_cmd_ambiguous(command, cmd_vector, index, match);
1968
1969
			if (ret == 1) {
1970
				vector_free(cmd_vector);
1971
				return CMD_ERR_AMBIGUOUS;
1972
			} else if (ret == 2) {
1973
				vector_free(cmd_vector);
1974
				return CMD_ERR_NO_MATCH;
1975
			}
1976
		}
1977
1978
	/* Check matched count. */
1979
	matched_element = NULL;
1980
	matched_count = 0;
1981
	incomplete_count = 0;
1982
1983
	for (i = 0; i < vector_active(cmd_vector); i++)
1984
		if ((cmd_element = vector_slot(cmd_vector, i))) {
1985
			if (match == vararg_match
1986
			    || index >= cmd_element->cmdsize) {
1987
				matched_element = cmd_element;
1988
#if 0
1989
				printf("DEBUG: %s\n", cmd_element->string);
1990
#endif
1991
				matched_count++;
1992
			} else {
1993
				incomplete_count++;
1994
			}
1995
		}
1996
1997
	/* Finish of using cmd_vector. */
1998
	vector_free(cmd_vector);
1999
2000
	/* To execute command, matched_count must be 1. */
2001
	if (matched_count == 0) {
2002
		if (incomplete_count)
2003
			return CMD_ERR_INCOMPLETE;
2004
		else
2005
			return CMD_ERR_NO_MATCH;
2006
	}
2007
2008
	if (matched_count > 1)
2009
		return CMD_ERR_AMBIGUOUS;
2010
2011
	/* Argument treatment */
2012
	varflag = 0;
2013
	argc = 0;
2014
2015
	for (i = 0; i < vector_active(vline); i++) {
2016
		if (varflag)
2017
			argv[argc++] = vector_slot(vline, i);
2018
		else {
2019
			vector descvec =
2020
			    vector_slot(matched_element->strvec, i);
2021
2022
			if (vector_active(descvec) == 1) {
2023
				struct desc *desc = vector_slot(descvec, 0);
2024
2025
				if (CMD_VARARG(desc->cmd))
2026
					varflag = 1;
2027
2028
				if (varflag || CMD_VARIABLE(desc->cmd)
2029
				    || CMD_OPTION(desc->cmd))
2030
					argv[argc++] = vector_slot(vline, i);
2031
			} else
2032
				argv[argc++] = vector_slot(vline, i);
2033
		}
2034
2035
		if (argc >= CMD_ARGC_MAX)
2036
			return CMD_ERR_EXEED_ARGC_MAX;
2037
	}
2038
2039
	/* For vtysh execution. */
2040
	if (cmd)
2041
		*cmd = matched_element;
2042
2043
	if (matched_element->daemon)
2044
		return CMD_SUCCESS_DAEMON;
2045
2046
	/* Execute matched command. */
2047
	return (*matched_element->func) (matched_element, vty, argc, argv);
2048
}
2049
2050
int
2051
cmd_execute_command(vector vline, struct vty *vty, struct cmd_element **cmd,
2052
		    int vtysh)
2053
{
2054
	int ret, saved_ret, tried = 0;
2055
	enum node_type onode, try_node;
2056
2057
	onode = try_node = vty->node;
2058
2059
	if (cmd_try_do_shortcut(vty->node, vector_slot(vline, 0))) {
2060
		vector shifted_vline;
2061
		unsigned int index;
2062
2063
		vty->node = ENABLE_NODE;
2064
		/* We can try it on enable node, cos' the vty is authenticated */
2065
2066
		shifted_vline = vector_init(vector_count(vline));
2067
		/* use memcpy? */
2068
		for (index = 1; index < vector_active(vline); index++) {
2069
			vector_set_index(shifted_vline, index - 1,
2070
					 vector_lookup(vline, index));
2071
		}
2072
2073
		ret = cmd_execute_command_real(shifted_vline, vty, cmd);
2074
2075
		vector_free(shifted_vline);
2076
		vty->node = onode;
2077
		return ret;
2078
	}
2079
2080
	saved_ret = ret = cmd_execute_command_real(vline, vty, cmd);
2081
2082
	if (vtysh)
2083
		return saved_ret;
2084
2085
	/* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
2086
	while (ret != CMD_SUCCESS && ret != CMD_WARNING
2087
	       && vty->node > CONFIG_NODE) {
2088
		try_node = node_parent(try_node);
2089
		vty->node = try_node;
2090
		ret = cmd_execute_command_real(vline, vty, cmd);
2091
		tried = 1;
2092
		if (ret == CMD_SUCCESS || ret == CMD_WARNING) {
2093
			/* succesfull command, leave the node as is */
2094
			return ret;
2095
		}
2096
	}
2097
	/* no command succeeded, reset the vty to the original node and
2098
	   return the error for this node */
2099
	if (tried)
2100
		vty->node = onode;
2101
	return saved_ret;
2102
}
2103
2104
/* Execute command by argument readline. */
2105
int
2106
cmd_execute_command_strict(vector vline, struct vty *vty,
2107
			   struct cmd_element **cmd)
2108
{
2109
	unsigned int i;
2110
	unsigned int index;
2111
	vector cmd_vector;
2112
	struct cmd_element *cmd_element;
2113
	struct cmd_element *matched_element;
2114
	unsigned int matched_count, incomplete_count;
2115
	int argc;
2116
	const char *argv[CMD_ARGC_MAX];
2117
	int varflag;
2118
	enum match_type match = 0;
2119
	char *command;
2120
2121
	/* Make copy of command element */
2122
	cmd_vector = vector_copy(cmd_node_vector(cmdvec, vty->node));
2123
2124
	for (index = 0; index < vector_active(vline); index++)
2125
		if ((command = vector_slot(vline, index))) {
2126
			int ret;
2127
2128
			match = cmd_filter_by_string(vector_slot(vline, index),
2129
						     cmd_vector, index);
2130
2131
			/* If command meets '.VARARG' then finish matching. */
2132
			if (match == vararg_match)
2133
				break;
2134
2135
			ret =
2136
			    is_cmd_ambiguous(command, cmd_vector, index, match);
2137
			if (ret == 1) {
2138
				vector_free(cmd_vector);
2139
				return CMD_ERR_AMBIGUOUS;
2140
			}
2141
			if (ret == 2) {
2142
				vector_free(cmd_vector);
2143
				return CMD_ERR_NO_MATCH;
2144
			}
2145
		}
2146
2147
	/* Check matched count. */
2148
	matched_element = NULL;
2149
	matched_count = 0;
2150
	incomplete_count = 0;
2151
	for (i = 0; i < vector_active(cmd_vector); i++)
2152
		if (vector_slot(cmd_vector, i) != NULL) {
2153
			cmd_element = vector_slot(cmd_vector, i);
2154
2155
			if (match == vararg_match
2156
			    || index >= cmd_element->cmdsize) {
2157
				matched_element = cmd_element;
2158
				matched_count++;
2159
			} else
2160
				incomplete_count++;
2161
		}
2162
2163
	/* Finish of using cmd_vector. */
2164
	vector_free(cmd_vector);
2165
2166
	/* To execute command, matched_count must be 1. */
2167
	if (matched_count == 0) {
2168
		if (incomplete_count)
2169
			return CMD_ERR_INCOMPLETE;
2170
		else
2171
			return CMD_ERR_NO_MATCH;
2172
	}
2173
2174
	if (matched_count > 1)
2175
		return CMD_ERR_AMBIGUOUS;
2176
2177
	/* Argument treatment */
2178
	varflag = 0;
2179
	argc = 0;
2180
2181
	for (i = 0; i < vector_active(vline); i++) {
2182
		if (varflag)
2183
			argv[argc++] = vector_slot(vline, i);
2184
		else {
2185
			vector descvec =
2186
			    vector_slot(matched_element->strvec, i);
2187
2188
			if (vector_active(descvec) == 1) {
2189
				struct desc *desc = vector_slot(descvec, 0);
2190
2191
				if (CMD_VARARG(desc->cmd))
2192
					varflag = 1;
2193
2194
				if (varflag || CMD_VARIABLE(desc->cmd)
2195
				    || CMD_OPTION(desc->cmd))
2196
					argv[argc++] = vector_slot(vline, i);
2197
			} else
2198
				argv[argc++] = vector_slot(vline, i);
2199
		}
2200
2201
		if (argc >= CMD_ARGC_MAX)
2202
			return CMD_ERR_EXEED_ARGC_MAX;
2203
	}
2204
2205
	/* For vtysh execution. */
2206
	if (cmd)
2207
		*cmd = matched_element;
2208
2209
	if (matched_element->daemon)
2210
		return CMD_SUCCESS_DAEMON;
2211
2212
	/* Now execute matched command */
2213
	return (*matched_element->func) (matched_element, vty, argc, argv);
2214
}
2215
2216
#if 0
2217
/* Configration make from file. */
2218
int config_from_file(struct vty *vty, FILE * fp)
2219
{
2220
	int ret;
2221
	vector vline;
2222
2223
	while (fgets(vty->buf, VTY_BUFSIZ, fp)) {
2224
		vline = cmd_make_strvec(vty->buf);
2225
2226
		/* In case of comment line */
2227
		if (vline == NULL)
2228
			continue;
2229
		/* Execute configuration command : this is strict match */
2230
		ret = cmd_execute_command_strict(vline, vty, NULL);
2231
2232
		/* Try again with setting node to CONFIG_NODE */
2233
		while (ret != CMD_SUCCESS && ret != CMD_WARNING
2234
		       && ret != CMD_ERR_NOTHING_TODO
2235
		       && vty->node != CONFIG_NODE) {
2236
			vty->node = node_parent(vty->node);
2237
			ret = cmd_execute_command_strict(vline, vty, NULL);
2238
		}
2239
2240
		cmd_free_strvec(vline);
2241
2242
		if (ret != CMD_SUCCESS && ret != CMD_WARNING
2243
		    && ret != CMD_ERR_NOTHING_TODO)
2244
			return ret;
2245
	}
2246
	return CMD_SUCCESS;
2247
}
2248
#endif
2249
2250
/* Configration from terminal */
2251
DEFUN(config_terminal,
2252
      config_terminal_cmd,
2253
      "configure terminal",
2254
      "Configuration from vty interface\n" "Configuration terminal\n")
2255
{
2256
	if (vty_config_lock(vty))
2257
		vty->node = CONFIG_NODE;
2258
	else {
2259
		vty_out(vty, "VTY configuration is locked by other VTY%s",
2260
			VTY_NEWLINE);
2261
		return CMD_WARNING;
2262
	}
2263
	return CMD_SUCCESS;
2264
}
2265
2266
/* Enable command */
2267
DEFUN(enable, config_enable_cmd, "enable", "Turn on privileged mode command\n")
2268
{
2269
	/* If enable password is NULL, change to ENABLE_NODE */
2270
	if ((host.enable == NULL && host.enable_encrypt == NULL) ||
2271
	    vty->type == VTY_SHELL_SERV)
2272
		vty->node = ENABLE_NODE;
2273
	else
2274
		vty->node = AUTH_ENABLE_NODE;
2275
2276
	return CMD_SUCCESS;
2277
}
2278
2279
/* Disable command */
2280
DEFUN(disable,
2281
      config_disable_cmd, "disable", "Turn off privileged mode command\n")
2282
{
2283
	if (vty->node == ENABLE_NODE)
2284
		vty->node = VIEW_NODE;
2285
	return CMD_SUCCESS;
2286
}
2287
2288
/* Down vty node level. */
2289
DEFUN(config_exit,
2290
      config_exit_cmd, "exit", "Exit current mode and down to previous mode\n")
2291
{
2292
	switch (vty->node) {
2293
	case RC632_NODE:
2294
		vty->node = VIEW_NODE;
2295
		break;
2296
	case VIEW_NODE:
2297
	case ENABLE_NODE:
2298
		if (0)		//vty_shell (vty))
2299
			exit(0);
2300
		else
2301
			vty->status = VTY_CLOSE;
2302
		break;
2303
	case CONFIG_NODE:
2304
		vty->node = ENABLE_NODE;
2305
		vty_config_unlock(vty);
2306
		break;
2307
	case INTERFACE_NODE:
2308
	case ZEBRA_NODE:
2309
	case BGP_NODE:
2310
	case RIP_NODE:
2311
	case RIPNG_NODE:
2312
	case OSPF_NODE:
2313
	case OSPF6_NODE:
2314
	case ISIS_NODE:
2315
	case KEYCHAIN_NODE:
2316
	case MASC_NODE:
2317
	case RMAP_NODE:
2318
	case VTY_NODE:
2319
		vty->node = CONFIG_NODE;
2320
		break;
2321
	case BGP_VPNV4_NODE:
2322
	case BGP_IPV4_NODE:
2323
	case BGP_IPV4M_NODE:
2324
	case BGP_IPV6_NODE:
2325
		vty->node = BGP_NODE;
2326
		break;
2327
	case KEYCHAIN_KEY_NODE:
2328
		vty->node = KEYCHAIN_NODE;
2329
		break;
2330
	default:
2331
		break;
2332
	}
2333
	return CMD_SUCCESS;
2334
}
2335
2336
/* quit is alias of exit. */
2337
ALIAS(config_exit,
2338
      config_quit_cmd, "quit", "Exit current mode and down to previous mode\n")
2339
2340
/* End of configuration. */
2341
    DEFUN(config_end,
2342
      config_end_cmd, "end", "End current mode and change to enable mode.")
2343
{
2344
	switch (vty->node) {
2345
	case VIEW_NODE:
2346
	case ENABLE_NODE:
2347
		/* Nothing to do. */
2348
		break;
2349
	case CONFIG_NODE:
2350
	case INTERFACE_NODE:
2351
	case ZEBRA_NODE:
2352
	case RIP_NODE:
2353
	case RIPNG_NODE:
2354
	case BGP_NODE:
2355
	case BGP_VPNV4_NODE:
2356
	case BGP_IPV4_NODE:
2357
	case BGP_IPV4M_NODE:
2358
	case BGP_IPV6_NODE:
2359
	case RMAP_NODE:
2360
	case OSPF_NODE:
2361
	case OSPF6_NODE:
2362
	case ISIS_NODE:
2363
	case KEYCHAIN_NODE:
2364
	case KEYCHAIN_KEY_NODE:
2365
	case MASC_NODE:
2366
	case VTY_NODE:
2367
		vty_config_unlock(vty);
2368
		vty->node = ENABLE_NODE;
2369
		break;
2370
	default:
2371
		break;
2372
	}
2373
	return CMD_SUCCESS;
2374
}
2375
2376
/* Show version. */
2377
DEFUN(show_version,
2378
      show_version_cmd, "show version", SHOW_STR "Displays program version\n")
2379
{
2380
	vty_out(vty, "%s %s (%s).%s", QUAGGA_PROGNAME, QUAGGA_VERSION,
2381
		host.name ? host.name : "", VTY_NEWLINE);
2382
	vty_out(vty, "%s%s", QUAGGA_COPYRIGHT, VTY_NEWLINE);
2383
2384
	return CMD_SUCCESS;
2385
}
2386
2387
/* Help display function for all node. */
2388
DEFUN(config_help,
2389
      config_help_cmd, "help", "Description of the interactive help system\n")
2390
{
2391
	vty_out(vty,
2392
		"This VTY provides advanced help features.  When you need help,%s\
2393
anytime at the command line please press '?'.%s\
2394
%s\
2395
If nothing matches, the help list will be empty and you must backup%s\
2396
 until entering a '?' shows the available options.%s\
2397
Two styles of help are provided:%s\
2398
1. Full help is available when you are ready to enter a%s\
2399
command argument (e.g. 'show ?') and describes each possible%s\
2400
argument.%s\
2401
2. Partial help is provided when an abbreviated argument is entered%s\
2402
   and you want to know what arguments match the input%s\
2403
   (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2404
		VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
2405
	return CMD_SUCCESS;
2406
}
2407
2408
/* Help display function for all node. */
2409
DEFUN(config_list, config_list_cmd, "list", "Print command list\n")
2410
{
2411
	unsigned int i;
2412
	struct cmd_node *cnode = vector_slot(cmdvec, vty->node);
2413
	struct cmd_element *cmd;
2414
2415
	for (i = 0; i < vector_active(cnode->cmd_vector); i++)
2416
		if ((cmd = vector_slot(cnode->cmd_vector, i)) != NULL
2417
		    && !(cmd->attr == CMD_ATTR_DEPRECATED
2418
			 || cmd->attr == CMD_ATTR_HIDDEN))
2419
			vty_out(vty, "  %s%s", cmd->string, VTY_NEWLINE);
2420
	return CMD_SUCCESS;
2421
}
2422
2423
#if 0
2424
/* Write current configuration into file. */
2425
DEFUN(config_write_file,
2426
      config_write_file_cmd,
2427
      "write file",
2428
      "Write running configuration to memory, network, or terminal\n"
2429
      "Write to configuration file\n")
2430
{
2431
	unsigned int i;
2432
	int fd;
2433
	struct cmd_node *node;
2434
	char *config_file;
2435
	char *config_file_tmp = NULL;
2436
	char *config_file_sav = NULL;
2437
	struct vty *file_vty;
2438
2439
	/* Check and see if we are operating under vtysh configuration */
2440
	if (host.config == NULL) {
2441
		vty_out(vty, "Can't save to configuration file, using vtysh.%s",
2442
			VTY_NEWLINE);
2443
		return CMD_WARNING;
2444
	}
2445
2446
	/* Get filename. */
2447
	config_file = host.config;
2448
2449
	config_file_sav =
2450
	    malloc(strlen(config_file) + strlen(CONF_BACKUP_EXT) + 1);
2451
	strcpy(config_file_sav, config_file);
2452
	strcat(config_file_sav, CONF_BACKUP_EXT);
2453
2454
	config_file_tmp = malloc(strlen(config_file) + 8);
2455
	sprintf(config_file_tmp, "%s.XXXXXX", config_file);
2456
2457
	/* Open file to configuration write. */
2458
	fd = mkstemp(config_file_tmp);
2459
	if (fd < 0) {
2460
		vty_out(vty, "Can't open configuration file %s.%s",
2461
			config_file_tmp, VTY_NEWLINE);
2462
		free(config_file_tmp);
2463
		free(config_file_sav);
2464
		return CMD_WARNING;
2465
	}
2466
2467
	/* Make vty for configuration file. */
2468
	file_vty = vty_new();
2469
	file_vty->fd = fd;
2470
	file_vty->type = VTY_FILE;
2471
2472
	/* Config file header print. */
2473
	vty_out(file_vty, "!\n! Zebra configuration saved from vty\n!   ");
2474
	//vty_time_print (file_vty, 1);
2475
	vty_out(file_vty, "!\n");
2476
2477
	for (i = 0; i < vector_active(cmdvec); i++)
2478
		if ((node = vector_slot(cmdvec, i)) && node->func) {
2479
			if ((*node->func) (file_vty))
2480
				vty_out(file_vty, "!\n");
2481
		}
2482
	vty_close(file_vty);
2483
2484
	if (unlink(config_file_sav) != 0)
2485
		if (errno != ENOENT) {
2486
			vty_out(vty,
2487
				"Can't unlink backup configuration file %s.%s",
2488
				config_file_sav, VTY_NEWLINE);
2489
			free(config_file_sav);
2490
			free(config_file_tmp);
2491
			unlink(config_file_tmp);
2492
			return CMD_WARNING;
2493
		}
2494
	if (link(config_file, config_file_sav) != 0) {
2495
		vty_out(vty, "Can't backup old configuration file %s.%s",
2496
			config_file_sav, VTY_NEWLINE);
2497
		free(config_file_sav);
2498
		free(config_file_tmp);
2499
		unlink(config_file_tmp);
2500
		return CMD_WARNING;
2501
	}
2502
	sync();
2503
	if (unlink(config_file) != 0) {
2504
		vty_out(vty, "Can't unlink configuration file %s.%s",
2505
			config_file, VTY_NEWLINE);
2506
		free(config_file_sav);
2507
		free(config_file_tmp);
2508
		unlink(config_file_tmp);
2509
		return CMD_WARNING;
2510
	}
2511
	if (link(config_file_tmp, config_file) != 0) {
2512
		vty_out(vty, "Can't save configuration file %s.%s", config_file,
2513
			VTY_NEWLINE);
2514
		free(config_file_sav);
2515
		free(config_file_tmp);
2516
		unlink(config_file_tmp);
2517
		return CMD_WARNING;
2518
	}
2519
	unlink(config_file_tmp);
2520
	sync();
2521
2522
	free(config_file_sav);
2523
	free(config_file_tmp);
2524
2525
	if (chmod(config_file, CONFIGFILE_MASK) != 0) {
2526
		vty_out(vty, "Can't chmod configuration file %s: %s (%d).%s",
2527
			config_file, safe_strerror(errno), errno, VTY_NEWLINE);
2528
		return CMD_WARNING;
2529
	}
2530
2531
	vty_out(vty, "Configuration saved to %s%s", config_file, VTY_NEWLINE);
2532
	return CMD_SUCCESS;
2533
}
2534
2535
ALIAS(config_write_file,
2536
      config_write_cmd,
2537
      "write", "Write running configuration to memory, network, or terminal\n")
2538
2539
    ALIAS(config_write_file,
2540
      config_write_memory_cmd,
2541
      "write memory",
2542
      "Write running configuration to memory, network, or terminal\n"
2543
      "Write configuration to the file (same as write file)\n")
2544
2545
    ALIAS(config_write_file,
2546
      copy_runningconfig_startupconfig_cmd,
2547
      "copy running-config startup-config",
2548
      "Copy configuration\n"
2549
      "Copy running config to... \n"
2550
      "Copy running config to startup config (same as write file)\n")
2551
2552
/* Write current configuration into the terminal. */
2553
    DEFUN(config_write_terminal,
2554
      config_write_terminal_cmd,
2555
      "write terminal",
2556
      "Write running configuration to memory, network, or terminal\n"
2557
      "Write to terminal\n")
2558
{
2559
	unsigned int i;
2560
	struct cmd_node *node;
2561
2562
	if (vty->type == VTY_SHELL_SERV) {
2563
		for (i = 0; i < vector_active(cmdvec); i++)
2564
			if ((node = vector_slot(cmdvec, i)) && node->func
2565
			    && node->vtysh) {
2566
				if ((*node->func) (vty))
2567
					vty_out(vty, "!%s", VTY_NEWLINE);
2568
			}
2569
	} else {
2570
		vty_out(vty, "%sCurrent configuration:%s", VTY_NEWLINE,
2571
			VTY_NEWLINE);
2572
		vty_out(vty, "!%s", VTY_NEWLINE);
2573
2574
		for (i = 0; i < vector_active(cmdvec); i++)
2575
			if ((node = vector_slot(cmdvec, i)) && node->func) {
2576
				if ((*node->func) (vty))
2577
					vty_out(vty, "!%s", VTY_NEWLINE);
2578
			}
2579
		vty_out(vty, "end%s", VTY_NEWLINE);
2580
	}
2581
	return CMD_SUCCESS;
2582
}
2583
2584
/* Write current configuration into the terminal. */
2585
ALIAS(config_write_terminal,
2586
      show_running_config_cmd,
2587
      "show running-config", SHOW_STR "running configuration\n")
2588
2589
/* Write startup configuration into the terminal. */
2590
    DEFUN(show_startup_config,
2591
      show_startup_config_cmd,
2592
      "show startup-config", SHOW_STR "Contentes of startup configuration\n")
2593
{
2594
	char buf[BUFSIZ];
2595
	FILE *confp;
2596
2597
	confp = fopen(host.config, "r");
2598
	if (confp == NULL) {
2599
		vty_out(vty, "Can't open configuration file [%s]%s",
2600
			host.config, VTY_NEWLINE);
2601
		return CMD_WARNING;
2602
	}
2603
2604
	while (fgets(buf, BUFSIZ, confp)) {
2605
		char *cp = buf;
2606
2607
		while (*cp != '\r' && *cp != '\n' && *cp != '\0')
2608
			cp++;
2609
		*cp = '\0';
2610
2611
		vty_out(vty, "%s%s", buf, VTY_NEWLINE);
2612
	}
2613
2614
	fclose(confp);
2615
2616
	return CMD_SUCCESS;
2617
}
2618
#endif
2619
2620
/* Hostname configuration */
2621
DEFUN(config_hostname,
2622
      hostname_cmd,
2623
      "hostname WORD",
2624
      "Set system's network name\n" "This system's network name\n")
2625
{
2626
	if (!isalpha((int)*argv[0])) {
2627
		vty_out(vty, "Please specify string starting with alphabet%s",
2628
			VTY_NEWLINE);
2629
		return CMD_WARNING;
2630
	}
2631
2632
	if (host.name)
2633
		free(host.name);
2634
2635
	host.name = strdup(argv[0]);
2636
	return CMD_SUCCESS;
2637
}
2638
2639
DEFUN(config_no_hostname,
2640
      no_hostname_cmd,
2641
      "no hostname [HOSTNAME]",
2642
      NO_STR "Reset system's network name\n" "Host name of this router\n")
2643
{
2644
	if (host.name)
2645
		free(host.name);
2646
	host.name = NULL;
2647
	return CMD_SUCCESS;
2648
}
2649
2650
/* VTY interface password set. */
2651
DEFUN(config_password, password_cmd,
2652
      "password (8|) WORD",
2653
      "Assign the terminal connection password\n"
2654
      "Specifies a HIDDEN password will follow\n"
2655
      "dummy string \n" "The HIDDEN line password string\n")
2656
{
2657
	/* Argument check. */
2658
	if (argc == 0) {
2659
		vty_out(vty, "Please specify password.%s", VTY_NEWLINE);
2660
		return CMD_WARNING;
2661
	}
2662
2663
	if (argc == 2) {
2664
		if (*argv[0] == '8') {
2665
			if (host.password)
2666
				free(host.password);
2667
			host.password = NULL;
2668
			if (host.password_encrypt)
2669
				free(host.password_encrypt);
2670
			host.password_encrypt = strdup(strdup(argv[1]));
2671
			return CMD_SUCCESS;
2672
		} else {
2673
			vty_out(vty, "Unknown encryption type.%s", VTY_NEWLINE);
2674
			return CMD_WARNING;
2675
		}
2676
	}
2677
2678
	if (!isalnum((int)*argv[0])) {
2679
		vty_out(vty,
2680
			"Please specify string starting with alphanumeric%s",
2681
			VTY_NEWLINE);
2682
		return CMD_WARNING;
2683
	}
2684
2685
	if (host.password)
2686
		free(host.password);
2687
	host.password = NULL;
2688
2689
	if (host.encrypt) {
2690
		if (host.password_encrypt)
2691
			free(host.password_encrypt);
2692
		host.password_encrypt = strdup(zencrypt(argv[0]));
2693
	} else
2694
		host.password = strdup(argv[0]);
2695
2696
	return CMD_SUCCESS;
2697
}
2698
2699
ALIAS(config_password, password_text_cmd,
2700
      "password LINE",
2701
      "Assign the terminal connection password\n"
2702
      "The UNENCRYPTED (cleartext) line password\n")
2703
2704
/* VTY enable password set. */
2705
    DEFUN(config_enable_password, enable_password_cmd,
2706
      "enable password (8|) WORD",
2707
      "Modify enable password parameters\n"
2708
      "Assign the privileged level password\n"
2709
      "Specifies a HIDDEN password will follow\n"
2710
      "dummy string \n" "The HIDDEN 'enable' password string\n")
2711
{
2712
	/* Argument check. */
2713
	if (argc == 0) {
2714
		vty_out(vty, "Please specify password.%s", VTY_NEWLINE);
2715
		return CMD_WARNING;
2716
	}
2717
2718
	/* Crypt type is specified. */
2719
	if (argc == 2) {
2720
		if (*argv[0] == '8') {
2721
			if (host.enable)
2722
				free(host.enable);
2723
			host.enable = NULL;
2724
2725
			if (host.enable_encrypt)
2726
				free(host.enable_encrypt);
2727
			host.enable_encrypt = strdup(argv[1]);
2728
2729
			return CMD_SUCCESS;
2730
		} else {
2731
			vty_out(vty, "Unknown encryption type.%s", VTY_NEWLINE);
2732
			return CMD_WARNING;
2733
		}
2734
	}
2735
2736
	if (!isalnum((int)*argv[0])) {
2737
		vty_out(vty,
2738
			"Please specify string starting with alphanumeric%s",
2739
			VTY_NEWLINE);
2740
		return CMD_WARNING;
2741
	}
2742
2743
	if (host.enable)
2744
		free(host.enable);
2745
	host.enable = NULL;
2746
2747
	/* Plain password input. */
2748
	if (host.encrypt) {
2749
		if (host.enable_encrypt)
2750
			free(host.enable_encrypt);
2751
		host.enable_encrypt = strdup(zencrypt(argv[0]));
2752
	} else
2753
		host.enable = strdup(argv[0]);
2754
2755
	return CMD_SUCCESS;
2756
}
2757
2758
ALIAS(config_enable_password,
2759
      enable_password_text_cmd,
2760
      "enable password LINE",
2761
      "Modify enable password parameters\n"
2762
      "Assign the privileged level password\n"
2763
      "The UNENCRYPTED (cleartext) 'enable' password\n")
2764
2765
/* VTY enable password delete. */
2766
    DEFUN(no_config_enable_password, no_enable_password_cmd,
2767
      "no enable password",
2768
      NO_STR
2769
      "Modify enable password parameters\n"
2770
      "Assign the privileged level password\n")
2771
{
2772
	if (host.enable)
2773
		free(host.enable);
2774
	host.enable = NULL;
2775
2776
	if (host.enable_encrypt)
2777
		free(host.enable_encrypt);
2778
	host.enable_encrypt = NULL;
2779
2780
	return CMD_SUCCESS;
2781
}
2782
2783
DEFUN(service_password_encrypt,
2784
      service_password_encrypt_cmd,
2785
      "service password-encryption",
2786
      "Set up miscellaneous service\n" "Enable encrypted passwords\n")
2787
{
2788
	if (host.encrypt)
2789
		return CMD_SUCCESS;
2790
2791
	host.encrypt = 1;
2792
2793
	if (host.password) {
2794
		if (host.password_encrypt)
2795
			free(host.password_encrypt);
2796
		host.password_encrypt = strdup(zencrypt(host.password));
2797
	}
2798
	if (host.enable) {
2799
		if (host.enable_encrypt)
2800
			free(host.enable_encrypt);
2801
		host.enable_encrypt = strdup(zencrypt(host.enable));
2802
	}
2803
2804
	return CMD_SUCCESS;
2805
}
2806
2807
DEFUN(no_service_password_encrypt,
2808
      no_service_password_encrypt_cmd,
2809
      "no service password-encryption",
2810
      NO_STR "Set up miscellaneous service\n" "Enable encrypted passwords\n")
2811
{
2812
	if (!host.encrypt)
2813
		return CMD_SUCCESS;
2814
2815
	host.encrypt = 0;
2816
2817
	if (host.password_encrypt)
2818
		free(host.password_encrypt);
2819
	host.password_encrypt = NULL;
2820
2821
	if (host.enable_encrypt)
2822
		free(host.enable_encrypt);
2823
	host.enable_encrypt = NULL;
2824
2825
	return CMD_SUCCESS;
2826
}
2827
2828
DEFUN(config_terminal_length, config_terminal_length_cmd,
2829
      "terminal length <0-512>",
2830
      "Set terminal line parameters\n"
2831
      "Set number of lines on a screen\n"
2832
      "Number of lines on screen (0 for no pausing)\n")
2833
{
2834
	int lines;
2835
	char *endptr = NULL;
2836
2837
	lines = strtol(argv[0], &endptr, 10);
2838
	if (lines < 0 || lines > 512 || *endptr != '\0') {
2839
		vty_out(vty, "length is malformed%s", VTY_NEWLINE);
2840
		return CMD_WARNING;
2841
	}
2842
	vty->lines = lines;
2843
2844
	return CMD_SUCCESS;
2845
}
2846
2847
DEFUN(config_terminal_no_length, config_terminal_no_length_cmd,
2848
      "terminal no length",
2849
      "Set terminal line parameters\n"
2850
      NO_STR "Set number of lines on a screen\n")
2851
{
2852
	vty->lines = -1;
2853
	return CMD_SUCCESS;
2854
}
2855
2856
DEFUN(service_terminal_length, service_terminal_length_cmd,
2857
      "service terminal-length <0-512>",
2858
      "Set up miscellaneous service\n"
2859
      "System wide terminal length configuration\n"
2860
      "Number of lines of VTY (0 means no line control)\n")
2861
{
2862
	int lines;
2863
	char *endptr = NULL;
2864
2865
	lines = strtol(argv[0], &endptr, 10);
2866
	if (lines < 0 || lines > 512 || *endptr != '\0') {
2867
		vty_out(vty, "length is malformed%s", VTY_NEWLINE);
2868
		return CMD_WARNING;
2869
	}
2870
	host.lines = lines;
2871
2872
	return CMD_SUCCESS;
2873
}
2874
2875
DEFUN(no_service_terminal_length, no_service_terminal_length_cmd,
2876
      "no service terminal-length [<0-512>]",
2877
      NO_STR
2878
      "Set up miscellaneous service\n"
2879
      "System wide terminal length configuration\n"
2880
      "Number of lines of VTY (0 means no line control)\n")
2881
{
2882
	host.lines = -1;
2883
	return CMD_SUCCESS;
2884
}
2885
2886
DEFUN_HIDDEN(do_echo,
2887
	     echo_cmd,
2888
	     "echo .MESSAGE",
2889
	     "Echo a message back to the vty\n" "The message to echo\n")
2890
{
2891
	char *message;
2892
2893
	vty_out(vty, "%s%s",
2894
		((message =
2895
		  argv_concat(argv, argc, 0)) ? message : ""), VTY_NEWLINE);
2896
	if (message)
2897
		free(message);
2898
	return CMD_SUCCESS;
2899
}
2900
2901
#if 0
2902
DEFUN(config_logmsg,
2903
      config_logmsg_cmd,
2904
      "logmsg " LOG_LEVELS " .MESSAGE",
2905
      "Send a message to enabled logging destinations\n"
2906
      LOG_LEVEL_DESC "The message to send\n")
2907
{
2908
	int level;
2909
	char *message;
2910
2911
	if ((level = level_match(argv[0])) == ZLOG_DISABLED)
2912
		return CMD_ERR_NO_MATCH;
2913
2914
	zlog(NULL, level,
2915
	     ((message = argv_concat(argv, argc, 1)) ? message : ""));
2916
	if (message)
2917
		free(message);
2918
	return CMD_SUCCESS;
2919
}
2920
2921
DEFUN(show_logging,
2922
      show_logging_cmd,
2923
      "show logging", SHOW_STR "Show current logging configuration\n")
2924
{
2925
	struct zlog *zl = zlog_default;
2926
2927
	vty_out(vty, "Syslog logging: ");
2928
	if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED)
2929
		vty_out(vty, "disabled");
2930
	else
2931
		vty_out(vty, "level %s, facility %s, ident %s",
2932
			zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]],
2933
			facility_name(zl->facility), zl->ident);
2934
	vty_out(vty, "%s", VTY_NEWLINE);
2935
2936
	vty_out(vty, "Stdout logging: ");
2937
	if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED)
2938
		vty_out(vty, "disabled");
2939
	else
2940
		vty_out(vty, "level %s",
2941
			zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
2942
	vty_out(vty, "%s", VTY_NEWLINE);
2943
2944
	vty_out(vty, "Monitor logging: ");
2945
	if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
2946
		vty_out(vty, "disabled");
2947
	else
2948
		vty_out(vty, "level %s",
2949
			zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
2950
	vty_out(vty, "%s", VTY_NEWLINE);
2951
2952
	vty_out(vty, "File logging: ");
2953
	if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) || !zl->fp)
2954
		vty_out(vty, "disabled");
2955
	else
2956
		vty_out(vty, "level %s, filename %s",
2957
			zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
2958
			zl->filename);
2959
	vty_out(vty, "%s", VTY_NEWLINE);
2960
2961
	vty_out(vty, "Protocol name: %s%s",
2962
		zlog_proto_names[zl->protocol], VTY_NEWLINE);
2963
	vty_out(vty, "Record priority: %s%s",
2964
		(zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE);
2965
2966
	return CMD_SUCCESS;
2967
}
2968
2969
DEFUN(config_log_stdout,
2970
      config_log_stdout_cmd,
2971
      "log stdout", "Logging control\n" "Set stdout logging level\n")
2972
{
2973
	zlog_set_level(NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl);
2974
	return CMD_SUCCESS;
2975
}
2976
2977
DEFUN(config_log_stdout_level,
2978
      config_log_stdout_level_cmd,
2979
      "log stdout " LOG_LEVELS,
2980
      "Logging control\n" "Set stdout logging level\n" LOG_LEVEL_DESC)
2981
{
2982
	int level;
2983
2984
	if ((level = level_match(argv[0])) == ZLOG_DISABLED)
2985
		return CMD_ERR_NO_MATCH;
2986
	zlog_set_level(NULL, ZLOG_DEST_STDOUT, level);
2987
	return CMD_SUCCESS;
2988
}
2989
2990
DEFUN(no_config_log_stdout,
2991
      no_config_log_stdout_cmd,
2992
      "no log stdout [LEVEL]",
2993
      NO_STR "Logging control\n" "Cancel logging to stdout\n" "Logging level\n")
2994
{
2995
	zlog_set_level(NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED);
2996
	return CMD_SUCCESS;
2997
}
2998
2999
DEFUN(config_log_monitor,
3000
      config_log_monitor_cmd,
3001
      "log monitor",
3002
      "Logging control\n" "Set terminal line (monitor) logging level\n")
3003
{
3004
	zlog_set_level(NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl);
3005
	return CMD_SUCCESS;
3006
}
3007
3008
DEFUN(config_log_monitor_level,
3009
      config_log_monitor_level_cmd,
3010
      "log monitor " LOG_LEVELS,
3011
      "Logging control\n"
3012
      "Set terminal line (monitor) logging level\n" LOG_LEVEL_DESC)
3013
{
3014
	int level;
3015
3016
	if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3017
		return CMD_ERR_NO_MATCH;
3018
	zlog_set_level(NULL, ZLOG_DEST_MONITOR, level);
3019
	return CMD_SUCCESS;
3020
}
3021
3022
DEFUN(no_config_log_monitor,
3023
      no_config_log_monitor_cmd,
3024
      "no log monitor [LEVEL]",
3025
      NO_STR
3026
      "Logging control\n"
3027
      "Disable terminal line (monitor) logging\n" "Logging level\n")
3028
{
3029
	zlog_set_level(NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
3030
	return CMD_SUCCESS;
3031
}
3032
3033
static int set_log_file(struct vty *vty, const char *fname, int loglevel)
3034
{
3035
	int ret;
3036
	char *p = NULL;
3037
	const char *fullpath;
3038
3039
	/* Path detection. */
3040
	if (!IS_DIRECTORY_SEP(*fname)) {
3041
		char cwd[MAXPATHLEN + 1];
3042
		cwd[MAXPATHLEN] = '\0';
3043
3044
		if (getcwd(cwd, MAXPATHLEN) == NULL) {
3045
			zlog_err("config_log_file: Unable to alloc mem!");
3046
			return CMD_WARNING;
3047
		}
3048
3049
		if ((p = malloc(strlen(cwd) + strlen(fname) + 2))
3050
		    == NULL) {
3051
			zlog_err("config_log_file: Unable to alloc mem!");
3052
			return CMD_WARNING;
3053
		}
3054
		sprintf(p, "%s/%s", cwd, fname);
3055
		fullpath = p;
3056
	} else
3057
		fullpath = fname;
3058
3059
	ret = zlog_set_file(NULL, fullpath, loglevel);
3060
3061
	if (p)
3062
		free(p);
3063
3064
	if (!ret) {
3065
		vty_out(vty, "can't open logfile %s\n", fname);
3066
		return CMD_WARNING;
3067
	}
3068
3069
	if (host.logfile)
3070
		free(host.logfile);
3071
3072
	host.logfile = strdup(fname);
3073
3074
	return CMD_SUCCESS;
3075
}
3076
3077
DEFUN(config_log_file,
3078
      config_log_file_cmd,
3079
      "log file FILENAME",
3080
      "Logging control\n" "Logging to file\n" "Logging filename\n")
3081
{
3082
	return set_log_file(vty, argv[0], zlog_default->default_lvl);
3083
}
3084
3085
DEFUN(config_log_file_level,
3086
      config_log_file_level_cmd,
3087
      "log file FILENAME " LOG_LEVELS,
3088
      "Logging control\n"
3089
      "Logging to file\n" "Logging filename\n" LOG_LEVEL_DESC)
3090
{
3091
	int level;
3092
3093
	if ((level = level_match(argv[1])) == ZLOG_DISABLED)
3094
		return CMD_ERR_NO_MATCH;
3095
	return set_log_file(vty, argv[0], level);
3096
}
3097
3098
DEFUN(no_config_log_file,
3099
      no_config_log_file_cmd,
3100
      "no log file [FILENAME]",
3101
      NO_STR
3102
      "Logging control\n" "Cancel logging to file\n" "Logging file name\n")
3103
{
3104
	zlog_reset_file(NULL);
3105
3106
	if (host.logfile)
3107
		free(host.logfile);
3108
3109
	host.logfile = NULL;
3110
3111
	return CMD_SUCCESS;
3112
}
3113
3114
ALIAS(no_config_log_file,
3115
      no_config_log_file_level_cmd,
3116
      "no log file FILENAME LEVEL",
3117
      NO_STR
3118
      "Logging control\n"
3119
      "Cancel logging to file\n" "Logging file name\n" "Logging level\n")
3120
3121
    DEFUN(config_log_syslog,
3122
      config_log_syslog_cmd,
3123
      "log syslog", "Logging control\n" "Set syslog logging level\n")
3124
{
3125
	zlog_set_level(NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
3126
	return CMD_SUCCESS;
3127
}
3128
3129
DEFUN(config_log_syslog_level,
3130
      config_log_syslog_level_cmd,
3131
      "log syslog " LOG_LEVELS,
3132
      "Logging control\n" "Set syslog logging level\n" LOG_LEVEL_DESC)
3133
{
3134
	int level;
3135
3136
	if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3137
		return CMD_ERR_NO_MATCH;
3138
	zlog_set_level(NULL, ZLOG_DEST_SYSLOG, level);
3139
	return CMD_SUCCESS;
3140
}
3141
3142
DEFUN_DEPRECATED(config_log_syslog_facility,
3143
		 config_log_syslog_facility_cmd,
3144
		 "log syslog facility " LOG_FACILITIES,
3145
		 "Logging control\n"
3146
		 "Logging goes to syslog\n"
3147
		 "(Deprecated) Facility parameter for syslog messages\n"
3148
		 LOG_FACILITY_DESC)
3149
{
3150
	int facility;
3151
3152
	if ((facility = facility_match(argv[0])) < 0)
3153
		return CMD_ERR_NO_MATCH;
3154
3155
	zlog_set_level(NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
3156
	zlog_default->facility = facility;
3157
	return CMD_SUCCESS;
3158
}
3159
3160
DEFUN(no_config_log_syslog,
3161
      no_config_log_syslog_cmd,
3162
      "no log syslog [LEVEL]",
3163
      NO_STR "Logging control\n" "Cancel logging to syslog\n" "Logging level\n")
3164
{
3165
	zlog_set_level(NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
3166
	return CMD_SUCCESS;
3167
}
3168
3169
ALIAS(no_config_log_syslog,
3170
      no_config_log_syslog_facility_cmd,
3171
      "no log syslog facility " LOG_FACILITIES,
3172
      NO_STR
3173
      "Logging control\n"
3174
      "Logging goes to syslog\n"
3175
      "Facility parameter for syslog messages\n" LOG_FACILITY_DESC)
3176
3177
    DEFUN(config_log_facility,
3178
      config_log_facility_cmd,
3179
      "log facility " LOG_FACILITIES,
3180
      "Logging control\n"
3181
      "Facility parameter for syslog messages\n" LOG_FACILITY_DESC)
3182
{
3183
	int facility;
3184
3185
	if ((facility = facility_match(argv[0])) < 0)
3186
		return CMD_ERR_NO_MATCH;
3187
	zlog_default->facility = facility;
3188
	return CMD_SUCCESS;
3189
}
3190
3191
DEFUN(no_config_log_facility,
3192
      no_config_log_facility_cmd,
3193
      "no log facility [FACILITY]",
3194
      NO_STR
3195
      "Logging control\n"
3196
      "Reset syslog facility to default (daemon)\n" "Syslog facility\n")
3197
{
3198
	zlog_default->facility = LOG_DAEMON;
3199
	return CMD_SUCCESS;
3200
}
3201
3202
DEFUN_DEPRECATED(config_log_trap,
3203
		 config_log_trap_cmd,
3204
		 "log trap " LOG_LEVELS,
3205
		 "Logging control\n"
3206
		 "(Deprecated) Set logging level and default for all destinations\n"
3207
		 LOG_LEVEL_DESC)
3208
{
3209
	int new_level;
3210
	int i;
3211
3212
	if ((new_level = level_match(argv[0])) == ZLOG_DISABLED)
3213
		return CMD_ERR_NO_MATCH;
3214
3215
	zlog_default->default_lvl = new_level;
3216
	for (i = 0; i < ZLOG_NUM_DESTS; i++)
3217
		if (zlog_default->maxlvl[i] != ZLOG_DISABLED)
3218
			zlog_default->maxlvl[i] = new_level;
3219
	return CMD_SUCCESS;
3220
}
3221
3222
DEFUN_DEPRECATED(no_config_log_trap,
3223
		 no_config_log_trap_cmd,
3224
		 "no log trap [LEVEL]",
3225
		 NO_STR
3226
		 "Logging control\n"
3227
		 "Permit all logging information\n" "Logging level\n")
3228
{
3229
	zlog_default->default_lvl = LOG_DEBUG;
3230
	return CMD_SUCCESS;
3231
}
3232
3233
DEFUN(config_log_record_priority,
3234
      config_log_record_priority_cmd,
3235
      "log record-priority",
3236
      "Logging control\n"
3237
      "Log the priority of the message within the message\n")
3238
{
3239
	zlog_default->record_priority = 1;
3240
	return CMD_SUCCESS;
3241
}
3242
3243
DEFUN(no_config_log_record_priority,
3244
      no_config_log_record_priority_cmd,
3245
      "no log record-priority",
3246
      NO_STR
3247
      "Logging control\n"
3248
      "Do not log the priority of the message within the message\n")
3249
{
3250
	zlog_default->record_priority = 0;
3251
	return CMD_SUCCESS;
3252
}
3253
#endif
3254
3255
DEFUN(banner_motd_file,
3256
      banner_motd_file_cmd,
3257
      "banner motd file [FILE]",
3258
      "Set banner\n" "Banner for motd\n" "Banner from a file\n" "Filename\n")
3259
{
3260
	if (host.motdfile)
3261
		free(host.motdfile);
3262
	host.motdfile = strdup(argv[0]);
3263
3264
	return CMD_SUCCESS;
3265
}
3266
3267
DEFUN(banner_motd_default,
3268
      banner_motd_default_cmd,
3269
      "banner motd default",
3270
      "Set banner string\n" "Strings for motd\n" "Default string\n")
3271
{
3272
	host.motd = default_motd;
3273
	return CMD_SUCCESS;
3274
}
3275
3276
DEFUN(no_banner_motd,
3277
      no_banner_motd_cmd,
3278
      "no banner motd", NO_STR "Set banner string\n" "Strings for motd\n")
3279
{
3280
	host.motd = NULL;
3281
	if (host.motdfile)
3282
		free(host.motdfile);
3283
	host.motdfile = NULL;
3284
	return CMD_SUCCESS;
3285
}
3286
3287
/* Set config filename.  Called from vty.c */
3288
void host_config_set(char *filename)
3289
{
3290
	host.config = strdup(filename);
3291
}
3292
3293
void install_default(enum node_type node)
3294
{
3295
	install_element(node, &config_exit_cmd);
3296
	install_element(node, &config_quit_cmd);
3297
	install_element(node, &config_end_cmd);
3298
	install_element(node, &config_help_cmd);
3299
	install_element(node, &config_list_cmd);
3300
3301
#if 0
3302
	install_element(node, &config_write_terminal_cmd);
3303
	install_element(node, &config_write_file_cmd);
3304
	install_element(node, &config_write_memory_cmd);
3305
	install_element(node, &config_write_cmd);
3306
	install_element(node, &show_running_config_cmd);
3307
#endif
3308
}
3309
3310
/* Initialize command interface. Install basic nodes and commands. */
3311
void cmd_init(int terminal)
3312
{
3313
	/* Allocate initial top vector of commands. */
3314
	cmdvec = vector_init(VECTOR_MIN_SIZE);
3315
3316
	/* Default host value settings. */
3317
	host.name = NULL;
3318
	//host.password = NULL;
3319
	host.password = "foo";
3320
	host.enable = NULL;
3321
	host.logfile = NULL;
3322
	host.config = NULL;
3323
	host.lines = -1;
3324
	host.motd = default_motd;
3325
	host.motdfile = NULL;
3326
3327
	/* Install top nodes. */
3328
	install_node(&view_node, NULL);
3329
	install_node(&enable_node, NULL);
3330
	install_node(&auth_node, NULL);
3331
	install_node(&auth_enable_node, NULL);
3332
	install_node(&config_node, config_write_host);
3333
3334
	/* Each node's basic commands. */
3335
	install_element(VIEW_NODE, &show_version_cmd);
3336
	if (terminal) {
3337
		install_element(VIEW_NODE, &config_list_cmd);
3338
		install_element(VIEW_NODE, &config_exit_cmd);
3339
		install_element(VIEW_NODE, &config_quit_cmd);
3340
		install_element(VIEW_NODE, &config_help_cmd);
3341
		install_element(VIEW_NODE, &config_enable_cmd);
3342
		install_element(VIEW_NODE, &config_terminal_length_cmd);
3343
		install_element(VIEW_NODE, &config_terminal_no_length_cmd);
3344
		install_element(VIEW_NODE, &echo_cmd);
3345
	}
3346
3347
	if (terminal) {
3348
		install_default(ENABLE_NODE);
3349
		install_element(ENABLE_NODE, &config_disable_cmd);
3350
		install_element(ENABLE_NODE, &config_terminal_cmd);
3351
		//install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
3352
	}
3353
	//install_element (ENABLE_NODE, &show_startup_config_cmd);
3354
	install_element(ENABLE_NODE, &show_version_cmd);
3355
3356
	if (terminal) {
3357
		install_element(ENABLE_NODE, &config_terminal_length_cmd);
3358
		install_element(ENABLE_NODE, &config_terminal_no_length_cmd);
3359
		install_element(ENABLE_NODE, &echo_cmd);
3360
3361
		install_default(CONFIG_NODE);
3362
	}
3363
3364
	install_element(CONFIG_NODE, &hostname_cmd);
3365
	install_element(CONFIG_NODE, &no_hostname_cmd);
3366
3367
	if (terminal) {
3368
		install_element(CONFIG_NODE, &password_cmd);
3369
		install_element(CONFIG_NODE, &password_text_cmd);
3370
		install_element(CONFIG_NODE, &enable_password_cmd);
3371
		install_element(CONFIG_NODE, &enable_password_text_cmd);
3372
		install_element(CONFIG_NODE, &no_enable_password_cmd);
3373
3374
		install_element(CONFIG_NODE, &service_password_encrypt_cmd);
3375
		install_element(CONFIG_NODE, &no_service_password_encrypt_cmd);
3376
		install_element(CONFIG_NODE, &banner_motd_default_cmd);
3377
		install_element(CONFIG_NODE, &banner_motd_file_cmd);
3378
		install_element(CONFIG_NODE, &no_banner_motd_cmd);
3379
		install_element(CONFIG_NODE, &service_terminal_length_cmd);
3380
		install_element(CONFIG_NODE, &no_service_terminal_length_cmd);
3381
3382
	}
3383
	srand(time(NULL));
3384
}
Add picture from clipboard (Maximum size: 48.8 MB)