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