Annotation of embedaddon/quagga/lib/command.c, revision 1.1.1.3
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\
1.1.1.3 ! misho 87: " GIT_INFO "\r\n";
1.1 misho 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:
1.1.1.3 ! misho 871: return no_match;
1.1 misho 872: }
873:
874: static enum match_type
875: cmd_ipv6_prefix_match (const char *str)
876: {
877: int state = STATE_START;
878: int colons = 0, nums = 0, double_colon = 0;
879: int mask;
880: const char *sp = NULL;
881: char *endptr = NULL;
882:
883: if (str == NULL)
884: return partly_match;
885:
886: if (strspn (str, IPV6_PREFIX_STR) != strlen (str))
887: return no_match;
888:
889: while (*str != '\0' && state != STATE_MASK)
890: {
891: switch (state)
892: {
893: case STATE_START:
894: if (*str == ':')
895: {
896: if (*(str + 1) != ':' && *(str + 1) != '\0')
897: return no_match;
898: colons--;
899: state = STATE_COLON;
900: }
901: else
902: {
903: sp = str;
904: state = STATE_ADDR;
905: }
906:
907: continue;
908: case STATE_COLON:
909: colons++;
910: if (*(str + 1) == '/')
911: return no_match;
912: else if (*(str + 1) == ':')
913: state = STATE_DOUBLE;
914: else
915: {
916: sp = str + 1;
917: state = STATE_ADDR;
918: }
919: break;
920: case STATE_DOUBLE:
921: if (double_colon)
922: return no_match;
923:
924: if (*(str + 1) == ':')
925: return no_match;
926: else
927: {
928: if (*(str + 1) != '\0' && *(str + 1) != '/')
929: colons++;
930: sp = str + 1;
931:
932: if (*(str + 1) == '/')
933: state = STATE_SLASH;
934: else
935: state = STATE_ADDR;
936: }
937:
938: double_colon++;
939: nums += 1;
940: break;
941: case STATE_ADDR:
942: if (*(str + 1) == ':' || *(str + 1) == '.'
943: || *(str + 1) == '\0' || *(str + 1) == '/')
944: {
945: if (str - sp > 3)
946: return no_match;
947:
948: for (; sp <= str; sp++)
949: if (*sp == '/')
950: return no_match;
951:
952: nums++;
953:
954: if (*(str + 1) == ':')
955: state = STATE_COLON;
956: else if (*(str + 1) == '.')
1.1.1.3 ! misho 957: {
! 958: if (colons || double_colon)
! 959: state = STATE_DOT;
! 960: else
! 961: return no_match;
! 962: }
1.1 misho 963: else if (*(str + 1) == '/')
964: state = STATE_SLASH;
965: }
966: break;
967: case STATE_DOT:
968: state = STATE_ADDR;
969: break;
970: case STATE_SLASH:
971: if (*(str + 1) == '\0')
972: return partly_match;
973:
974: state = STATE_MASK;
975: break;
976: default:
977: break;
978: }
979:
980: if (nums > 11)
981: return no_match;
982:
983: if (colons > 7)
984: return no_match;
985:
986: str++;
987: }
988:
989: if (state < STATE_MASK)
990: return partly_match;
991:
992: mask = strtol (str, &endptr, 10);
993: if (*endptr != '\0')
994: return no_match;
995:
996: if (mask < 0 || mask > 128)
997: return no_match;
998:
999: /* I don't know why mask < 13 makes command match partly.
1000: Forgive me to make this comments. I Want to set static default route
1001: because of lack of function to originate default in ospf6d; sorry
1002: yasu
1003: if (mask < 13)
1004: return partly_match;
1005: */
1006:
1007: return exact_match;
1008: }
1009:
1010: #endif /* HAVE_IPV6 */
1011:
1012: #define DECIMAL_STRLEN_MAX 10
1013:
1014: static int
1015: cmd_range_match (const char *range, const char *str)
1016: {
1017: char *p;
1018: char buf[DECIMAL_STRLEN_MAX + 1];
1019: char *endptr = NULL;
1020: unsigned long min, max, val;
1021:
1022: if (str == NULL)
1023: return 1;
1024:
1025: val = strtoul (str, &endptr, 10);
1026: if (*endptr != '\0')
1027: return 0;
1028:
1029: range++;
1030: p = strchr (range, '-');
1031: if (p == NULL)
1032: return 0;
1033: if (p - range > DECIMAL_STRLEN_MAX)
1034: return 0;
1035: strncpy (buf, range, p - range);
1036: buf[p - range] = '\0';
1037: min = strtoul (buf, &endptr, 10);
1038: if (*endptr != '\0')
1039: return 0;
1040:
1041: range = p + 1;
1042: p = strchr (range, '>');
1043: if (p == NULL)
1044: return 0;
1045: if (p - range > DECIMAL_STRLEN_MAX)
1046: return 0;
1047: strncpy (buf, range, p - range);
1048: buf[p - range] = '\0';
1049: max = strtoul (buf, &endptr, 10);
1050: if (*endptr != '\0')
1051: return 0;
1052:
1053: if (val < min || val > max)
1054: return 0;
1055:
1056: return 1;
1057: }
1058:
1059: /* Make completion match and return match type flag. */
1060: static enum match_type
1061: cmd_filter_by_completion (char *command, vector v, unsigned int index)
1062: {
1063: unsigned int i;
1064: const char *str;
1065: struct cmd_element *cmd_element;
1066: enum match_type match_type;
1067: vector descvec;
1068: struct desc *desc;
1069:
1070: match_type = no_match;
1071:
1072: /* If command and cmd_element string does not match set NULL to vector */
1073: for (i = 0; i < vector_active (v); i++)
1074: if ((cmd_element = vector_slot (v, i)) != NULL)
1075: {
1076: if (index >= vector_active (cmd_element->strvec))
1077: vector_slot (v, i) = NULL;
1078: else
1079: {
1080: unsigned int j;
1081: int matched = 0;
1082:
1083: descvec = vector_slot (cmd_element->strvec, index);
1084:
1085: for (j = 0; j < vector_active (descvec); j++)
1086: if ((desc = vector_slot (descvec, j)))
1087: {
1088: str = desc->cmd;
1089:
1090: if (CMD_VARARG (str))
1091: {
1092: if (match_type < vararg_match)
1093: match_type = vararg_match;
1094: matched++;
1095: }
1096: else if (CMD_RANGE (str))
1097: {
1098: if (cmd_range_match (str, command))
1099: {
1100: if (match_type < range_match)
1101: match_type = range_match;
1102:
1103: matched++;
1104: }
1105: }
1106: #ifdef HAVE_IPV6
1107: else if (CMD_IPV6 (str))
1108: {
1109: if (cmd_ipv6_match (command))
1110: {
1111: if (match_type < ipv6_match)
1112: match_type = ipv6_match;
1113:
1114: matched++;
1115: }
1116: }
1117: else if (CMD_IPV6_PREFIX (str))
1118: {
1119: if (cmd_ipv6_prefix_match (command))
1120: {
1121: if (match_type < ipv6_prefix_match)
1122: match_type = ipv6_prefix_match;
1123:
1124: matched++;
1125: }
1126: }
1127: #endif /* HAVE_IPV6 */
1128: else if (CMD_IPV4 (str))
1129: {
1130: if (cmd_ipv4_match (command))
1131: {
1132: if (match_type < ipv4_match)
1133: match_type = ipv4_match;
1134:
1135: matched++;
1136: }
1137: }
1138: else if (CMD_IPV4_PREFIX (str))
1139: {
1140: if (cmd_ipv4_prefix_match (command))
1141: {
1142: if (match_type < ipv4_prefix_match)
1143: match_type = ipv4_prefix_match;
1144: matched++;
1145: }
1146: }
1147: else
1148: /* Check is this point's argument optional ? */
1149: if (CMD_OPTION (str) || CMD_VARIABLE (str))
1150: {
1151: if (match_type < extend_match)
1152: match_type = extend_match;
1153: matched++;
1154: }
1155: else if (strncmp (command, str, strlen (command)) == 0)
1156: {
1157: if (strcmp (command, str) == 0)
1158: match_type = exact_match;
1159: else
1160: {
1161: if (match_type < partly_match)
1162: match_type = partly_match;
1163: }
1164: matched++;
1165: }
1166: }
1167: if (!matched)
1168: vector_slot (v, i) = NULL;
1169: }
1170: }
1171: return match_type;
1172: }
1173:
1174: /* Filter vector by command character with index. */
1175: static enum match_type
1176: cmd_filter_by_string (char *command, vector v, unsigned int index)
1177: {
1178: unsigned int i;
1179: const char *str;
1180: struct cmd_element *cmd_element;
1181: enum match_type match_type;
1182: vector descvec;
1183: struct desc *desc;
1184:
1185: match_type = no_match;
1186:
1187: /* If command and cmd_element string does not match set NULL to vector */
1188: for (i = 0; i < vector_active (v); i++)
1189: if ((cmd_element = vector_slot (v, i)) != NULL)
1190: {
1191: /* If given index is bigger than max string vector of command,
1192: set NULL */
1193: if (index >= vector_active (cmd_element->strvec))
1194: vector_slot (v, i) = NULL;
1195: else
1196: {
1197: unsigned int j;
1198: int matched = 0;
1199:
1200: descvec = vector_slot (cmd_element->strvec, index);
1201:
1202: for (j = 0; j < vector_active (descvec); j++)
1203: if ((desc = vector_slot (descvec, j)))
1204: {
1205: str = desc->cmd;
1206:
1207: if (CMD_VARARG (str))
1208: {
1209: if (match_type < vararg_match)
1210: match_type = vararg_match;
1211: matched++;
1212: }
1213: else if (CMD_RANGE (str))
1214: {
1215: if (cmd_range_match (str, command))
1216: {
1217: if (match_type < range_match)
1218: match_type = range_match;
1219: matched++;
1220: }
1221: }
1222: #ifdef HAVE_IPV6
1223: else if (CMD_IPV6 (str))
1224: {
1225: if (cmd_ipv6_match (command) == exact_match)
1226: {
1227: if (match_type < ipv6_match)
1228: match_type = ipv6_match;
1229: matched++;
1230: }
1231: }
1232: else if (CMD_IPV6_PREFIX (str))
1233: {
1234: if (cmd_ipv6_prefix_match (command) == exact_match)
1235: {
1236: if (match_type < ipv6_prefix_match)
1237: match_type = ipv6_prefix_match;
1238: matched++;
1239: }
1240: }
1241: #endif /* HAVE_IPV6 */
1242: else if (CMD_IPV4 (str))
1243: {
1244: if (cmd_ipv4_match (command) == exact_match)
1245: {
1246: if (match_type < ipv4_match)
1247: match_type = ipv4_match;
1248: matched++;
1249: }
1250: }
1251: else if (CMD_IPV4_PREFIX (str))
1252: {
1253: if (cmd_ipv4_prefix_match (command) == exact_match)
1254: {
1255: if (match_type < ipv4_prefix_match)
1256: match_type = ipv4_prefix_match;
1257: matched++;
1258: }
1259: }
1260: else if (CMD_OPTION (str) || CMD_VARIABLE (str))
1261: {
1262: if (match_type < extend_match)
1263: match_type = extend_match;
1264: matched++;
1265: }
1266: else
1267: {
1268: if (strcmp (command, str) == 0)
1269: {
1270: match_type = exact_match;
1271: matched++;
1272: }
1273: }
1274: }
1275: if (!matched)
1276: vector_slot (v, i) = NULL;
1277: }
1278: }
1279: return match_type;
1280: }
1281:
1282: /* Check ambiguous match */
1283: static int
1284: is_cmd_ambiguous (char *command, vector v, int index, enum match_type type)
1285: {
1286: unsigned int i;
1287: unsigned int j;
1288: const char *str = NULL;
1289: struct cmd_element *cmd_element;
1290: const char *matched = NULL;
1291: vector descvec;
1292: struct desc *desc;
1293:
1294: for (i = 0; i < vector_active (v); i++)
1295: if ((cmd_element = vector_slot (v, i)) != NULL)
1296: {
1297: int match = 0;
1298:
1299: descvec = vector_slot (cmd_element->strvec, index);
1300:
1301: for (j = 0; j < vector_active (descvec); j++)
1302: if ((desc = vector_slot (descvec, j)))
1303: {
1304: enum match_type ret;
1305:
1306: str = desc->cmd;
1307:
1308: switch (type)
1309: {
1310: case exact_match:
1311: if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
1312: && strcmp (command, str) == 0)
1313: match++;
1314: break;
1315: case partly_match:
1316: if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
1317: && strncmp (command, str, strlen (command)) == 0)
1318: {
1319: if (matched && strcmp (matched, str) != 0)
1320: return 1; /* There is ambiguous match. */
1321: else
1322: matched = str;
1323: match++;
1324: }
1325: break;
1326: case range_match:
1327: if (cmd_range_match (str, command))
1328: {
1329: if (matched && strcmp (matched, str) != 0)
1330: return 1;
1331: else
1332: matched = str;
1333: match++;
1334: }
1335: break;
1336: #ifdef HAVE_IPV6
1337: case ipv6_match:
1338: if (CMD_IPV6 (str))
1339: match++;
1340: break;
1341: case ipv6_prefix_match:
1342: if ((ret = cmd_ipv6_prefix_match (command)) != no_match)
1343: {
1344: if (ret == partly_match)
1345: return 2; /* There is incomplete match. */
1346:
1347: match++;
1348: }
1349: break;
1350: #endif /* HAVE_IPV6 */
1351: case ipv4_match:
1352: if (CMD_IPV4 (str))
1353: match++;
1354: break;
1355: case ipv4_prefix_match:
1356: if ((ret = cmd_ipv4_prefix_match (command)) != no_match)
1357: {
1358: if (ret == partly_match)
1359: return 2; /* There is incomplete match. */
1360:
1361: match++;
1362: }
1363: break;
1364: case extend_match:
1365: if (CMD_OPTION (str) || CMD_VARIABLE (str))
1366: match++;
1367: break;
1368: case no_match:
1369: default:
1370: break;
1371: }
1372: }
1373: if (!match)
1374: vector_slot (v, i) = NULL;
1375: }
1376: return 0;
1377: }
1378:
1379: /* If src matches dst return dst string, otherwise return NULL */
1380: static const char *
1381: cmd_entry_function (const char *src, const char *dst)
1382: {
1383: /* Skip variable arguments. */
1384: if (CMD_OPTION (dst) || CMD_VARIABLE (dst) || CMD_VARARG (dst) ||
1385: CMD_IPV4 (dst) || CMD_IPV4_PREFIX (dst) || CMD_RANGE (dst))
1386: return NULL;
1387:
1388: /* In case of 'command \t', given src is NULL string. */
1389: if (src == NULL)
1390: return dst;
1391:
1392: /* Matched with input string. */
1393: if (strncmp (src, dst, strlen (src)) == 0)
1394: return dst;
1395:
1396: return NULL;
1397: }
1398:
1399: /* If src matches dst return dst string, otherwise return NULL */
1400: /* This version will return the dst string always if it is
1401: CMD_VARIABLE for '?' key processing */
1402: static const char *
1403: cmd_entry_function_desc (const char *src, const char *dst)
1404: {
1405: if (CMD_VARARG (dst))
1406: return dst;
1407:
1408: if (CMD_RANGE (dst))
1409: {
1410: if (cmd_range_match (dst, src))
1411: return dst;
1412: else
1413: return NULL;
1414: }
1415:
1416: #ifdef HAVE_IPV6
1417: if (CMD_IPV6 (dst))
1418: {
1419: if (cmd_ipv6_match (src))
1420: return dst;
1421: else
1422: return NULL;
1423: }
1424:
1425: if (CMD_IPV6_PREFIX (dst))
1426: {
1427: if (cmd_ipv6_prefix_match (src))
1428: return dst;
1429: else
1430: return NULL;
1431: }
1432: #endif /* HAVE_IPV6 */
1433:
1434: if (CMD_IPV4 (dst))
1435: {
1436: if (cmd_ipv4_match (src))
1437: return dst;
1438: else
1439: return NULL;
1440: }
1441:
1442: if (CMD_IPV4_PREFIX (dst))
1443: {
1444: if (cmd_ipv4_prefix_match (src))
1445: return dst;
1446: else
1447: return NULL;
1448: }
1449:
1450: /* Optional or variable commands always match on '?' */
1451: if (CMD_OPTION (dst) || CMD_VARIABLE (dst))
1452: return dst;
1453:
1454: /* In case of 'command \t', given src is NULL string. */
1455: if (src == NULL)
1456: return dst;
1457:
1458: if (strncmp (src, dst, strlen (src)) == 0)
1459: return dst;
1460: else
1461: return NULL;
1462: }
1463:
1464: /* Check same string element existence. If it isn't there return
1465: 1. */
1466: static int
1467: cmd_unique_string (vector v, const char *str)
1468: {
1469: unsigned int i;
1470: char *match;
1471:
1472: for (i = 0; i < vector_active (v); i++)
1473: if ((match = vector_slot (v, i)) != NULL)
1474: if (strcmp (match, str) == 0)
1475: return 0;
1476: return 1;
1477: }
1478:
1479: /* Compare string to description vector. If there is same string
1480: return 1 else return 0. */
1481: static int
1482: desc_unique_string (vector v, const char *str)
1483: {
1484: unsigned int i;
1485: struct desc *desc;
1486:
1487: for (i = 0; i < vector_active (v); i++)
1488: if ((desc = vector_slot (v, i)) != NULL)
1489: if (strcmp (desc->cmd, str) == 0)
1490: return 1;
1491: return 0;
1492: }
1493:
1494: static int
1495: cmd_try_do_shortcut (enum node_type node, char* first_word) {
1496: if ( first_word != NULL &&
1497: node != AUTH_NODE &&
1498: node != VIEW_NODE &&
1499: node != AUTH_ENABLE_NODE &&
1500: node != ENABLE_NODE &&
1501: node != RESTRICTED_NODE &&
1502: 0 == strcmp( "do", first_word ) )
1503: return 1;
1504: return 0;
1505: }
1506:
1507: /* '?' describe command support. */
1508: static vector
1509: cmd_describe_command_real (vector vline, struct vty *vty, int *status)
1510: {
1511: unsigned int i;
1512: vector cmd_vector;
1513: #define INIT_MATCHVEC_SIZE 10
1514: vector matchvec;
1515: struct cmd_element *cmd_element;
1516: unsigned int index;
1517: int ret;
1518: enum match_type match;
1519: char *command;
1520:
1521: /* Set index. */
1522: if (vector_active (vline) == 0)
1523: {
1524: *status = CMD_ERR_NO_MATCH;
1525: return NULL;
1526: }
1527: else
1528: index = vector_active (vline) - 1;
1529:
1530: /* Make copy vector of current node's command vector. */
1531: cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1532:
1533: /* Prepare match vector */
1534: matchvec = vector_init (INIT_MATCHVEC_SIZE);
1535:
1536: /* Filter commands. */
1537: /* Only words precedes current word will be checked in this loop. */
1538: for (i = 0; i < index; i++)
1539: if ((command = vector_slot (vline, i)))
1540: {
1541: match = cmd_filter_by_completion (command, cmd_vector, i);
1542:
1543: if (match == vararg_match)
1544: {
1545: struct cmd_element *cmd_element;
1546: vector descvec;
1547: unsigned int j, k;
1548:
1549: for (j = 0; j < vector_active (cmd_vector); j++)
1550: if ((cmd_element = vector_slot (cmd_vector, j)) != NULL
1551: && (vector_active (cmd_element->strvec)))
1552: {
1553: descvec = vector_slot (cmd_element->strvec,
1554: vector_active (cmd_element->strvec) - 1);
1555: for (k = 0; k < vector_active (descvec); k++)
1556: {
1557: struct desc *desc = vector_slot (descvec, k);
1558: vector_set (matchvec, desc);
1559: }
1560: }
1561:
1562: vector_set (matchvec, &desc_cr);
1563: vector_free (cmd_vector);
1564:
1565: return matchvec;
1566: }
1567:
1568: if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
1569: {
1570: vector_free (cmd_vector);
1571: vector_free (matchvec);
1572: *status = CMD_ERR_AMBIGUOUS;
1573: return NULL;
1574: }
1575: else if (ret == 2)
1576: {
1577: vector_free (cmd_vector);
1578: vector_free (matchvec);
1579: *status = CMD_ERR_NO_MATCH;
1580: return NULL;
1581: }
1582: }
1583:
1584: /* Prepare match vector */
1585: /* matchvec = vector_init (INIT_MATCHVEC_SIZE); */
1586:
1587: /* Make sure that cmd_vector is filtered based on current word */
1588: command = vector_slot (vline, index);
1589: if (command)
1590: match = cmd_filter_by_completion (command, cmd_vector, index);
1591:
1592: /* Make description vector. */
1593: for (i = 0; i < vector_active (cmd_vector); i++)
1594: if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
1595: {
1596: vector strvec = cmd_element->strvec;
1597:
1598: /* if command is NULL, index may be equal to vector_active */
1599: if (command && index >= vector_active (strvec))
1600: vector_slot (cmd_vector, i) = NULL;
1601: else
1602: {
1603: /* Check if command is completed. */
1604: if (command == NULL && index == vector_active (strvec))
1605: {
1606: if (!desc_unique_string (matchvec, command_cr))
1607: vector_set (matchvec, &desc_cr);
1608: }
1609: else
1610: {
1611: unsigned int j;
1612: vector descvec = vector_slot (strvec, index);
1613: struct desc *desc;
1614:
1615: for (j = 0; j < vector_active (descvec); j++)
1616: if ((desc = vector_slot (descvec, j)))
1617: {
1618: const char *string;
1619:
1620: string = cmd_entry_function_desc (command, desc->cmd);
1621: if (string)
1622: {
1623: /* Uniqueness check */
1624: if (!desc_unique_string (matchvec, string))
1625: vector_set (matchvec, desc);
1626: }
1627: }
1628: }
1629: }
1630: }
1631: vector_free (cmd_vector);
1632:
1633: if (vector_slot (matchvec, 0) == NULL)
1634: {
1635: vector_free (matchvec);
1636: *status = CMD_ERR_NO_MATCH;
1637: return NULL;
1638: }
1639:
1640: *status = CMD_SUCCESS;
1641: return matchvec;
1642: }
1643:
1644: vector
1645: cmd_describe_command (vector vline, struct vty *vty, int *status)
1646: {
1647: vector ret;
1648:
1649: if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1650: {
1651: enum node_type onode;
1652: vector shifted_vline;
1653: unsigned int index;
1654:
1655: onode = vty->node;
1656: vty->node = ENABLE_NODE;
1657: /* We can try it on enable node, cos' the vty is authenticated */
1658:
1659: shifted_vline = vector_init (vector_count(vline));
1660: /* use memcpy? */
1661: for (index = 1; index < vector_active (vline); index++)
1662: {
1663: vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1664: }
1665:
1666: ret = cmd_describe_command_real (shifted_vline, vty, status);
1667:
1668: vector_free(shifted_vline);
1669: vty->node = onode;
1670: return ret;
1671: }
1672:
1673:
1674: return cmd_describe_command_real (vline, vty, status);
1675: }
1676:
1677:
1678: /* Check LCD of matched command. */
1679: static int
1680: cmd_lcd (char **matched)
1681: {
1682: int i;
1683: int j;
1684: int lcd = -1;
1685: char *s1, *s2;
1686: char c1, c2;
1687:
1688: if (matched[0] == NULL || matched[1] == NULL)
1689: return 0;
1690:
1691: for (i = 1; matched[i] != NULL; i++)
1692: {
1693: s1 = matched[i - 1];
1694: s2 = matched[i];
1695:
1696: for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
1697: if (c1 != c2)
1698: break;
1699:
1700: if (lcd < 0)
1701: lcd = j;
1702: else
1703: {
1704: if (lcd > j)
1705: lcd = j;
1706: }
1707: }
1708: return lcd;
1709: }
1710:
1711: /* Command line completion support. */
1712: static char **
1713: cmd_complete_command_real (vector vline, struct vty *vty, int *status)
1714: {
1715: unsigned int i;
1716: vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1717: #define INIT_MATCHVEC_SIZE 10
1718: vector matchvec;
1719: struct cmd_element *cmd_element;
1720: unsigned int index;
1721: char **match_str;
1722: struct desc *desc;
1723: vector descvec;
1724: char *command;
1725: int lcd;
1726:
1727: if (vector_active (vline) == 0)
1728: {
1729: vector_free (cmd_vector);
1730: *status = CMD_ERR_NO_MATCH;
1731: return NULL;
1732: }
1733: else
1734: index = vector_active (vline) - 1;
1735:
1736: /* First, filter by preceeding command string */
1737: for (i = 0; i < index; i++)
1738: if ((command = vector_slot (vline, i)))
1739: {
1740: enum match_type match;
1741: int ret;
1742:
1743: /* First try completion match, if there is exactly match return 1 */
1744: match = cmd_filter_by_completion (command, cmd_vector, i);
1745:
1746: /* If there is exact match then filter ambiguous match else check
1747: ambiguousness. */
1748: if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
1749: {
1750: vector_free (cmd_vector);
1751: *status = CMD_ERR_AMBIGUOUS;
1752: return NULL;
1753: }
1754: /*
1755: else if (ret == 2)
1756: {
1757: vector_free (cmd_vector);
1758: *status = CMD_ERR_NO_MATCH;
1759: return NULL;
1760: }
1761: */
1762: }
1763:
1764: /* Prepare match vector. */
1765: matchvec = vector_init (INIT_MATCHVEC_SIZE);
1766:
1767: /* Now we got into completion */
1768: for (i = 0; i < vector_active (cmd_vector); i++)
1769: if ((cmd_element = vector_slot (cmd_vector, i)))
1770: {
1771: const char *string;
1772: vector strvec = cmd_element->strvec;
1773:
1774: /* Check field length */
1775: if (index >= vector_active (strvec))
1776: vector_slot (cmd_vector, i) = NULL;
1777: else
1778: {
1779: unsigned int j;
1780:
1781: descvec = vector_slot (strvec, index);
1782: for (j = 0; j < vector_active (descvec); j++)
1783: if ((desc = vector_slot (descvec, j)))
1784: {
1785: if ((string =
1786: cmd_entry_function (vector_slot (vline, index),
1787: desc->cmd)))
1788: if (cmd_unique_string (matchvec, string))
1789: vector_set (matchvec, XSTRDUP (MTYPE_TMP, string));
1790: }
1791: }
1792: }
1793:
1794: /* We don't need cmd_vector any more. */
1795: vector_free (cmd_vector);
1796:
1797: /* No matched command */
1798: if (vector_slot (matchvec, 0) == NULL)
1799: {
1800: vector_free (matchvec);
1801:
1802: /* In case of 'command \t' pattern. Do you need '?' command at
1803: the end of the line. */
1804: if (vector_slot (vline, index) == '\0')
1805: *status = CMD_ERR_NOTHING_TODO;
1806: else
1807: *status = CMD_ERR_NO_MATCH;
1808: return NULL;
1809: }
1810:
1811: /* Only one matched */
1812: if (vector_slot (matchvec, 1) == NULL)
1813: {
1814: match_str = (char **) matchvec->index;
1815: vector_only_wrapper_free (matchvec);
1816: *status = CMD_COMPLETE_FULL_MATCH;
1817: return match_str;
1818: }
1819: /* Make it sure last element is NULL. */
1820: vector_set (matchvec, NULL);
1821:
1822: /* Check LCD of matched strings. */
1823: if (vector_slot (vline, index) != NULL)
1824: {
1825: lcd = cmd_lcd ((char **) matchvec->index);
1826:
1827: if (lcd)
1828: {
1829: int len = strlen (vector_slot (vline, index));
1830:
1831: if (len < lcd)
1832: {
1833: char *lcdstr;
1834:
1835: lcdstr = XMALLOC (MTYPE_STRVEC, lcd + 1);
1836: memcpy (lcdstr, matchvec->index[0], lcd);
1837: lcdstr[lcd] = '\0';
1838:
1839: /* match_str = (char **) &lcdstr; */
1840:
1841: /* Free matchvec. */
1842: for (i = 0; i < vector_active (matchvec); i++)
1843: {
1844: if (vector_slot (matchvec, i))
1845: XFREE (MTYPE_STRVEC, vector_slot (matchvec, i));
1846: }
1847: vector_free (matchvec);
1848:
1849: /* Make new matchvec. */
1850: matchvec = vector_init (INIT_MATCHVEC_SIZE);
1851: vector_set (matchvec, lcdstr);
1852: match_str = (char **) matchvec->index;
1853: vector_only_wrapper_free (matchvec);
1854:
1855: *status = CMD_COMPLETE_MATCH;
1856: return match_str;
1857: }
1858: }
1859: }
1860:
1861: match_str = (char **) matchvec->index;
1862: vector_only_wrapper_free (matchvec);
1863: *status = CMD_COMPLETE_LIST_MATCH;
1864: return match_str;
1865: }
1866:
1867: char **
1868: cmd_complete_command (vector vline, struct vty *vty, int *status)
1869: {
1870: char **ret;
1871:
1872: if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1873: {
1874: enum node_type onode;
1875: vector shifted_vline;
1876: unsigned int index;
1877:
1878: onode = vty->node;
1879: vty->node = ENABLE_NODE;
1880: /* We can try it on enable node, cos' the vty is authenticated */
1881:
1882: shifted_vline = vector_init (vector_count(vline));
1883: /* use memcpy? */
1884: for (index = 1; index < vector_active (vline); index++)
1885: {
1886: vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1887: }
1888:
1889: ret = cmd_complete_command_real (shifted_vline, vty, status);
1890:
1891: vector_free(shifted_vline);
1892: vty->node = onode;
1893: return ret;
1894: }
1895:
1896:
1897: return cmd_complete_command_real (vline, vty, status);
1898: }
1899:
1900: /* return parent node */
1901: /* MUST eventually converge on CONFIG_NODE */
1902: enum node_type
1903: node_parent ( enum node_type node )
1904: {
1905: enum node_type ret;
1906:
1907: assert (node > CONFIG_NODE);
1908:
1909: switch (node)
1910: {
1911: case BGP_VPNV4_NODE:
1912: case BGP_IPV4_NODE:
1913: case BGP_IPV4M_NODE:
1914: case BGP_IPV6_NODE:
1915: case BGP_IPV6M_NODE:
1916: ret = BGP_NODE;
1917: break;
1918: case KEYCHAIN_KEY_NODE:
1919: ret = KEYCHAIN_NODE;
1920: break;
1921: default:
1922: ret = CONFIG_NODE;
1923: }
1924:
1925: return ret;
1926: }
1927:
1928: /* Execute command by argument vline vector. */
1929: static int
1930: cmd_execute_command_real (vector vline, struct vty *vty,
1931: struct cmd_element **cmd)
1932: {
1933: unsigned int i;
1934: unsigned int index;
1935: vector cmd_vector;
1936: struct cmd_element *cmd_element;
1937: struct cmd_element *matched_element;
1938: unsigned int matched_count, incomplete_count;
1939: int argc;
1940: const char *argv[CMD_ARGC_MAX];
1941: enum match_type match = 0;
1942: int varflag;
1943: char *command;
1944:
1945: /* Make copy of command elements. */
1946: cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1947:
1948: for (index = 0; index < vector_active (vline); index++)
1949: if ((command = vector_slot (vline, index)))
1950: {
1951: int ret;
1952:
1953: match = cmd_filter_by_completion (command, cmd_vector, index);
1954:
1955: if (match == vararg_match)
1956: break;
1957:
1958: ret = is_cmd_ambiguous (command, cmd_vector, index, match);
1959:
1960: if (ret == 1)
1961: {
1962: vector_free (cmd_vector);
1963: return CMD_ERR_AMBIGUOUS;
1964: }
1965: else if (ret == 2)
1966: {
1967: vector_free (cmd_vector);
1968: return CMD_ERR_NO_MATCH;
1969: }
1970: }
1971:
1972: /* Check matched count. */
1973: matched_element = NULL;
1974: matched_count = 0;
1975: incomplete_count = 0;
1976:
1977: for (i = 0; i < vector_active (cmd_vector); i++)
1978: if ((cmd_element = vector_slot (cmd_vector, i)))
1979: {
1980: if (match == vararg_match || index >= cmd_element->cmdsize)
1981: {
1982: matched_element = cmd_element;
1983: #if 0
1984: printf ("DEBUG: %s\n", cmd_element->string);
1985: #endif
1986: matched_count++;
1987: }
1988: else
1989: {
1990: incomplete_count++;
1991: }
1992: }
1993:
1994: /* Finish of using cmd_vector. */
1995: vector_free (cmd_vector);
1996:
1997: /* To execute command, matched_count must be 1. */
1998: if (matched_count == 0)
1999: {
2000: if (incomplete_count)
2001: return CMD_ERR_INCOMPLETE;
2002: else
2003: return CMD_ERR_NO_MATCH;
2004: }
2005:
2006: if (matched_count > 1)
2007: return CMD_ERR_AMBIGUOUS;
2008:
2009: /* Argument treatment */
2010: varflag = 0;
2011: argc = 0;
2012:
2013: for (i = 0; i < vector_active (vline); i++)
2014: {
2015: if (varflag)
2016: argv[argc++] = vector_slot (vline, i);
2017: else
2018: {
2019: vector descvec = vector_slot (matched_element->strvec, i);
2020:
2021: if (vector_active (descvec) == 1)
2022: {
2023: struct desc *desc = vector_slot (descvec, 0);
2024:
2025: if (CMD_VARARG (desc->cmd))
2026: varflag = 1;
2027:
2028: if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
2029: argv[argc++] = vector_slot (vline, i);
2030: }
2031: else
2032: argv[argc++] = vector_slot (vline, i);
2033: }
2034:
2035: if (argc >= CMD_ARGC_MAX)
2036: return CMD_ERR_EXEED_ARGC_MAX;
2037: }
2038:
2039: /* For vtysh execution. */
2040: if (cmd)
2041: *cmd = matched_element;
2042:
2043: if (matched_element->daemon)
2044: return CMD_SUCCESS_DAEMON;
2045:
2046: /* Execute matched command. */
2047: return (*matched_element->func) (matched_element, vty, argc, argv);
2048: }
2049:
2050: int
2051: cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,
2052: int vtysh) {
2053: int ret, saved_ret, tried = 0;
2054: enum node_type onode, try_node;
2055:
2056: onode = try_node = vty->node;
2057:
2058: if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
2059: {
2060: vector shifted_vline;
2061: unsigned int index;
2062:
2063: vty->node = ENABLE_NODE;
2064: /* We can try it on enable node, cos' the vty is authenticated */
2065:
2066: shifted_vline = vector_init (vector_count(vline));
2067: /* use memcpy? */
2068: for (index = 1; index < vector_active (vline); index++)
2069: {
2070: vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
2071: }
2072:
2073: ret = cmd_execute_command_real (shifted_vline, vty, cmd);
2074:
2075: vector_free(shifted_vline);
2076: vty->node = onode;
2077: return ret;
2078: }
2079:
2080:
2081: saved_ret = ret = cmd_execute_command_real (vline, vty, cmd);
2082:
2083: if (vtysh)
2084: return saved_ret;
2085:
2086: /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
2087: while ( ret != CMD_SUCCESS && ret != CMD_WARNING
2088: && vty->node > CONFIG_NODE )
2089: {
2090: try_node = node_parent(try_node);
2091: vty->node = try_node;
2092: ret = cmd_execute_command_real (vline, vty, cmd);
2093: tried = 1;
2094: if (ret == CMD_SUCCESS || ret == CMD_WARNING)
2095: {
2096: /* succesfull command, leave the node as is */
2097: return ret;
2098: }
2099: }
2100: /* no command succeeded, reset the vty to the original node and
2101: return the error for this node */
2102: if ( tried )
2103: vty->node = onode;
2104: return saved_ret;
2105: }
2106:
2107: /* Execute command by argument readline. */
2108: int
2109: cmd_execute_command_strict (vector vline, struct vty *vty,
2110: struct cmd_element **cmd)
2111: {
2112: unsigned int i;
2113: unsigned int index;
2114: vector cmd_vector;
2115: struct cmd_element *cmd_element;
2116: struct cmd_element *matched_element;
2117: unsigned int matched_count, incomplete_count;
2118: int argc;
2119: const char *argv[CMD_ARGC_MAX];
2120: int varflag;
2121: enum match_type match = 0;
2122: char *command;
2123:
2124: /* Make copy of command element */
2125: cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2126:
2127: for (index = 0; index < vector_active (vline); index++)
2128: if ((command = vector_slot (vline, index)))
2129: {
2130: int ret;
2131:
2132: match = cmd_filter_by_string (vector_slot (vline, index),
2133: cmd_vector, index);
2134:
2135: /* If command meets '.VARARG' then finish matching. */
2136: if (match == vararg_match)
2137: break;
2138:
2139: ret = is_cmd_ambiguous (command, cmd_vector, index, match);
2140: if (ret == 1)
2141: {
2142: vector_free (cmd_vector);
2143: return CMD_ERR_AMBIGUOUS;
2144: }
2145: if (ret == 2)
2146: {
2147: vector_free (cmd_vector);
2148: return CMD_ERR_NO_MATCH;
2149: }
2150: }
2151:
2152: /* Check matched count. */
2153: matched_element = NULL;
2154: matched_count = 0;
2155: incomplete_count = 0;
2156: for (i = 0; i < vector_active (cmd_vector); i++)
2157: if (vector_slot (cmd_vector, i) != NULL)
2158: {
2159: cmd_element = vector_slot (cmd_vector, i);
2160:
2161: if (match == vararg_match || index >= cmd_element->cmdsize)
2162: {
2163: matched_element = cmd_element;
2164: matched_count++;
2165: }
2166: else
2167: incomplete_count++;
2168: }
2169:
2170: /* Finish of using cmd_vector. */
2171: vector_free (cmd_vector);
2172:
2173: /* To execute command, matched_count must be 1. */
2174: if (matched_count == 0)
2175: {
2176: if (incomplete_count)
2177: return CMD_ERR_INCOMPLETE;
2178: else
2179: return CMD_ERR_NO_MATCH;
2180: }
2181:
2182: if (matched_count > 1)
2183: return CMD_ERR_AMBIGUOUS;
2184:
2185: /* Argument treatment */
2186: varflag = 0;
2187: argc = 0;
2188:
2189: for (i = 0; i < vector_active (vline); i++)
2190: {
2191: if (varflag)
2192: argv[argc++] = vector_slot (vline, i);
2193: else
2194: {
2195: vector descvec = vector_slot (matched_element->strvec, i);
2196:
2197: if (vector_active (descvec) == 1)
2198: {
2199: struct desc *desc = vector_slot (descvec, 0);
2200:
2201: if (CMD_VARARG (desc->cmd))
2202: varflag = 1;
2203:
2204: if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
2205: argv[argc++] = vector_slot (vline, i);
2206: }
2207: else
2208: argv[argc++] = vector_slot (vline, i);
2209: }
2210:
2211: if (argc >= CMD_ARGC_MAX)
2212: return CMD_ERR_EXEED_ARGC_MAX;
2213: }
2214:
2215: /* For vtysh execution. */
2216: if (cmd)
2217: *cmd = matched_element;
2218:
2219: if (matched_element->daemon)
2220: return CMD_SUCCESS_DAEMON;
2221:
2222: /* Now execute matched command */
2223: return (*matched_element->func) (matched_element, vty, argc, argv);
2224: }
2225:
2226: /* Configration make from file. */
2227: int
2228: config_from_file (struct vty *vty, FILE *fp)
2229: {
2230: int ret;
2231: vector vline;
2232:
2233: while (fgets (vty->buf, VTY_BUFSIZ, fp))
2234: {
2235: vline = cmd_make_strvec (vty->buf);
2236:
2237: /* In case of comment line */
2238: if (vline == NULL)
2239: continue;
2240: /* Execute configuration command : this is strict match */
2241: ret = cmd_execute_command_strict (vline, vty, NULL);
2242:
2243: /* Try again with setting node to CONFIG_NODE */
2244: while (ret != CMD_SUCCESS && ret != CMD_WARNING
2245: && ret != CMD_ERR_NOTHING_TODO && vty->node != CONFIG_NODE)
2246: {
2247: vty->node = node_parent(vty->node);
2248: ret = cmd_execute_command_strict (vline, vty, NULL);
2249: }
2250:
2251: cmd_free_strvec (vline);
2252:
2253: if (ret != CMD_SUCCESS && ret != CMD_WARNING
2254: && ret != CMD_ERR_NOTHING_TODO)
2255: return ret;
2256: }
2257: return CMD_SUCCESS;
2258: }
2259:
2260: /* Configration from terminal */
2261: DEFUN (config_terminal,
2262: config_terminal_cmd,
2263: "configure terminal",
2264: "Configuration from vty interface\n"
2265: "Configuration terminal\n")
2266: {
2267: if (vty_config_lock (vty))
2268: vty->node = CONFIG_NODE;
2269: else
2270: {
2271: vty_out (vty, "VTY configuration is locked by other VTY%s", VTY_NEWLINE);
2272: return CMD_WARNING;
2273: }
2274: return CMD_SUCCESS;
2275: }
2276:
2277: /* Enable command */
2278: DEFUN (enable,
2279: config_enable_cmd,
2280: "enable",
2281: "Turn on privileged mode command\n")
2282: {
2283: /* If enable password is NULL, change to ENABLE_NODE */
2284: if ((host.enable == NULL && host.enable_encrypt == NULL) ||
2285: vty->type == VTY_SHELL_SERV)
2286: vty->node = ENABLE_NODE;
2287: else
2288: vty->node = AUTH_ENABLE_NODE;
2289:
2290: return CMD_SUCCESS;
2291: }
2292:
2293: /* Disable command */
2294: DEFUN (disable,
2295: config_disable_cmd,
2296: "disable",
2297: "Turn off privileged mode command\n")
2298: {
2299: if (vty->node == ENABLE_NODE)
2300: vty->node = VIEW_NODE;
2301: return CMD_SUCCESS;
2302: }
2303:
2304: /* Down vty node level. */
2305: DEFUN (config_exit,
2306: config_exit_cmd,
2307: "exit",
2308: "Exit current mode and down to previous mode\n")
2309: {
2310: switch (vty->node)
2311: {
2312: case VIEW_NODE:
2313: case ENABLE_NODE:
2314: case RESTRICTED_NODE:
2315: if (vty_shell (vty))
2316: exit (0);
2317: else
2318: vty->status = VTY_CLOSE;
2319: break;
2320: case CONFIG_NODE:
2321: vty->node = ENABLE_NODE;
2322: vty_config_unlock (vty);
2323: break;
2324: case INTERFACE_NODE:
2325: case ZEBRA_NODE:
2326: case BGP_NODE:
2327: case RIP_NODE:
2328: case RIPNG_NODE:
1.1.1.2 misho 2329: case BABEL_NODE:
1.1 misho 2330: case OSPF_NODE:
2331: case OSPF6_NODE:
2332: case ISIS_NODE:
2333: case KEYCHAIN_NODE:
2334: case MASC_NODE:
2335: case RMAP_NODE:
2336: case VTY_NODE:
2337: vty->node = CONFIG_NODE;
2338: break;
2339: case BGP_VPNV4_NODE:
2340: case BGP_IPV4_NODE:
2341: case BGP_IPV4M_NODE:
2342: case BGP_IPV6_NODE:
2343: case BGP_IPV6M_NODE:
2344: vty->node = BGP_NODE;
2345: break;
2346: case KEYCHAIN_KEY_NODE:
2347: vty->node = KEYCHAIN_NODE;
2348: break;
2349: default:
2350: break;
2351: }
2352: return CMD_SUCCESS;
2353: }
2354:
2355: /* quit is alias of exit. */
2356: ALIAS (config_exit,
2357: config_quit_cmd,
2358: "quit",
2359: "Exit current mode and down to previous mode\n")
2360:
2361: /* End of configuration. */
2362: DEFUN (config_end,
2363: config_end_cmd,
2364: "end",
2365: "End current mode and change to enable mode.")
2366: {
2367: switch (vty->node)
2368: {
2369: case VIEW_NODE:
2370: case ENABLE_NODE:
2371: case RESTRICTED_NODE:
2372: /* Nothing to do. */
2373: break;
2374: case CONFIG_NODE:
2375: case INTERFACE_NODE:
2376: case ZEBRA_NODE:
2377: case RIP_NODE:
2378: case RIPNG_NODE:
1.1.1.2 misho 2379: case BABEL_NODE:
1.1 misho 2380: case BGP_NODE:
2381: case BGP_VPNV4_NODE:
2382: case BGP_IPV4_NODE:
2383: case BGP_IPV4M_NODE:
2384: case BGP_IPV6_NODE:
2385: case BGP_IPV6M_NODE:
2386: case RMAP_NODE:
2387: case OSPF_NODE:
2388: case OSPF6_NODE:
2389: case ISIS_NODE:
2390: case KEYCHAIN_NODE:
2391: case KEYCHAIN_KEY_NODE:
2392: case MASC_NODE:
2393: case VTY_NODE:
2394: vty_config_unlock (vty);
2395: vty->node = ENABLE_NODE;
2396: break;
2397: default:
2398: break;
2399: }
2400: return CMD_SUCCESS;
2401: }
2402:
2403: /* Show version. */
2404: DEFUN (show_version,
2405: show_version_cmd,
2406: "show version",
2407: SHOW_STR
2408: "Displays zebra version\n")
2409: {
2410: vty_out (vty, "Quagga %s (%s).%s", QUAGGA_VERSION, host.name?host.name:"",
2411: VTY_NEWLINE);
1.1.1.3 ! misho 2412: vty_out (vty, "%s%s%s", QUAGGA_COPYRIGHT, GIT_INFO, VTY_NEWLINE);
1.1 misho 2413:
2414: return CMD_SUCCESS;
2415: }
2416:
2417: /* Help display function for all node. */
2418: DEFUN (config_help,
2419: config_help_cmd,
2420: "help",
2421: "Description of the interactive help system\n")
2422: {
2423: vty_out (vty,
2424: "Quagga VTY provides advanced help feature. When you need help,%s\
2425: anytime at the command line please press '?'.%s\
2426: %s\
2427: If nothing matches, the help list will be empty and you must backup%s\
2428: until entering a '?' shows the available options.%s\
2429: Two styles of help are provided:%s\
2430: 1. Full help is available when you are ready to enter a%s\
2431: command argument (e.g. 'show ?') and describes each possible%s\
2432: argument.%s\
2433: 2. Partial help is provided when an abbreviated argument is entered%s\
2434: and you want to know what arguments match the input%s\
2435: (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2436: VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2437: VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
2438: return CMD_SUCCESS;
2439: }
2440:
2441: /* Help display function for all node. */
2442: DEFUN (config_list,
2443: config_list_cmd,
2444: "list",
2445: "Print command list\n")
2446: {
2447: unsigned int i;
2448: struct cmd_node *cnode = vector_slot (cmdvec, vty->node);
2449: struct cmd_element *cmd;
2450:
2451: for (i = 0; i < vector_active (cnode->cmd_vector); i++)
2452: if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL
2453: && !(cmd->attr == CMD_ATTR_DEPRECATED
2454: || cmd->attr == CMD_ATTR_HIDDEN))
2455: vty_out (vty, " %s%s", cmd->string,
2456: VTY_NEWLINE);
2457: return CMD_SUCCESS;
2458: }
2459:
2460: /* Write current configuration into file. */
2461: DEFUN (config_write_file,
2462: config_write_file_cmd,
2463: "write file",
2464: "Write running configuration to memory, network, or terminal\n"
2465: "Write to configuration file\n")
2466: {
2467: unsigned int i;
2468: int fd;
2469: struct cmd_node *node;
2470: char *config_file;
2471: char *config_file_tmp = NULL;
2472: char *config_file_sav = NULL;
2473: int ret = CMD_WARNING;
2474: struct vty *file_vty;
2475:
2476: /* Check and see if we are operating under vtysh configuration */
2477: if (host.config == NULL)
2478: {
2479: vty_out (vty, "Can't save to configuration file, using vtysh.%s",
2480: VTY_NEWLINE);
2481: return CMD_WARNING;
2482: }
2483:
2484: /* Get filename. */
2485: config_file = host.config;
2486:
2487: config_file_sav =
2488: XMALLOC (MTYPE_TMP, strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
2489: strcpy (config_file_sav, config_file);
2490: strcat (config_file_sav, CONF_BACKUP_EXT);
2491:
2492:
2493: config_file_tmp = XMALLOC (MTYPE_TMP, strlen (config_file) + 8);
2494: sprintf (config_file_tmp, "%s.XXXXXX", config_file);
2495:
2496: /* Open file to configuration write. */
2497: fd = mkstemp (config_file_tmp);
2498: if (fd < 0)
2499: {
2500: vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
2501: VTY_NEWLINE);
2502: goto finished;
2503: }
2504:
2505: /* Make vty for configuration file. */
2506: file_vty = vty_new ();
2507: file_vty->fd = fd;
2508: file_vty->type = VTY_FILE;
2509:
2510: /* Config file header print. */
2511: vty_out (file_vty, "!\n! Zebra configuration saved from vty\n! ");
2512: vty_time_print (file_vty, 1);
2513: vty_out (file_vty, "!\n");
2514:
2515: for (i = 0; i < vector_active (cmdvec); i++)
2516: if ((node = vector_slot (cmdvec, i)) && node->func)
2517: {
2518: if ((*node->func) (file_vty))
2519: vty_out (file_vty, "!\n");
2520: }
2521: vty_close (file_vty);
2522:
2523: if (unlink (config_file_sav) != 0)
2524: if (errno != ENOENT)
2525: {
2526: vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
2527: VTY_NEWLINE);
2528: goto finished;
2529: }
2530: if (link (config_file, config_file_sav) != 0)
2531: {
2532: vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
2533: VTY_NEWLINE);
2534: goto finished;
2535: }
2536: sync ();
2537: if (unlink (config_file) != 0)
2538: {
2539: vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
2540: VTY_NEWLINE);
2541: goto finished;
2542: }
2543: if (link (config_file_tmp, config_file) != 0)
2544: {
2545: vty_out (vty, "Can't save configuration file %s.%s", config_file,
2546: VTY_NEWLINE);
2547: goto finished;
2548: }
2549: sync ();
2550:
2551: if (chmod (config_file, CONFIGFILE_MASK) != 0)
2552: {
2553: vty_out (vty, "Can't chmod configuration file %s: %s (%d).%s",
2554: config_file, safe_strerror(errno), errno, VTY_NEWLINE);
2555: goto finished;
2556: }
2557:
2558: vty_out (vty, "Configuration saved to %s%s", config_file,
2559: VTY_NEWLINE);
2560: ret = CMD_SUCCESS;
2561:
2562: finished:
2563: unlink (config_file_tmp);
2564: XFREE (MTYPE_TMP, config_file_tmp);
2565: XFREE (MTYPE_TMP, config_file_sav);
2566: return ret;
2567: }
2568:
2569: ALIAS (config_write_file,
2570: config_write_cmd,
2571: "write",
2572: "Write running configuration to memory, network, or terminal\n")
2573:
2574: ALIAS (config_write_file,
2575: config_write_memory_cmd,
2576: "write memory",
2577: "Write running configuration to memory, network, or terminal\n"
2578: "Write configuration to the file (same as write file)\n")
2579:
2580: ALIAS (config_write_file,
2581: copy_runningconfig_startupconfig_cmd,
2582: "copy running-config startup-config",
2583: "Copy configuration\n"
2584: "Copy running config to... \n"
2585: "Copy running config to startup config (same as write file)\n")
2586:
2587: /* Write current configuration into the terminal. */
2588: DEFUN (config_write_terminal,
2589: config_write_terminal_cmd,
2590: "write terminal",
2591: "Write running configuration to memory, network, or terminal\n"
2592: "Write to terminal\n")
2593: {
2594: unsigned int i;
2595: struct cmd_node *node;
2596:
2597: if (vty->type == VTY_SHELL_SERV)
2598: {
2599: for (i = 0; i < vector_active (cmdvec); i++)
2600: if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
2601: {
2602: if ((*node->func) (vty))
2603: vty_out (vty, "!%s", VTY_NEWLINE);
2604: }
2605: }
2606: else
2607: {
2608: vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
2609: VTY_NEWLINE);
2610: vty_out (vty, "!%s", VTY_NEWLINE);
2611:
2612: for (i = 0; i < vector_active (cmdvec); i++)
2613: if ((node = vector_slot (cmdvec, i)) && node->func)
2614: {
2615: if ((*node->func) (vty))
2616: vty_out (vty, "!%s", VTY_NEWLINE);
2617: }
2618: vty_out (vty, "end%s",VTY_NEWLINE);
2619: }
2620: return CMD_SUCCESS;
2621: }
2622:
2623: /* Write current configuration into the terminal. */
2624: ALIAS (config_write_terminal,
2625: show_running_config_cmd,
2626: "show running-config",
2627: SHOW_STR
2628: "running configuration\n")
2629:
2630: /* Write startup configuration into the terminal. */
2631: DEFUN (show_startup_config,
2632: show_startup_config_cmd,
2633: "show startup-config",
2634: SHOW_STR
2635: "Contentes of startup configuration\n")
2636: {
2637: char buf[BUFSIZ];
2638: FILE *confp;
2639:
2640: confp = fopen (host.config, "r");
2641: if (confp == NULL)
2642: {
2643: vty_out (vty, "Can't open configuration file [%s]%s",
2644: host.config, VTY_NEWLINE);
2645: return CMD_WARNING;
2646: }
2647:
2648: while (fgets (buf, BUFSIZ, confp))
2649: {
2650: char *cp = buf;
2651:
2652: while (*cp != '\r' && *cp != '\n' && *cp != '\0')
2653: cp++;
2654: *cp = '\0';
2655:
2656: vty_out (vty, "%s%s", buf, VTY_NEWLINE);
2657: }
2658:
2659: fclose (confp);
2660:
2661: return CMD_SUCCESS;
2662: }
2663:
2664: /* Hostname configuration */
2665: DEFUN (config_hostname,
2666: hostname_cmd,
2667: "hostname WORD",
2668: "Set system's network name\n"
2669: "This system's network name\n")
2670: {
2671: if (!isalpha((int) *argv[0]))
2672: {
2673: vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
2674: return CMD_WARNING;
2675: }
2676:
2677: if (host.name)
2678: XFREE (MTYPE_HOST, host.name);
2679:
2680: host.name = XSTRDUP (MTYPE_HOST, argv[0]);
2681: return CMD_SUCCESS;
2682: }
2683:
2684: DEFUN (config_no_hostname,
2685: no_hostname_cmd,
2686: "no hostname [HOSTNAME]",
2687: NO_STR
2688: "Reset system's network name\n"
2689: "Host name of this router\n")
2690: {
2691: if (host.name)
2692: XFREE (MTYPE_HOST, host.name);
2693: host.name = NULL;
2694: return CMD_SUCCESS;
2695: }
2696:
2697: /* VTY interface password set. */
2698: DEFUN (config_password, password_cmd,
2699: "password (8|) WORD",
2700: "Assign the terminal connection password\n"
2701: "Specifies a HIDDEN password will follow\n"
2702: "dummy string \n"
2703: "The HIDDEN line password string\n")
2704: {
2705: /* Argument check. */
2706: if (argc == 0)
2707: {
2708: vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2709: return CMD_WARNING;
2710: }
2711:
2712: if (argc == 2)
2713: {
2714: if (*argv[0] == '8')
2715: {
2716: if (host.password)
2717: XFREE (MTYPE_HOST, host.password);
2718: host.password = NULL;
2719: if (host.password_encrypt)
2720: XFREE (MTYPE_HOST, host.password_encrypt);
2721: host.password_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
2722: return CMD_SUCCESS;
2723: }
2724: else
2725: {
2726: vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2727: return CMD_WARNING;
2728: }
2729: }
2730:
2731: if (!isalnum ((int) *argv[0]))
2732: {
2733: vty_out (vty,
2734: "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2735: return CMD_WARNING;
2736: }
2737:
2738: if (host.password)
2739: XFREE (MTYPE_HOST, host.password);
2740: host.password = NULL;
2741:
2742: if (host.encrypt)
2743: {
2744: if (host.password_encrypt)
2745: XFREE (MTYPE_HOST, host.password_encrypt);
2746: host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
2747: }
2748: else
2749: host.password = XSTRDUP (MTYPE_HOST, argv[0]);
2750:
2751: return CMD_SUCCESS;
2752: }
2753:
2754: ALIAS (config_password, password_text_cmd,
2755: "password LINE",
2756: "Assign the terminal connection password\n"
2757: "The UNENCRYPTED (cleartext) line password\n")
2758:
2759: /* VTY enable password set. */
2760: DEFUN (config_enable_password, enable_password_cmd,
2761: "enable password (8|) WORD",
2762: "Modify enable password parameters\n"
2763: "Assign the privileged level password\n"
2764: "Specifies a HIDDEN password will follow\n"
2765: "dummy string \n"
2766: "The HIDDEN 'enable' password string\n")
2767: {
2768: /* Argument check. */
2769: if (argc == 0)
2770: {
2771: vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2772: return CMD_WARNING;
2773: }
2774:
2775: /* Crypt type is specified. */
2776: if (argc == 2)
2777: {
2778: if (*argv[0] == '8')
2779: {
2780: if (host.enable)
2781: XFREE (MTYPE_HOST, host.enable);
2782: host.enable = NULL;
2783:
2784: if (host.enable_encrypt)
2785: XFREE (MTYPE_HOST, host.enable_encrypt);
2786: host.enable_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
2787:
2788: return CMD_SUCCESS;
2789: }
2790: else
2791: {
2792: vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2793: return CMD_WARNING;
2794: }
2795: }
2796:
2797: if (!isalnum ((int) *argv[0]))
2798: {
2799: vty_out (vty,
2800: "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2801: return CMD_WARNING;
2802: }
2803:
2804: if (host.enable)
2805: XFREE (MTYPE_HOST, host.enable);
2806: host.enable = NULL;
2807:
2808: /* Plain password input. */
2809: if (host.encrypt)
2810: {
2811: if (host.enable_encrypt)
2812: XFREE (MTYPE_HOST, host.enable_encrypt);
2813: host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
2814: }
2815: else
2816: host.enable = XSTRDUP (MTYPE_HOST, argv[0]);
2817:
2818: return CMD_SUCCESS;
2819: }
2820:
2821: ALIAS (config_enable_password,
2822: enable_password_text_cmd,
2823: "enable password LINE",
2824: "Modify enable password parameters\n"
2825: "Assign the privileged level password\n"
2826: "The UNENCRYPTED (cleartext) 'enable' password\n")
2827:
2828: /* VTY enable password delete. */
2829: DEFUN (no_config_enable_password, no_enable_password_cmd,
2830: "no enable password",
2831: NO_STR
2832: "Modify enable password parameters\n"
2833: "Assign the privileged level password\n")
2834: {
2835: if (host.enable)
2836: XFREE (MTYPE_HOST, host.enable);
2837: host.enable = NULL;
2838:
2839: if (host.enable_encrypt)
2840: XFREE (MTYPE_HOST, host.enable_encrypt);
2841: host.enable_encrypt = NULL;
2842:
2843: return CMD_SUCCESS;
2844: }
2845:
2846: DEFUN (service_password_encrypt,
2847: service_password_encrypt_cmd,
2848: "service password-encryption",
2849: "Set up miscellaneous service\n"
2850: "Enable encrypted passwords\n")
2851: {
2852: if (host.encrypt)
2853: return CMD_SUCCESS;
2854:
2855: host.encrypt = 1;
2856:
2857: if (host.password)
2858: {
2859: if (host.password_encrypt)
2860: XFREE (MTYPE_HOST, host.password_encrypt);
2861: host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.password));
2862: }
2863: if (host.enable)
2864: {
2865: if (host.enable_encrypt)
2866: XFREE (MTYPE_HOST, host.enable_encrypt);
2867: host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.enable));
2868: }
2869:
2870: return CMD_SUCCESS;
2871: }
2872:
2873: DEFUN (no_service_password_encrypt,
2874: no_service_password_encrypt_cmd,
2875: "no service password-encryption",
2876: NO_STR
2877: "Set up miscellaneous service\n"
2878: "Enable encrypted passwords\n")
2879: {
2880: if (! host.encrypt)
2881: return CMD_SUCCESS;
2882:
2883: host.encrypt = 0;
2884:
2885: if (host.password_encrypt)
2886: XFREE (MTYPE_HOST, host.password_encrypt);
2887: host.password_encrypt = NULL;
2888:
2889: if (host.enable_encrypt)
2890: XFREE (MTYPE_HOST, host.enable_encrypt);
2891: host.enable_encrypt = NULL;
2892:
2893: return CMD_SUCCESS;
2894: }
2895:
2896: DEFUN (config_terminal_length, config_terminal_length_cmd,
2897: "terminal length <0-512>",
2898: "Set terminal line parameters\n"
2899: "Set number of lines on a screen\n"
2900: "Number of lines on screen (0 for no pausing)\n")
2901: {
2902: int lines;
2903: char *endptr = NULL;
2904:
2905: lines = strtol (argv[0], &endptr, 10);
2906: if (lines < 0 || lines > 512 || *endptr != '\0')
2907: {
2908: vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2909: return CMD_WARNING;
2910: }
2911: vty->lines = lines;
2912:
2913: return CMD_SUCCESS;
2914: }
2915:
2916: DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
2917: "terminal no length",
2918: "Set terminal line parameters\n"
2919: NO_STR
2920: "Set number of lines on a screen\n")
2921: {
2922: vty->lines = -1;
2923: return CMD_SUCCESS;
2924: }
2925:
2926: DEFUN (service_terminal_length, service_terminal_length_cmd,
2927: "service terminal-length <0-512>",
2928: "Set up miscellaneous service\n"
2929: "System wide terminal length configuration\n"
2930: "Number of lines of VTY (0 means no line control)\n")
2931: {
2932: int lines;
2933: char *endptr = NULL;
2934:
2935: lines = strtol (argv[0], &endptr, 10);
2936: if (lines < 0 || lines > 512 || *endptr != '\0')
2937: {
2938: vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2939: return CMD_WARNING;
2940: }
2941: host.lines = lines;
2942:
2943: return CMD_SUCCESS;
2944: }
2945:
2946: DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
2947: "no service terminal-length [<0-512>]",
2948: NO_STR
2949: "Set up miscellaneous service\n"
2950: "System wide terminal length configuration\n"
2951: "Number of lines of VTY (0 means no line control)\n")
2952: {
2953: host.lines = -1;
2954: return CMD_SUCCESS;
2955: }
2956:
2957: DEFUN_HIDDEN (do_echo,
2958: echo_cmd,
2959: "echo .MESSAGE",
2960: "Echo a message back to the vty\n"
2961: "The message to echo\n")
2962: {
2963: char *message;
2964:
2965: vty_out (vty, "%s%s", ((message = argv_concat(argv, argc, 0)) ? message : ""),
2966: VTY_NEWLINE);
2967: if (message)
2968: XFREE(MTYPE_TMP, message);
2969: return CMD_SUCCESS;
2970: }
2971:
2972: DEFUN (config_logmsg,
2973: config_logmsg_cmd,
2974: "logmsg "LOG_LEVELS" .MESSAGE",
2975: "Send a message to enabled logging destinations\n"
2976: LOG_LEVEL_DESC
2977: "The message to send\n")
2978: {
2979: int level;
2980: char *message;
2981:
2982: if ((level = level_match(argv[0])) == ZLOG_DISABLED)
2983: return CMD_ERR_NO_MATCH;
2984:
2985: zlog(NULL, level, "%s", ((message = argv_concat(argv, argc, 1)) ? message : ""));
2986: if (message)
2987: XFREE(MTYPE_TMP, message);
2988: return CMD_SUCCESS;
2989: }
2990:
2991: DEFUN (show_logging,
2992: show_logging_cmd,
2993: "show logging",
2994: SHOW_STR
2995: "Show current logging configuration\n")
2996: {
2997: struct zlog *zl = zlog_default;
2998:
2999: vty_out (vty, "Syslog logging: ");
3000: if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED)
3001: vty_out (vty, "disabled");
3002: else
3003: vty_out (vty, "level %s, facility %s, ident %s",
3004: zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]],
3005: facility_name(zl->facility), zl->ident);
3006: vty_out (vty, "%s", VTY_NEWLINE);
3007:
3008: vty_out (vty, "Stdout logging: ");
3009: if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED)
3010: vty_out (vty, "disabled");
3011: else
3012: vty_out (vty, "level %s",
3013: zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
3014: vty_out (vty, "%s", VTY_NEWLINE);
3015:
3016: vty_out (vty, "Monitor logging: ");
3017: if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
3018: vty_out (vty, "disabled");
3019: else
3020: vty_out (vty, "level %s",
3021: zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
3022: vty_out (vty, "%s", VTY_NEWLINE);
3023:
3024: vty_out (vty, "File logging: ");
3025: if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) ||
3026: !zl->fp)
3027: vty_out (vty, "disabled");
3028: else
3029: vty_out (vty, "level %s, filename %s",
3030: zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
3031: zl->filename);
3032: vty_out (vty, "%s", VTY_NEWLINE);
3033:
3034: vty_out (vty, "Protocol name: %s%s",
3035: zlog_proto_names[zl->protocol], VTY_NEWLINE);
3036: vty_out (vty, "Record priority: %s%s",
3037: (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE);
3038: vty_out (vty, "Timestamp precision: %d%s",
3039: zl->timestamp_precision, VTY_NEWLINE);
3040:
3041: return CMD_SUCCESS;
3042: }
3043:
3044: DEFUN (config_log_stdout,
3045: config_log_stdout_cmd,
3046: "log stdout",
3047: "Logging control\n"
3048: "Set stdout logging level\n")
3049: {
3050: zlog_set_level (NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl);
3051: return CMD_SUCCESS;
3052: }
3053:
3054: DEFUN (config_log_stdout_level,
3055: config_log_stdout_level_cmd,
3056: "log stdout "LOG_LEVELS,
3057: "Logging control\n"
3058: "Set stdout logging level\n"
3059: LOG_LEVEL_DESC)
3060: {
3061: int level;
3062:
3063: if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3064: return CMD_ERR_NO_MATCH;
3065: zlog_set_level (NULL, ZLOG_DEST_STDOUT, level);
3066: return CMD_SUCCESS;
3067: }
3068:
3069: DEFUN (no_config_log_stdout,
3070: no_config_log_stdout_cmd,
3071: "no log stdout [LEVEL]",
3072: NO_STR
3073: "Logging control\n"
3074: "Cancel logging to stdout\n"
3075: "Logging level\n")
3076: {
3077: zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED);
3078: return CMD_SUCCESS;
3079: }
3080:
3081: DEFUN (config_log_monitor,
3082: config_log_monitor_cmd,
3083: "log monitor",
3084: "Logging control\n"
3085: "Set terminal line (monitor) logging level\n")
3086: {
3087: zlog_set_level (NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl);
3088: return CMD_SUCCESS;
3089: }
3090:
3091: DEFUN (config_log_monitor_level,
3092: config_log_monitor_level_cmd,
3093: "log monitor "LOG_LEVELS,
3094: "Logging control\n"
3095: "Set terminal line (monitor) logging level\n"
3096: LOG_LEVEL_DESC)
3097: {
3098: int level;
3099:
3100: if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3101: return CMD_ERR_NO_MATCH;
3102: zlog_set_level (NULL, ZLOG_DEST_MONITOR, level);
3103: return CMD_SUCCESS;
3104: }
3105:
3106: DEFUN (no_config_log_monitor,
3107: no_config_log_monitor_cmd,
3108: "no log monitor [LEVEL]",
3109: NO_STR
3110: "Logging control\n"
3111: "Disable terminal line (monitor) logging\n"
3112: "Logging level\n")
3113: {
3114: zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
3115: return CMD_SUCCESS;
3116: }
3117:
3118: static int
3119: set_log_file(struct vty *vty, const char *fname, int loglevel)
3120: {
3121: int ret;
3122: char *p = NULL;
3123: const char *fullpath;
3124:
3125: /* Path detection. */
3126: if (! IS_DIRECTORY_SEP (*fname))
3127: {
3128: char cwd[MAXPATHLEN+1];
3129: cwd[MAXPATHLEN] = '\0';
3130:
3131: if (getcwd (cwd, MAXPATHLEN) == NULL)
3132: {
3133: zlog_err ("config_log_file: Unable to alloc mem!");
3134: return CMD_WARNING;
3135: }
3136:
3137: if ( (p = XMALLOC (MTYPE_TMP, strlen (cwd) + strlen (fname) + 2))
3138: == NULL)
3139: {
3140: zlog_err ("config_log_file: Unable to alloc mem!");
3141: return CMD_WARNING;
3142: }
3143: sprintf (p, "%s/%s", cwd, fname);
3144: fullpath = p;
3145: }
3146: else
3147: fullpath = fname;
3148:
3149: ret = zlog_set_file (NULL, fullpath, loglevel);
3150:
3151: if (p)
3152: XFREE (MTYPE_TMP, p);
3153:
3154: if (!ret)
3155: {
3156: vty_out (vty, "can't open logfile %s\n", fname);
3157: return CMD_WARNING;
3158: }
3159:
3160: if (host.logfile)
3161: XFREE (MTYPE_HOST, host.logfile);
3162:
3163: host.logfile = XSTRDUP (MTYPE_HOST, fname);
3164:
3165: return CMD_SUCCESS;
3166: }
3167:
3168: DEFUN (config_log_file,
3169: config_log_file_cmd,
3170: "log file FILENAME",
3171: "Logging control\n"
3172: "Logging to file\n"
3173: "Logging filename\n")
3174: {
3175: return set_log_file(vty, argv[0], zlog_default->default_lvl);
3176: }
3177:
3178: DEFUN (config_log_file_level,
3179: config_log_file_level_cmd,
3180: "log file FILENAME "LOG_LEVELS,
3181: "Logging control\n"
3182: "Logging to file\n"
3183: "Logging filename\n"
3184: LOG_LEVEL_DESC)
3185: {
3186: int level;
3187:
3188: if ((level = level_match(argv[1])) == ZLOG_DISABLED)
3189: return CMD_ERR_NO_MATCH;
3190: return set_log_file(vty, argv[0], level);
3191: }
3192:
3193: DEFUN (no_config_log_file,
3194: no_config_log_file_cmd,
3195: "no log file [FILENAME]",
3196: NO_STR
3197: "Logging control\n"
3198: "Cancel logging to file\n"
3199: "Logging file name\n")
3200: {
3201: zlog_reset_file (NULL);
3202:
3203: if (host.logfile)
3204: XFREE (MTYPE_HOST, host.logfile);
3205:
3206: host.logfile = NULL;
3207:
3208: return CMD_SUCCESS;
3209: }
3210:
3211: ALIAS (no_config_log_file,
3212: no_config_log_file_level_cmd,
3213: "no log file FILENAME LEVEL",
3214: NO_STR
3215: "Logging control\n"
3216: "Cancel logging to file\n"
3217: "Logging file name\n"
3218: "Logging level\n")
3219:
3220: DEFUN (config_log_syslog,
3221: config_log_syslog_cmd,
3222: "log syslog",
3223: "Logging control\n"
3224: "Set syslog logging level\n")
3225: {
3226: zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
3227: return CMD_SUCCESS;
3228: }
3229:
3230: DEFUN (config_log_syslog_level,
3231: config_log_syslog_level_cmd,
3232: "log syslog "LOG_LEVELS,
3233: "Logging control\n"
3234: "Set syslog logging level\n"
3235: LOG_LEVEL_DESC)
3236: {
3237: int level;
3238:
3239: if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3240: return CMD_ERR_NO_MATCH;
3241: zlog_set_level (NULL, ZLOG_DEST_SYSLOG, level);
3242: return CMD_SUCCESS;
3243: }
3244:
3245: DEFUN_DEPRECATED (config_log_syslog_facility,
3246: config_log_syslog_facility_cmd,
3247: "log syslog facility "LOG_FACILITIES,
3248: "Logging control\n"
3249: "Logging goes to syslog\n"
3250: "(Deprecated) Facility parameter for syslog messages\n"
3251: LOG_FACILITY_DESC)
3252: {
3253: int facility;
3254:
3255: if ((facility = facility_match(argv[0])) < 0)
3256: return CMD_ERR_NO_MATCH;
3257:
3258: zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
3259: zlog_default->facility = facility;
3260: return CMD_SUCCESS;
3261: }
3262:
3263: DEFUN (no_config_log_syslog,
3264: no_config_log_syslog_cmd,
3265: "no log syslog [LEVEL]",
3266: NO_STR
3267: "Logging control\n"
3268: "Cancel logging to syslog\n"
3269: "Logging level\n")
3270: {
3271: zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
3272: return CMD_SUCCESS;
3273: }
3274:
3275: ALIAS (no_config_log_syslog,
3276: no_config_log_syslog_facility_cmd,
3277: "no log syslog facility "LOG_FACILITIES,
3278: NO_STR
3279: "Logging control\n"
3280: "Logging goes to syslog\n"
3281: "Facility parameter for syslog messages\n"
3282: LOG_FACILITY_DESC)
3283:
3284: DEFUN (config_log_facility,
3285: config_log_facility_cmd,
3286: "log facility "LOG_FACILITIES,
3287: "Logging control\n"
3288: "Facility parameter for syslog messages\n"
3289: LOG_FACILITY_DESC)
3290: {
3291: int facility;
3292:
3293: if ((facility = facility_match(argv[0])) < 0)
3294: return CMD_ERR_NO_MATCH;
3295: zlog_default->facility = facility;
3296: return CMD_SUCCESS;
3297: }
3298:
3299: DEFUN (no_config_log_facility,
3300: no_config_log_facility_cmd,
3301: "no log facility [FACILITY]",
3302: NO_STR
3303: "Logging control\n"
3304: "Reset syslog facility to default (daemon)\n"
3305: "Syslog facility\n")
3306: {
3307: zlog_default->facility = LOG_DAEMON;
3308: return CMD_SUCCESS;
3309: }
3310:
3311: DEFUN_DEPRECATED (config_log_trap,
3312: config_log_trap_cmd,
3313: "log trap "LOG_LEVELS,
3314: "Logging control\n"
3315: "(Deprecated) Set logging level and default for all destinations\n"
3316: LOG_LEVEL_DESC)
3317: {
3318: int new_level ;
3319: int i;
3320:
3321: if ((new_level = level_match(argv[0])) == ZLOG_DISABLED)
3322: return CMD_ERR_NO_MATCH;
3323:
3324: zlog_default->default_lvl = new_level;
3325: for (i = 0; i < ZLOG_NUM_DESTS; i++)
3326: if (zlog_default->maxlvl[i] != ZLOG_DISABLED)
3327: zlog_default->maxlvl[i] = new_level;
3328: return CMD_SUCCESS;
3329: }
3330:
3331: DEFUN_DEPRECATED (no_config_log_trap,
3332: no_config_log_trap_cmd,
3333: "no log trap [LEVEL]",
3334: NO_STR
3335: "Logging control\n"
3336: "Permit all logging information\n"
3337: "Logging level\n")
3338: {
3339: zlog_default->default_lvl = LOG_DEBUG;
3340: return CMD_SUCCESS;
3341: }
3342:
3343: DEFUN (config_log_record_priority,
3344: config_log_record_priority_cmd,
3345: "log record-priority",
3346: "Logging control\n"
3347: "Log the priority of the message within the message\n")
3348: {
3349: zlog_default->record_priority = 1 ;
3350: return CMD_SUCCESS;
3351: }
3352:
3353: DEFUN (no_config_log_record_priority,
3354: no_config_log_record_priority_cmd,
3355: "no log record-priority",
3356: NO_STR
3357: "Logging control\n"
3358: "Do not log the priority of the message within the message\n")
3359: {
3360: zlog_default->record_priority = 0 ;
3361: return CMD_SUCCESS;
3362: }
3363:
3364: DEFUN (config_log_timestamp_precision,
3365: config_log_timestamp_precision_cmd,
3366: "log timestamp precision <0-6>",
3367: "Logging control\n"
3368: "Timestamp configuration\n"
3369: "Set the timestamp precision\n"
3370: "Number of subsecond digits\n")
3371: {
3372: if (argc != 1)
3373: {
3374: vty_out (vty, "Insufficient arguments%s", VTY_NEWLINE);
3375: return CMD_WARNING;
3376: }
3377:
3378: VTY_GET_INTEGER_RANGE("Timestamp Precision",
3379: zlog_default->timestamp_precision, argv[0], 0, 6);
3380: return CMD_SUCCESS;
3381: }
3382:
3383: DEFUN (no_config_log_timestamp_precision,
3384: no_config_log_timestamp_precision_cmd,
3385: "no log timestamp precision",
3386: NO_STR
3387: "Logging control\n"
3388: "Timestamp configuration\n"
3389: "Reset the timestamp precision to the default value of 0\n")
3390: {
3391: zlog_default->timestamp_precision = 0 ;
3392: return CMD_SUCCESS;
3393: }
3394:
3395: DEFUN (banner_motd_file,
3396: banner_motd_file_cmd,
3397: "banner motd file [FILE]",
3398: "Set banner\n"
3399: "Banner for motd\n"
3400: "Banner from a file\n"
3401: "Filename\n")
3402: {
3403: if (host.motdfile)
3404: XFREE (MTYPE_HOST, host.motdfile);
3405: host.motdfile = XSTRDUP (MTYPE_HOST, argv[0]);
3406:
3407: return CMD_SUCCESS;
3408: }
3409:
3410: DEFUN (banner_motd_default,
3411: banner_motd_default_cmd,
3412: "banner motd default",
3413: "Set banner string\n"
3414: "Strings for motd\n"
3415: "Default string\n")
3416: {
3417: host.motd = default_motd;
3418: return CMD_SUCCESS;
3419: }
3420:
3421: DEFUN (no_banner_motd,
3422: no_banner_motd_cmd,
3423: "no banner motd",
3424: NO_STR
3425: "Set banner string\n"
3426: "Strings for motd\n")
3427: {
3428: host.motd = NULL;
3429: if (host.motdfile)
3430: XFREE (MTYPE_HOST, host.motdfile);
3431: host.motdfile = NULL;
3432: return CMD_SUCCESS;
3433: }
3434:
3435: /* Set config filename. Called from vty.c */
3436: void
3437: host_config_set (char *filename)
3438: {
3439: if (host.config)
3440: XFREE (MTYPE_HOST, host.config);
3441: host.config = XSTRDUP (MTYPE_HOST, filename);
3442: }
3443:
3444: void
3445: install_default (enum node_type node)
3446: {
3447: install_element (node, &config_exit_cmd);
3448: install_element (node, &config_quit_cmd);
3449: install_element (node, &config_end_cmd);
3450: install_element (node, &config_help_cmd);
3451: install_element (node, &config_list_cmd);
3452:
3453: install_element (node, &config_write_terminal_cmd);
3454: install_element (node, &config_write_file_cmd);
3455: install_element (node, &config_write_memory_cmd);
3456: install_element (node, &config_write_cmd);
3457: install_element (node, &show_running_config_cmd);
3458: }
3459:
3460: /* Initialize command interface. Install basic nodes and commands. */
3461: void
3462: cmd_init (int terminal)
3463: {
3464: command_cr = XSTRDUP(MTYPE_STRVEC, "<cr>");
3465: desc_cr.cmd = command_cr;
3466: desc_cr.str = XSTRDUP(MTYPE_STRVEC, "");
3467:
3468: /* Allocate initial top vector of commands. */
3469: cmdvec = vector_init (VECTOR_MIN_SIZE);
3470:
3471: /* Default host value settings. */
3472: host.name = NULL;
3473: host.password = NULL;
3474: host.enable = NULL;
3475: host.logfile = NULL;
3476: host.config = NULL;
3477: host.lines = -1;
3478: host.motd = default_motd;
3479: host.motdfile = NULL;
3480:
3481: /* Install top nodes. */
3482: install_node (&view_node, NULL);
3483: install_node (&enable_node, NULL);
3484: install_node (&auth_node, NULL);
3485: install_node (&auth_enable_node, NULL);
3486: install_node (&restricted_node, NULL);
3487: install_node (&config_node, config_write_host);
3488:
3489: /* Each node's basic commands. */
3490: install_element (VIEW_NODE, &show_version_cmd);
3491: if (terminal)
3492: {
3493: install_element (VIEW_NODE, &config_list_cmd);
3494: install_element (VIEW_NODE, &config_exit_cmd);
3495: install_element (VIEW_NODE, &config_quit_cmd);
3496: install_element (VIEW_NODE, &config_help_cmd);
3497: install_element (VIEW_NODE, &config_enable_cmd);
3498: install_element (VIEW_NODE, &config_terminal_length_cmd);
3499: install_element (VIEW_NODE, &config_terminal_no_length_cmd);
3500: install_element (VIEW_NODE, &show_logging_cmd);
3501: install_element (VIEW_NODE, &echo_cmd);
3502:
3503: install_element (RESTRICTED_NODE, &config_list_cmd);
3504: install_element (RESTRICTED_NODE, &config_exit_cmd);
3505: install_element (RESTRICTED_NODE, &config_quit_cmd);
3506: install_element (RESTRICTED_NODE, &config_help_cmd);
3507: install_element (RESTRICTED_NODE, &config_enable_cmd);
3508: install_element (RESTRICTED_NODE, &config_terminal_length_cmd);
3509: install_element (RESTRICTED_NODE, &config_terminal_no_length_cmd);
3510: install_element (RESTRICTED_NODE, &echo_cmd);
3511: }
3512:
3513: if (terminal)
3514: {
3515: install_default (ENABLE_NODE);
3516: install_element (ENABLE_NODE, &config_disable_cmd);
3517: install_element (ENABLE_NODE, &config_terminal_cmd);
3518: install_element (ENABLE_NODE, ©_runningconfig_startupconfig_cmd);
3519: }
3520: install_element (ENABLE_NODE, &show_startup_config_cmd);
3521: install_element (ENABLE_NODE, &show_version_cmd);
3522:
3523: if (terminal)
3524: {
3525: install_element (ENABLE_NODE, &config_terminal_length_cmd);
3526: install_element (ENABLE_NODE, &config_terminal_no_length_cmd);
3527: install_element (ENABLE_NODE, &show_logging_cmd);
3528: install_element (ENABLE_NODE, &echo_cmd);
3529: install_element (ENABLE_NODE, &config_logmsg_cmd);
3530:
3531: install_default (CONFIG_NODE);
3532: }
3533:
3534: install_element (CONFIG_NODE, &hostname_cmd);
3535: install_element (CONFIG_NODE, &no_hostname_cmd);
3536:
3537: if (terminal)
3538: {
3539: install_element (CONFIG_NODE, &password_cmd);
3540: install_element (CONFIG_NODE, &password_text_cmd);
3541: install_element (CONFIG_NODE, &enable_password_cmd);
3542: install_element (CONFIG_NODE, &enable_password_text_cmd);
3543: install_element (CONFIG_NODE, &no_enable_password_cmd);
3544:
3545: install_element (CONFIG_NODE, &config_log_stdout_cmd);
3546: install_element (CONFIG_NODE, &config_log_stdout_level_cmd);
3547: install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
3548: install_element (CONFIG_NODE, &config_log_monitor_cmd);
3549: install_element (CONFIG_NODE, &config_log_monitor_level_cmd);
3550: install_element (CONFIG_NODE, &no_config_log_monitor_cmd);
3551: install_element (CONFIG_NODE, &config_log_file_cmd);
3552: install_element (CONFIG_NODE, &config_log_file_level_cmd);
3553: install_element (CONFIG_NODE, &no_config_log_file_cmd);
3554: install_element (CONFIG_NODE, &no_config_log_file_level_cmd);
3555: install_element (CONFIG_NODE, &config_log_syslog_cmd);
3556: install_element (CONFIG_NODE, &config_log_syslog_level_cmd);
3557: install_element (CONFIG_NODE, &config_log_syslog_facility_cmd);
3558: install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
3559: install_element (CONFIG_NODE, &no_config_log_syslog_facility_cmd);
3560: install_element (CONFIG_NODE, &config_log_facility_cmd);
3561: install_element (CONFIG_NODE, &no_config_log_facility_cmd);
3562: install_element (CONFIG_NODE, &config_log_trap_cmd);
3563: install_element (CONFIG_NODE, &no_config_log_trap_cmd);
3564: install_element (CONFIG_NODE, &config_log_record_priority_cmd);
3565: install_element (CONFIG_NODE, &no_config_log_record_priority_cmd);
3566: install_element (CONFIG_NODE, &config_log_timestamp_precision_cmd);
3567: install_element (CONFIG_NODE, &no_config_log_timestamp_precision_cmd);
3568: install_element (CONFIG_NODE, &service_password_encrypt_cmd);
3569: install_element (CONFIG_NODE, &no_service_password_encrypt_cmd);
3570: install_element (CONFIG_NODE, &banner_motd_default_cmd);
3571: install_element (CONFIG_NODE, &banner_motd_file_cmd);
3572: install_element (CONFIG_NODE, &no_banner_motd_cmd);
3573: install_element (CONFIG_NODE, &service_terminal_length_cmd);
3574: install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
3575:
3576: install_element (VIEW_NODE, &show_thread_cpu_cmd);
3577: install_element (ENABLE_NODE, &show_thread_cpu_cmd);
3578: install_element (RESTRICTED_NODE, &show_thread_cpu_cmd);
3579:
3580: install_element (ENABLE_NODE, &clear_thread_cpu_cmd);
3581: install_element (VIEW_NODE, &show_work_queues_cmd);
3582: install_element (ENABLE_NODE, &show_work_queues_cmd);
3583: }
3584: srand(time(NULL));
3585: }
3586:
3587: void
3588: cmd_terminate ()
3589: {
3590: unsigned int i, j, k, l;
3591: struct cmd_node *cmd_node;
3592: struct cmd_element *cmd_element;
3593: struct desc *desc;
3594: vector cmd_node_v, cmd_element_v, desc_v;
3595:
3596: if (cmdvec)
3597: {
3598: for (i = 0; i < vector_active (cmdvec); i++)
3599: if ((cmd_node = vector_slot (cmdvec, i)) != NULL)
3600: {
3601: cmd_node_v = cmd_node->cmd_vector;
3602:
3603: for (j = 0; j < vector_active (cmd_node_v); j++)
3604: if ((cmd_element = vector_slot (cmd_node_v, j)) != NULL &&
3605: cmd_element->strvec != NULL)
3606: {
3607: cmd_element_v = cmd_element->strvec;
3608:
3609: for (k = 0; k < vector_active (cmd_element_v); k++)
3610: if ((desc_v = vector_slot (cmd_element_v, k)) != NULL)
3611: {
3612: for (l = 0; l < vector_active (desc_v); l++)
3613: if ((desc = vector_slot (desc_v, l)) != NULL)
3614: {
3615: if (desc->cmd)
3616: XFREE (MTYPE_STRVEC, desc->cmd);
3617: if (desc->str)
3618: XFREE (MTYPE_STRVEC, desc->str);
3619:
3620: XFREE (MTYPE_DESC, desc);
3621: }
3622: vector_free (desc_v);
3623: }
3624:
3625: cmd_element->strvec = NULL;
3626: vector_free (cmd_element_v);
3627: }
3628:
3629: vector_free (cmd_node_v);
3630: }
3631:
3632: vector_free (cmdvec);
3633: cmdvec = NULL;
3634: }
3635:
3636: if (command_cr)
3637: XFREE(MTYPE_STRVEC, command_cr);
3638: if (desc_cr.str)
3639: XFREE(MTYPE_STRVEC, desc_cr.str);
3640: if (host.name)
3641: XFREE (MTYPE_HOST, host.name);
3642: if (host.password)
3643: XFREE (MTYPE_HOST, host.password);
3644: if (host.password_encrypt)
3645: XFREE (MTYPE_HOST, host.password_encrypt);
3646: if (host.enable)
3647: XFREE (MTYPE_HOST, host.enable);
3648: if (host.enable_encrypt)
3649: XFREE (MTYPE_HOST, host.enable_encrypt);
3650: if (host.logfile)
3651: XFREE (MTYPE_HOST, host.logfile);
3652: if (host.motdfile)
3653: XFREE (MTYPE_HOST, host.motdfile);
3654: if (host.config)
3655: XFREE (MTYPE_HOST, host.config);
3656: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>