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