Annotation of embedaddon/quagga/lib/command.c, revision 1.1.1.1
1.1 misho 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 OSPF_NODE:
2404: case OSPF6_NODE:
2405: case ISIS_NODE:
2406: case KEYCHAIN_NODE:
2407: case MASC_NODE:
2408: case RMAP_NODE:
2409: case VTY_NODE:
2410: vty->node = CONFIG_NODE;
2411: break;
2412: case BGP_VPNV4_NODE:
2413: case BGP_IPV4_NODE:
2414: case BGP_IPV4M_NODE:
2415: case BGP_IPV6_NODE:
2416: case BGP_IPV6M_NODE:
2417: vty->node = BGP_NODE;
2418: break;
2419: case KEYCHAIN_KEY_NODE:
2420: vty->node = KEYCHAIN_NODE;
2421: break;
2422: default:
2423: break;
2424: }
2425: return CMD_SUCCESS;
2426: }
2427:
2428: /* quit is alias of exit. */
2429: ALIAS (config_exit,
2430: config_quit_cmd,
2431: "quit",
2432: "Exit current mode and down to previous mode\n")
2433:
2434: /* End of configuration. */
2435: DEFUN (config_end,
2436: config_end_cmd,
2437: "end",
2438: "End current mode and change to enable mode.")
2439: {
2440: switch (vty->node)
2441: {
2442: case VIEW_NODE:
2443: case ENABLE_NODE:
2444: case RESTRICTED_NODE:
2445: /* Nothing to do. */
2446: break;
2447: case CONFIG_NODE:
2448: case INTERFACE_NODE:
2449: case ZEBRA_NODE:
2450: case RIP_NODE:
2451: case RIPNG_NODE:
2452: case BGP_NODE:
2453: case BGP_VPNV4_NODE:
2454: case BGP_IPV4_NODE:
2455: case BGP_IPV4M_NODE:
2456: case BGP_IPV6_NODE:
2457: case BGP_IPV6M_NODE:
2458: case RMAP_NODE:
2459: case OSPF_NODE:
2460: case OSPF6_NODE:
2461: case ISIS_NODE:
2462: case KEYCHAIN_NODE:
2463: case KEYCHAIN_KEY_NODE:
2464: case MASC_NODE:
2465: case VTY_NODE:
2466: vty_config_unlock (vty);
2467: vty->node = ENABLE_NODE;
2468: break;
2469: default:
2470: break;
2471: }
2472: return CMD_SUCCESS;
2473: }
2474:
2475: /* Show version. */
2476: DEFUN (show_version,
2477: show_version_cmd,
2478: "show version",
2479: SHOW_STR
2480: "Displays zebra version\n")
2481: {
2482: vty_out (vty, "Quagga %s (%s).%s", QUAGGA_VERSION, host.name?host.name:"",
2483: VTY_NEWLINE);
2484: vty_out (vty, "%s%s", QUAGGA_COPYRIGHT, VTY_NEWLINE);
2485:
2486: return CMD_SUCCESS;
2487: }
2488:
2489: /* Help display function for all node. */
2490: DEFUN (config_help,
2491: config_help_cmd,
2492: "help",
2493: "Description of the interactive help system\n")
2494: {
2495: vty_out (vty,
2496: "Quagga VTY provides advanced help feature. When you need help,%s\
2497: anytime at the command line please press '?'.%s\
2498: %s\
2499: If nothing matches, the help list will be empty and you must backup%s\
2500: until entering a '?' shows the available options.%s\
2501: Two styles of help are provided:%s\
2502: 1. Full help is available when you are ready to enter a%s\
2503: command argument (e.g. 'show ?') and describes each possible%s\
2504: argument.%s\
2505: 2. Partial help is provided when an abbreviated argument is entered%s\
2506: and you want to know what arguments match the input%s\
2507: (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2508: VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2509: VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
2510: return CMD_SUCCESS;
2511: }
2512:
2513: /* Help display function for all node. */
2514: DEFUN (config_list,
2515: config_list_cmd,
2516: "list",
2517: "Print command list\n")
2518: {
2519: unsigned int i;
2520: struct cmd_node *cnode = vector_slot (cmdvec, vty->node);
2521: struct cmd_element *cmd;
2522:
2523: for (i = 0; i < vector_active (cnode->cmd_vector); i++)
2524: if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL
2525: && !(cmd->attr == CMD_ATTR_DEPRECATED
2526: || cmd->attr == CMD_ATTR_HIDDEN))
2527: vty_out (vty, " %s%s", cmd->string,
2528: VTY_NEWLINE);
2529: return CMD_SUCCESS;
2530: }
2531:
2532: /* Write current configuration into file. */
2533: DEFUN (config_write_file,
2534: config_write_file_cmd,
2535: "write file",
2536: "Write running configuration to memory, network, or terminal\n"
2537: "Write to configuration file\n")
2538: {
2539: unsigned int i;
2540: int fd;
2541: struct cmd_node *node;
2542: char *config_file;
2543: char *config_file_tmp = NULL;
2544: char *config_file_sav = NULL;
2545: int ret = CMD_WARNING;
2546: struct vty *file_vty;
2547:
2548: /* Check and see if we are operating under vtysh configuration */
2549: if (host.config == NULL)
2550: {
2551: vty_out (vty, "Can't save to configuration file, using vtysh.%s",
2552: VTY_NEWLINE);
2553: return CMD_WARNING;
2554: }
2555:
2556: /* Get filename. */
2557: config_file = host.config;
2558:
2559: config_file_sav =
2560: XMALLOC (MTYPE_TMP, strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
2561: strcpy (config_file_sav, config_file);
2562: strcat (config_file_sav, CONF_BACKUP_EXT);
2563:
2564:
2565: config_file_tmp = XMALLOC (MTYPE_TMP, strlen (config_file) + 8);
2566: sprintf (config_file_tmp, "%s.XXXXXX", config_file);
2567:
2568: /* Open file to configuration write. */
2569: fd = mkstemp (config_file_tmp);
2570: if (fd < 0)
2571: {
2572: vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
2573: VTY_NEWLINE);
2574: goto finished;
2575: }
2576:
2577: /* Make vty for configuration file. */
2578: file_vty = vty_new ();
2579: file_vty->fd = fd;
2580: file_vty->type = VTY_FILE;
2581:
2582: /* Config file header print. */
2583: vty_out (file_vty, "!\n! Zebra configuration saved from vty\n! ");
2584: vty_time_print (file_vty, 1);
2585: vty_out (file_vty, "!\n");
2586:
2587: for (i = 0; i < vector_active (cmdvec); i++)
2588: if ((node = vector_slot (cmdvec, i)) && node->func)
2589: {
2590: if ((*node->func) (file_vty))
2591: vty_out (file_vty, "!\n");
2592: }
2593: vty_close (file_vty);
2594:
2595: if (unlink (config_file_sav) != 0)
2596: if (errno != ENOENT)
2597: {
2598: vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
2599: VTY_NEWLINE);
2600: goto finished;
2601: }
2602: if (link (config_file, config_file_sav) != 0)
2603: {
2604: vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
2605: VTY_NEWLINE);
2606: goto finished;
2607: }
2608: sync ();
2609: if (unlink (config_file) != 0)
2610: {
2611: vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
2612: VTY_NEWLINE);
2613: goto finished;
2614: }
2615: if (link (config_file_tmp, config_file) != 0)
2616: {
2617: vty_out (vty, "Can't save configuration file %s.%s", config_file,
2618: VTY_NEWLINE);
2619: goto finished;
2620: }
2621: sync ();
2622:
2623: if (chmod (config_file, CONFIGFILE_MASK) != 0)
2624: {
2625: vty_out (vty, "Can't chmod configuration file %s: %s (%d).%s",
2626: config_file, safe_strerror(errno), errno, VTY_NEWLINE);
2627: goto finished;
2628: }
2629:
2630: vty_out (vty, "Configuration saved to %s%s", config_file,
2631: VTY_NEWLINE);
2632: ret = CMD_SUCCESS;
2633:
2634: finished:
2635: unlink (config_file_tmp);
2636: XFREE (MTYPE_TMP, config_file_tmp);
2637: XFREE (MTYPE_TMP, config_file_sav);
2638: return ret;
2639: }
2640:
2641: ALIAS (config_write_file,
2642: config_write_cmd,
2643: "write",
2644: "Write running configuration to memory, network, or terminal\n")
2645:
2646: ALIAS (config_write_file,
2647: config_write_memory_cmd,
2648: "write memory",
2649: "Write running configuration to memory, network, or terminal\n"
2650: "Write configuration to the file (same as write file)\n")
2651:
2652: ALIAS (config_write_file,
2653: copy_runningconfig_startupconfig_cmd,
2654: "copy running-config startup-config",
2655: "Copy configuration\n"
2656: "Copy running config to... \n"
2657: "Copy running config to startup config (same as write file)\n")
2658:
2659: /* Write current configuration into the terminal. */
2660: DEFUN (config_write_terminal,
2661: config_write_terminal_cmd,
2662: "write terminal",
2663: "Write running configuration to memory, network, or terminal\n"
2664: "Write to terminal\n")
2665: {
2666: unsigned int i;
2667: struct cmd_node *node;
2668:
2669: if (vty->type == VTY_SHELL_SERV)
2670: {
2671: for (i = 0; i < vector_active (cmdvec); i++)
2672: if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
2673: {
2674: if ((*node->func) (vty))
2675: vty_out (vty, "!%s", VTY_NEWLINE);
2676: }
2677: }
2678: else
2679: {
2680: vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
2681: VTY_NEWLINE);
2682: vty_out (vty, "!%s", VTY_NEWLINE);
2683:
2684: for (i = 0; i < vector_active (cmdvec); i++)
2685: if ((node = vector_slot (cmdvec, i)) && node->func)
2686: {
2687: if ((*node->func) (vty))
2688: vty_out (vty, "!%s", VTY_NEWLINE);
2689: }
2690: vty_out (vty, "end%s",VTY_NEWLINE);
2691: }
2692: return CMD_SUCCESS;
2693: }
2694:
2695: /* Write current configuration into the terminal. */
2696: ALIAS (config_write_terminal,
2697: show_running_config_cmd,
2698: "show running-config",
2699: SHOW_STR
2700: "running configuration\n")
2701:
2702: /* Write startup configuration into the terminal. */
2703: DEFUN (show_startup_config,
2704: show_startup_config_cmd,
2705: "show startup-config",
2706: SHOW_STR
2707: "Contentes of startup configuration\n")
2708: {
2709: char buf[BUFSIZ];
2710: FILE *confp;
2711:
2712: confp = fopen (host.config, "r");
2713: if (confp == NULL)
2714: {
2715: vty_out (vty, "Can't open configuration file [%s]%s",
2716: host.config, VTY_NEWLINE);
2717: return CMD_WARNING;
2718: }
2719:
2720: while (fgets (buf, BUFSIZ, confp))
2721: {
2722: char *cp = buf;
2723:
2724: while (*cp != '\r' && *cp != '\n' && *cp != '\0')
2725: cp++;
2726: *cp = '\0';
2727:
2728: vty_out (vty, "%s%s", buf, VTY_NEWLINE);
2729: }
2730:
2731: fclose (confp);
2732:
2733: return CMD_SUCCESS;
2734: }
2735:
2736: /* Hostname configuration */
2737: DEFUN (config_hostname,
2738: hostname_cmd,
2739: "hostname WORD",
2740: "Set system's network name\n"
2741: "This system's network name\n")
2742: {
2743: if (!isalpha((int) *argv[0]))
2744: {
2745: vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
2746: return CMD_WARNING;
2747: }
2748:
2749: if (host.name)
2750: XFREE (MTYPE_HOST, host.name);
2751:
2752: host.name = XSTRDUP (MTYPE_HOST, argv[0]);
2753: return CMD_SUCCESS;
2754: }
2755:
2756: DEFUN (config_no_hostname,
2757: no_hostname_cmd,
2758: "no hostname [HOSTNAME]",
2759: NO_STR
2760: "Reset system's network name\n"
2761: "Host name of this router\n")
2762: {
2763: if (host.name)
2764: XFREE (MTYPE_HOST, host.name);
2765: host.name = NULL;
2766: return CMD_SUCCESS;
2767: }
2768:
2769: /* VTY interface password set. */
2770: DEFUN (config_password, password_cmd,
2771: "password (8|) WORD",
2772: "Assign the terminal connection password\n"
2773: "Specifies a HIDDEN password will follow\n"
2774: "dummy string \n"
2775: "The HIDDEN line password string\n")
2776: {
2777: /* Argument check. */
2778: if (argc == 0)
2779: {
2780: vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2781: return CMD_WARNING;
2782: }
2783:
2784: if (argc == 2)
2785: {
2786: if (*argv[0] == '8')
2787: {
2788: if (host.password)
2789: XFREE (MTYPE_HOST, host.password);
2790: host.password = NULL;
2791: if (host.password_encrypt)
2792: XFREE (MTYPE_HOST, host.password_encrypt);
2793: host.password_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
2794: return CMD_SUCCESS;
2795: }
2796: else
2797: {
2798: vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2799: return CMD_WARNING;
2800: }
2801: }
2802:
2803: if (!isalnum ((int) *argv[0]))
2804: {
2805: vty_out (vty,
2806: "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2807: return CMD_WARNING;
2808: }
2809:
2810: if (host.password)
2811: XFREE (MTYPE_HOST, host.password);
2812: host.password = NULL;
2813:
2814: if (host.encrypt)
2815: {
2816: if (host.password_encrypt)
2817: XFREE (MTYPE_HOST, host.password_encrypt);
2818: host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
2819: }
2820: else
2821: host.password = XSTRDUP (MTYPE_HOST, argv[0]);
2822:
2823: return CMD_SUCCESS;
2824: }
2825:
2826: ALIAS (config_password, password_text_cmd,
2827: "password LINE",
2828: "Assign the terminal connection password\n"
2829: "The UNENCRYPTED (cleartext) line password\n")
2830:
2831: /* VTY enable password set. */
2832: DEFUN (config_enable_password, enable_password_cmd,
2833: "enable password (8|) WORD",
2834: "Modify enable password parameters\n"
2835: "Assign the privileged level password\n"
2836: "Specifies a HIDDEN password will follow\n"
2837: "dummy string \n"
2838: "The HIDDEN 'enable' password string\n")
2839: {
2840: /* Argument check. */
2841: if (argc == 0)
2842: {
2843: vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2844: return CMD_WARNING;
2845: }
2846:
2847: /* Crypt type is specified. */
2848: if (argc == 2)
2849: {
2850: if (*argv[0] == '8')
2851: {
2852: if (host.enable)
2853: XFREE (MTYPE_HOST, host.enable);
2854: host.enable = NULL;
2855:
2856: if (host.enable_encrypt)
2857: XFREE (MTYPE_HOST, host.enable_encrypt);
2858: host.enable_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
2859:
2860: return CMD_SUCCESS;
2861: }
2862: else
2863: {
2864: vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2865: return CMD_WARNING;
2866: }
2867: }
2868:
2869: if (!isalnum ((int) *argv[0]))
2870: {
2871: vty_out (vty,
2872: "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2873: return CMD_WARNING;
2874: }
2875:
2876: if (host.enable)
2877: XFREE (MTYPE_HOST, host.enable);
2878: host.enable = NULL;
2879:
2880: /* Plain password input. */
2881: if (host.encrypt)
2882: {
2883: if (host.enable_encrypt)
2884: XFREE (MTYPE_HOST, host.enable_encrypt);
2885: host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
2886: }
2887: else
2888: host.enable = XSTRDUP (MTYPE_HOST, argv[0]);
2889:
2890: return CMD_SUCCESS;
2891: }
2892:
2893: ALIAS (config_enable_password,
2894: enable_password_text_cmd,
2895: "enable password LINE",
2896: "Modify enable password parameters\n"
2897: "Assign the privileged level password\n"
2898: "The UNENCRYPTED (cleartext) 'enable' password\n")
2899:
2900: /* VTY enable password delete. */
2901: DEFUN (no_config_enable_password, no_enable_password_cmd,
2902: "no enable password",
2903: NO_STR
2904: "Modify enable password parameters\n"
2905: "Assign the privileged level password\n")
2906: {
2907: if (host.enable)
2908: XFREE (MTYPE_HOST, host.enable);
2909: host.enable = NULL;
2910:
2911: if (host.enable_encrypt)
2912: XFREE (MTYPE_HOST, host.enable_encrypt);
2913: host.enable_encrypt = NULL;
2914:
2915: return CMD_SUCCESS;
2916: }
2917:
2918: DEFUN (service_password_encrypt,
2919: service_password_encrypt_cmd,
2920: "service password-encryption",
2921: "Set up miscellaneous service\n"
2922: "Enable encrypted passwords\n")
2923: {
2924: if (host.encrypt)
2925: return CMD_SUCCESS;
2926:
2927: host.encrypt = 1;
2928:
2929: if (host.password)
2930: {
2931: if (host.password_encrypt)
2932: XFREE (MTYPE_HOST, host.password_encrypt);
2933: host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.password));
2934: }
2935: if (host.enable)
2936: {
2937: if (host.enable_encrypt)
2938: XFREE (MTYPE_HOST, host.enable_encrypt);
2939: host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.enable));
2940: }
2941:
2942: return CMD_SUCCESS;
2943: }
2944:
2945: DEFUN (no_service_password_encrypt,
2946: no_service_password_encrypt_cmd,
2947: "no service password-encryption",
2948: NO_STR
2949: "Set up miscellaneous service\n"
2950: "Enable encrypted passwords\n")
2951: {
2952: if (! host.encrypt)
2953: return CMD_SUCCESS;
2954:
2955: host.encrypt = 0;
2956:
2957: if (host.password_encrypt)
2958: XFREE (MTYPE_HOST, host.password_encrypt);
2959: host.password_encrypt = NULL;
2960:
2961: if (host.enable_encrypt)
2962: XFREE (MTYPE_HOST, host.enable_encrypt);
2963: host.enable_encrypt = NULL;
2964:
2965: return CMD_SUCCESS;
2966: }
2967:
2968: DEFUN (config_terminal_length, config_terminal_length_cmd,
2969: "terminal length <0-512>",
2970: "Set terminal line parameters\n"
2971: "Set number of lines on a screen\n"
2972: "Number of lines on screen (0 for no pausing)\n")
2973: {
2974: int lines;
2975: char *endptr = NULL;
2976:
2977: lines = strtol (argv[0], &endptr, 10);
2978: if (lines < 0 || lines > 512 || *endptr != '\0')
2979: {
2980: vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2981: return CMD_WARNING;
2982: }
2983: vty->lines = lines;
2984:
2985: return CMD_SUCCESS;
2986: }
2987:
2988: DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
2989: "terminal no length",
2990: "Set terminal line parameters\n"
2991: NO_STR
2992: "Set number of lines on a screen\n")
2993: {
2994: vty->lines = -1;
2995: return CMD_SUCCESS;
2996: }
2997:
2998: DEFUN (service_terminal_length, service_terminal_length_cmd,
2999: "service terminal-length <0-512>",
3000: "Set up miscellaneous service\n"
3001: "System wide terminal length configuration\n"
3002: "Number of lines of VTY (0 means no line control)\n")
3003: {
3004: int lines;
3005: char *endptr = NULL;
3006:
3007: lines = strtol (argv[0], &endptr, 10);
3008: if (lines < 0 || lines > 512 || *endptr != '\0')
3009: {
3010: vty_out (vty, "length is malformed%s", VTY_NEWLINE);
3011: return CMD_WARNING;
3012: }
3013: host.lines = lines;
3014:
3015: return CMD_SUCCESS;
3016: }
3017:
3018: DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
3019: "no service terminal-length [<0-512>]",
3020: NO_STR
3021: "Set up miscellaneous service\n"
3022: "System wide terminal length configuration\n"
3023: "Number of lines of VTY (0 means no line control)\n")
3024: {
3025: host.lines = -1;
3026: return CMD_SUCCESS;
3027: }
3028:
3029: DEFUN_HIDDEN (do_echo,
3030: echo_cmd,
3031: "echo .MESSAGE",
3032: "Echo a message back to the vty\n"
3033: "The message to echo\n")
3034: {
3035: char *message;
3036:
3037: vty_out (vty, "%s%s", ((message = argv_concat(argv, argc, 0)) ? message : ""),
3038: VTY_NEWLINE);
3039: if (message)
3040: XFREE(MTYPE_TMP, message);
3041: return CMD_SUCCESS;
3042: }
3043:
3044: DEFUN (config_logmsg,
3045: config_logmsg_cmd,
3046: "logmsg "LOG_LEVELS" .MESSAGE",
3047: "Send a message to enabled logging destinations\n"
3048: LOG_LEVEL_DESC
3049: "The message to send\n")
3050: {
3051: int level;
3052: char *message;
3053:
3054: if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3055: return CMD_ERR_NO_MATCH;
3056:
3057: zlog(NULL, level, "%s", ((message = argv_concat(argv, argc, 1)) ? message : ""));
3058: if (message)
3059: XFREE(MTYPE_TMP, message);
3060: return CMD_SUCCESS;
3061: }
3062:
3063: DEFUN (show_logging,
3064: show_logging_cmd,
3065: "show logging",
3066: SHOW_STR
3067: "Show current logging configuration\n")
3068: {
3069: struct zlog *zl = zlog_default;
3070:
3071: vty_out (vty, "Syslog logging: ");
3072: if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED)
3073: vty_out (vty, "disabled");
3074: else
3075: vty_out (vty, "level %s, facility %s, ident %s",
3076: zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]],
3077: facility_name(zl->facility), zl->ident);
3078: vty_out (vty, "%s", VTY_NEWLINE);
3079:
3080: vty_out (vty, "Stdout logging: ");
3081: if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED)
3082: vty_out (vty, "disabled");
3083: else
3084: vty_out (vty, "level %s",
3085: zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
3086: vty_out (vty, "%s", VTY_NEWLINE);
3087:
3088: vty_out (vty, "Monitor logging: ");
3089: if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
3090: vty_out (vty, "disabled");
3091: else
3092: vty_out (vty, "level %s",
3093: zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
3094: vty_out (vty, "%s", VTY_NEWLINE);
3095:
3096: vty_out (vty, "File logging: ");
3097: if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) ||
3098: !zl->fp)
3099: vty_out (vty, "disabled");
3100: else
3101: vty_out (vty, "level %s, filename %s",
3102: zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
3103: zl->filename);
3104: vty_out (vty, "%s", VTY_NEWLINE);
3105:
3106: vty_out (vty, "Protocol name: %s%s",
3107: zlog_proto_names[zl->protocol], VTY_NEWLINE);
3108: vty_out (vty, "Record priority: %s%s",
3109: (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE);
3110: vty_out (vty, "Timestamp precision: %d%s",
3111: zl->timestamp_precision, VTY_NEWLINE);
3112:
3113: return CMD_SUCCESS;
3114: }
3115:
3116: DEFUN (config_log_stdout,
3117: config_log_stdout_cmd,
3118: "log stdout",
3119: "Logging control\n"
3120: "Set stdout logging level\n")
3121: {
3122: zlog_set_level (NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl);
3123: return CMD_SUCCESS;
3124: }
3125:
3126: DEFUN (config_log_stdout_level,
3127: config_log_stdout_level_cmd,
3128: "log stdout "LOG_LEVELS,
3129: "Logging control\n"
3130: "Set stdout logging level\n"
3131: LOG_LEVEL_DESC)
3132: {
3133: int level;
3134:
3135: if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3136: return CMD_ERR_NO_MATCH;
3137: zlog_set_level (NULL, ZLOG_DEST_STDOUT, level);
3138: return CMD_SUCCESS;
3139: }
3140:
3141: DEFUN (no_config_log_stdout,
3142: no_config_log_stdout_cmd,
3143: "no log stdout [LEVEL]",
3144: NO_STR
3145: "Logging control\n"
3146: "Cancel logging to stdout\n"
3147: "Logging level\n")
3148: {
3149: zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED);
3150: return CMD_SUCCESS;
3151: }
3152:
3153: DEFUN (config_log_monitor,
3154: config_log_monitor_cmd,
3155: "log monitor",
3156: "Logging control\n"
3157: "Set terminal line (monitor) logging level\n")
3158: {
3159: zlog_set_level (NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl);
3160: return CMD_SUCCESS;
3161: }
3162:
3163: DEFUN (config_log_monitor_level,
3164: config_log_monitor_level_cmd,
3165: "log monitor "LOG_LEVELS,
3166: "Logging control\n"
3167: "Set terminal line (monitor) logging level\n"
3168: LOG_LEVEL_DESC)
3169: {
3170: int level;
3171:
3172: if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3173: return CMD_ERR_NO_MATCH;
3174: zlog_set_level (NULL, ZLOG_DEST_MONITOR, level);
3175: return CMD_SUCCESS;
3176: }
3177:
3178: DEFUN (no_config_log_monitor,
3179: no_config_log_monitor_cmd,
3180: "no log monitor [LEVEL]",
3181: NO_STR
3182: "Logging control\n"
3183: "Disable terminal line (monitor) logging\n"
3184: "Logging level\n")
3185: {
3186: zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
3187: return CMD_SUCCESS;
3188: }
3189:
3190: static int
3191: set_log_file(struct vty *vty, const char *fname, int loglevel)
3192: {
3193: int ret;
3194: char *p = NULL;
3195: const char *fullpath;
3196:
3197: /* Path detection. */
3198: if (! IS_DIRECTORY_SEP (*fname))
3199: {
3200: char cwd[MAXPATHLEN+1];
3201: cwd[MAXPATHLEN] = '\0';
3202:
3203: if (getcwd (cwd, MAXPATHLEN) == NULL)
3204: {
3205: zlog_err ("config_log_file: Unable to alloc mem!");
3206: return CMD_WARNING;
3207: }
3208:
3209: if ( (p = XMALLOC (MTYPE_TMP, strlen (cwd) + strlen (fname) + 2))
3210: == NULL)
3211: {
3212: zlog_err ("config_log_file: Unable to alloc mem!");
3213: return CMD_WARNING;
3214: }
3215: sprintf (p, "%s/%s", cwd, fname);
3216: fullpath = p;
3217: }
3218: else
3219: fullpath = fname;
3220:
3221: ret = zlog_set_file (NULL, fullpath, loglevel);
3222:
3223: if (p)
3224: XFREE (MTYPE_TMP, p);
3225:
3226: if (!ret)
3227: {
3228: vty_out (vty, "can't open logfile %s\n", fname);
3229: return CMD_WARNING;
3230: }
3231:
3232: if (host.logfile)
3233: XFREE (MTYPE_HOST, host.logfile);
3234:
3235: host.logfile = XSTRDUP (MTYPE_HOST, fname);
3236:
3237: return CMD_SUCCESS;
3238: }
3239:
3240: DEFUN (config_log_file,
3241: config_log_file_cmd,
3242: "log file FILENAME",
3243: "Logging control\n"
3244: "Logging to file\n"
3245: "Logging filename\n")
3246: {
3247: return set_log_file(vty, argv[0], zlog_default->default_lvl);
3248: }
3249:
3250: DEFUN (config_log_file_level,
3251: config_log_file_level_cmd,
3252: "log file FILENAME "LOG_LEVELS,
3253: "Logging control\n"
3254: "Logging to file\n"
3255: "Logging filename\n"
3256: LOG_LEVEL_DESC)
3257: {
3258: int level;
3259:
3260: if ((level = level_match(argv[1])) == ZLOG_DISABLED)
3261: return CMD_ERR_NO_MATCH;
3262: return set_log_file(vty, argv[0], level);
3263: }
3264:
3265: DEFUN (no_config_log_file,
3266: no_config_log_file_cmd,
3267: "no log file [FILENAME]",
3268: NO_STR
3269: "Logging control\n"
3270: "Cancel logging to file\n"
3271: "Logging file name\n")
3272: {
3273: zlog_reset_file (NULL);
3274:
3275: if (host.logfile)
3276: XFREE (MTYPE_HOST, host.logfile);
3277:
3278: host.logfile = NULL;
3279:
3280: return CMD_SUCCESS;
3281: }
3282:
3283: ALIAS (no_config_log_file,
3284: no_config_log_file_level_cmd,
3285: "no log file FILENAME LEVEL",
3286: NO_STR
3287: "Logging control\n"
3288: "Cancel logging to file\n"
3289: "Logging file name\n"
3290: "Logging level\n")
3291:
3292: DEFUN (config_log_syslog,
3293: config_log_syslog_cmd,
3294: "log syslog",
3295: "Logging control\n"
3296: "Set syslog logging level\n")
3297: {
3298: zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
3299: return CMD_SUCCESS;
3300: }
3301:
3302: DEFUN (config_log_syslog_level,
3303: config_log_syslog_level_cmd,
3304: "log syslog "LOG_LEVELS,
3305: "Logging control\n"
3306: "Set syslog logging level\n"
3307: LOG_LEVEL_DESC)
3308: {
3309: int level;
3310:
3311: if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3312: return CMD_ERR_NO_MATCH;
3313: zlog_set_level (NULL, ZLOG_DEST_SYSLOG, level);
3314: return CMD_SUCCESS;
3315: }
3316:
3317: DEFUN_DEPRECATED (config_log_syslog_facility,
3318: config_log_syslog_facility_cmd,
3319: "log syslog facility "LOG_FACILITIES,
3320: "Logging control\n"
3321: "Logging goes to syslog\n"
3322: "(Deprecated) Facility parameter for syslog messages\n"
3323: LOG_FACILITY_DESC)
3324: {
3325: int facility;
3326:
3327: if ((facility = facility_match(argv[0])) < 0)
3328: return CMD_ERR_NO_MATCH;
3329:
3330: zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
3331: zlog_default->facility = facility;
3332: return CMD_SUCCESS;
3333: }
3334:
3335: DEFUN (no_config_log_syslog,
3336: no_config_log_syslog_cmd,
3337: "no log syslog [LEVEL]",
3338: NO_STR
3339: "Logging control\n"
3340: "Cancel logging to syslog\n"
3341: "Logging level\n")
3342: {
3343: zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
3344: return CMD_SUCCESS;
3345: }
3346:
3347: ALIAS (no_config_log_syslog,
3348: no_config_log_syslog_facility_cmd,
3349: "no log syslog facility "LOG_FACILITIES,
3350: NO_STR
3351: "Logging control\n"
3352: "Logging goes to syslog\n"
3353: "Facility parameter for syslog messages\n"
3354: LOG_FACILITY_DESC)
3355:
3356: DEFUN (config_log_facility,
3357: config_log_facility_cmd,
3358: "log facility "LOG_FACILITIES,
3359: "Logging control\n"
3360: "Facility parameter for syslog messages\n"
3361: LOG_FACILITY_DESC)
3362: {
3363: int facility;
3364:
3365: if ((facility = facility_match(argv[0])) < 0)
3366: return CMD_ERR_NO_MATCH;
3367: zlog_default->facility = facility;
3368: return CMD_SUCCESS;
3369: }
3370:
3371: DEFUN (no_config_log_facility,
3372: no_config_log_facility_cmd,
3373: "no log facility [FACILITY]",
3374: NO_STR
3375: "Logging control\n"
3376: "Reset syslog facility to default (daemon)\n"
3377: "Syslog facility\n")
3378: {
3379: zlog_default->facility = LOG_DAEMON;
3380: return CMD_SUCCESS;
3381: }
3382:
3383: DEFUN_DEPRECATED (config_log_trap,
3384: config_log_trap_cmd,
3385: "log trap "LOG_LEVELS,
3386: "Logging control\n"
3387: "(Deprecated) Set logging level and default for all destinations\n"
3388: LOG_LEVEL_DESC)
3389: {
3390: int new_level ;
3391: int i;
3392:
3393: if ((new_level = level_match(argv[0])) == ZLOG_DISABLED)
3394: return CMD_ERR_NO_MATCH;
3395:
3396: zlog_default->default_lvl = new_level;
3397: for (i = 0; i < ZLOG_NUM_DESTS; i++)
3398: if (zlog_default->maxlvl[i] != ZLOG_DISABLED)
3399: zlog_default->maxlvl[i] = new_level;
3400: return CMD_SUCCESS;
3401: }
3402:
3403: DEFUN_DEPRECATED (no_config_log_trap,
3404: no_config_log_trap_cmd,
3405: "no log trap [LEVEL]",
3406: NO_STR
3407: "Logging control\n"
3408: "Permit all logging information\n"
3409: "Logging level\n")
3410: {
3411: zlog_default->default_lvl = LOG_DEBUG;
3412: return CMD_SUCCESS;
3413: }
3414:
3415: DEFUN (config_log_record_priority,
3416: config_log_record_priority_cmd,
3417: "log record-priority",
3418: "Logging control\n"
3419: "Log the priority of the message within the message\n")
3420: {
3421: zlog_default->record_priority = 1 ;
3422: return CMD_SUCCESS;
3423: }
3424:
3425: DEFUN (no_config_log_record_priority,
3426: no_config_log_record_priority_cmd,
3427: "no log record-priority",
3428: NO_STR
3429: "Logging control\n"
3430: "Do not log the priority of the message within the message\n")
3431: {
3432: zlog_default->record_priority = 0 ;
3433: return CMD_SUCCESS;
3434: }
3435:
3436: DEFUN (config_log_timestamp_precision,
3437: config_log_timestamp_precision_cmd,
3438: "log timestamp precision <0-6>",
3439: "Logging control\n"
3440: "Timestamp configuration\n"
3441: "Set the timestamp precision\n"
3442: "Number of subsecond digits\n")
3443: {
3444: if (argc != 1)
3445: {
3446: vty_out (vty, "Insufficient arguments%s", VTY_NEWLINE);
3447: return CMD_WARNING;
3448: }
3449:
3450: VTY_GET_INTEGER_RANGE("Timestamp Precision",
3451: zlog_default->timestamp_precision, argv[0], 0, 6);
3452: return CMD_SUCCESS;
3453: }
3454:
3455: DEFUN (no_config_log_timestamp_precision,
3456: no_config_log_timestamp_precision_cmd,
3457: "no log timestamp precision",
3458: NO_STR
3459: "Logging control\n"
3460: "Timestamp configuration\n"
3461: "Reset the timestamp precision to the default value of 0\n")
3462: {
3463: zlog_default->timestamp_precision = 0 ;
3464: return CMD_SUCCESS;
3465: }
3466:
3467: DEFUN (banner_motd_file,
3468: banner_motd_file_cmd,
3469: "banner motd file [FILE]",
3470: "Set banner\n"
3471: "Banner for motd\n"
3472: "Banner from a file\n"
3473: "Filename\n")
3474: {
3475: if (host.motdfile)
3476: XFREE (MTYPE_HOST, host.motdfile);
3477: host.motdfile = XSTRDUP (MTYPE_HOST, argv[0]);
3478:
3479: return CMD_SUCCESS;
3480: }
3481:
3482: DEFUN (banner_motd_default,
3483: banner_motd_default_cmd,
3484: "banner motd default",
3485: "Set banner string\n"
3486: "Strings for motd\n"
3487: "Default string\n")
3488: {
3489: host.motd = default_motd;
3490: return CMD_SUCCESS;
3491: }
3492:
3493: DEFUN (no_banner_motd,
3494: no_banner_motd_cmd,
3495: "no banner motd",
3496: NO_STR
3497: "Set banner string\n"
3498: "Strings for motd\n")
3499: {
3500: host.motd = NULL;
3501: if (host.motdfile)
3502: XFREE (MTYPE_HOST, host.motdfile);
3503: host.motdfile = NULL;
3504: return CMD_SUCCESS;
3505: }
3506:
3507: /* Set config filename. Called from vty.c */
3508: void
3509: host_config_set (char *filename)
3510: {
3511: if (host.config)
3512: XFREE (MTYPE_HOST, host.config);
3513: host.config = XSTRDUP (MTYPE_HOST, filename);
3514: }
3515:
3516: void
3517: install_default (enum node_type node)
3518: {
3519: install_element (node, &config_exit_cmd);
3520: install_element (node, &config_quit_cmd);
3521: install_element (node, &config_end_cmd);
3522: install_element (node, &config_help_cmd);
3523: install_element (node, &config_list_cmd);
3524:
3525: install_element (node, &config_write_terminal_cmd);
3526: install_element (node, &config_write_file_cmd);
3527: install_element (node, &config_write_memory_cmd);
3528: install_element (node, &config_write_cmd);
3529: install_element (node, &show_running_config_cmd);
3530: }
3531:
3532: /* Initialize command interface. Install basic nodes and commands. */
3533: void
3534: cmd_init (int terminal)
3535: {
3536: command_cr = XSTRDUP(MTYPE_STRVEC, "<cr>");
3537: desc_cr.cmd = command_cr;
3538: desc_cr.str = XSTRDUP(MTYPE_STRVEC, "");
3539:
3540: /* Allocate initial top vector of commands. */
3541: cmdvec = vector_init (VECTOR_MIN_SIZE);
3542:
3543: /* Default host value settings. */
3544: host.name = NULL;
3545: host.password = NULL;
3546: host.enable = NULL;
3547: host.logfile = NULL;
3548: host.config = NULL;
3549: host.lines = -1;
3550: host.motd = default_motd;
3551: host.motdfile = NULL;
3552:
3553: /* Install top nodes. */
3554: install_node (&view_node, NULL);
3555: install_node (&enable_node, NULL);
3556: install_node (&auth_node, NULL);
3557: install_node (&auth_enable_node, NULL);
3558: install_node (&restricted_node, NULL);
3559: install_node (&config_node, config_write_host);
3560:
3561: /* Each node's basic commands. */
3562: install_element (VIEW_NODE, &show_version_cmd);
3563: if (terminal)
3564: {
3565: install_element (VIEW_NODE, &config_list_cmd);
3566: install_element (VIEW_NODE, &config_exit_cmd);
3567: install_element (VIEW_NODE, &config_quit_cmd);
3568: install_element (VIEW_NODE, &config_help_cmd);
3569: install_element (VIEW_NODE, &config_enable_cmd);
3570: install_element (VIEW_NODE, &config_terminal_length_cmd);
3571: install_element (VIEW_NODE, &config_terminal_no_length_cmd);
3572: install_element (VIEW_NODE, &show_logging_cmd);
3573: install_element (VIEW_NODE, &echo_cmd);
3574:
3575: install_element (RESTRICTED_NODE, &config_list_cmd);
3576: install_element (RESTRICTED_NODE, &config_exit_cmd);
3577: install_element (RESTRICTED_NODE, &config_quit_cmd);
3578: install_element (RESTRICTED_NODE, &config_help_cmd);
3579: install_element (RESTRICTED_NODE, &config_enable_cmd);
3580: install_element (RESTRICTED_NODE, &config_terminal_length_cmd);
3581: install_element (RESTRICTED_NODE, &config_terminal_no_length_cmd);
3582: install_element (RESTRICTED_NODE, &echo_cmd);
3583: }
3584:
3585: if (terminal)
3586: {
3587: install_default (ENABLE_NODE);
3588: install_element (ENABLE_NODE, &config_disable_cmd);
3589: install_element (ENABLE_NODE, &config_terminal_cmd);
3590: install_element (ENABLE_NODE, ©_runningconfig_startupconfig_cmd);
3591: }
3592: install_element (ENABLE_NODE, &show_startup_config_cmd);
3593: install_element (ENABLE_NODE, &show_version_cmd);
3594:
3595: if (terminal)
3596: {
3597: install_element (ENABLE_NODE, &config_terminal_length_cmd);
3598: install_element (ENABLE_NODE, &config_terminal_no_length_cmd);
3599: install_element (ENABLE_NODE, &show_logging_cmd);
3600: install_element (ENABLE_NODE, &echo_cmd);
3601: install_element (ENABLE_NODE, &config_logmsg_cmd);
3602:
3603: install_default (CONFIG_NODE);
3604: }
3605:
3606: install_element (CONFIG_NODE, &hostname_cmd);
3607: install_element (CONFIG_NODE, &no_hostname_cmd);
3608:
3609: if (terminal)
3610: {
3611: install_element (CONFIG_NODE, &password_cmd);
3612: install_element (CONFIG_NODE, &password_text_cmd);
3613: install_element (CONFIG_NODE, &enable_password_cmd);
3614: install_element (CONFIG_NODE, &enable_password_text_cmd);
3615: install_element (CONFIG_NODE, &no_enable_password_cmd);
3616:
3617: install_element (CONFIG_NODE, &config_log_stdout_cmd);
3618: install_element (CONFIG_NODE, &config_log_stdout_level_cmd);
3619: install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
3620: install_element (CONFIG_NODE, &config_log_monitor_cmd);
3621: install_element (CONFIG_NODE, &config_log_monitor_level_cmd);
3622: install_element (CONFIG_NODE, &no_config_log_monitor_cmd);
3623: install_element (CONFIG_NODE, &config_log_file_cmd);
3624: install_element (CONFIG_NODE, &config_log_file_level_cmd);
3625: install_element (CONFIG_NODE, &no_config_log_file_cmd);
3626: install_element (CONFIG_NODE, &no_config_log_file_level_cmd);
3627: install_element (CONFIG_NODE, &config_log_syslog_cmd);
3628: install_element (CONFIG_NODE, &config_log_syslog_level_cmd);
3629: install_element (CONFIG_NODE, &config_log_syslog_facility_cmd);
3630: install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
3631: install_element (CONFIG_NODE, &no_config_log_syslog_facility_cmd);
3632: install_element (CONFIG_NODE, &config_log_facility_cmd);
3633: install_element (CONFIG_NODE, &no_config_log_facility_cmd);
3634: install_element (CONFIG_NODE, &config_log_trap_cmd);
3635: install_element (CONFIG_NODE, &no_config_log_trap_cmd);
3636: install_element (CONFIG_NODE, &config_log_record_priority_cmd);
3637: install_element (CONFIG_NODE, &no_config_log_record_priority_cmd);
3638: install_element (CONFIG_NODE, &config_log_timestamp_precision_cmd);
3639: install_element (CONFIG_NODE, &no_config_log_timestamp_precision_cmd);
3640: install_element (CONFIG_NODE, &service_password_encrypt_cmd);
3641: install_element (CONFIG_NODE, &no_service_password_encrypt_cmd);
3642: install_element (CONFIG_NODE, &banner_motd_default_cmd);
3643: install_element (CONFIG_NODE, &banner_motd_file_cmd);
3644: install_element (CONFIG_NODE, &no_banner_motd_cmd);
3645: install_element (CONFIG_NODE, &service_terminal_length_cmd);
3646: install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
3647:
3648: install_element (VIEW_NODE, &show_thread_cpu_cmd);
3649: install_element (ENABLE_NODE, &show_thread_cpu_cmd);
3650: install_element (RESTRICTED_NODE, &show_thread_cpu_cmd);
3651:
3652: install_element (ENABLE_NODE, &clear_thread_cpu_cmd);
3653: install_element (VIEW_NODE, &show_work_queues_cmd);
3654: install_element (ENABLE_NODE, &show_work_queues_cmd);
3655: }
3656: srand(time(NULL));
3657: }
3658:
3659: void
3660: cmd_terminate ()
3661: {
3662: unsigned int i, j, k, l;
3663: struct cmd_node *cmd_node;
3664: struct cmd_element *cmd_element;
3665: struct desc *desc;
3666: vector cmd_node_v, cmd_element_v, desc_v;
3667:
3668: if (cmdvec)
3669: {
3670: for (i = 0; i < vector_active (cmdvec); i++)
3671: if ((cmd_node = vector_slot (cmdvec, i)) != NULL)
3672: {
3673: cmd_node_v = cmd_node->cmd_vector;
3674:
3675: for (j = 0; j < vector_active (cmd_node_v); j++)
3676: if ((cmd_element = vector_slot (cmd_node_v, j)) != NULL &&
3677: cmd_element->strvec != NULL)
3678: {
3679: cmd_element_v = cmd_element->strvec;
3680:
3681: for (k = 0; k < vector_active (cmd_element_v); k++)
3682: if ((desc_v = vector_slot (cmd_element_v, k)) != NULL)
3683: {
3684: for (l = 0; l < vector_active (desc_v); l++)
3685: if ((desc = vector_slot (desc_v, l)) != NULL)
3686: {
3687: if (desc->cmd)
3688: XFREE (MTYPE_STRVEC, desc->cmd);
3689: if (desc->str)
3690: XFREE (MTYPE_STRVEC, desc->str);
3691:
3692: XFREE (MTYPE_DESC, desc);
3693: }
3694: vector_free (desc_v);
3695: }
3696:
3697: cmd_element->strvec = NULL;
3698: vector_free (cmd_element_v);
3699: }
3700:
3701: vector_free (cmd_node_v);
3702: }
3703:
3704: vector_free (cmdvec);
3705: cmdvec = NULL;
3706: }
3707:
3708: if (command_cr)
3709: XFREE(MTYPE_STRVEC, command_cr);
3710: if (desc_cr.str)
3711: XFREE(MTYPE_STRVEC, desc_cr.str);
3712: if (host.name)
3713: XFREE (MTYPE_HOST, host.name);
3714: if (host.password)
3715: XFREE (MTYPE_HOST, host.password);
3716: if (host.password_encrypt)
3717: XFREE (MTYPE_HOST, host.password_encrypt);
3718: if (host.enable)
3719: XFREE (MTYPE_HOST, host.enable);
3720: if (host.enable_encrypt)
3721: XFREE (MTYPE_HOST, host.enable_encrypt);
3722: if (host.logfile)
3723: XFREE (MTYPE_HOST, host.logfile);
3724: if (host.motdfile)
3725: XFREE (MTYPE_HOST, host.motdfile);
3726: if (host.config)
3727: XFREE (MTYPE_HOST, host.config);
3728: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>