Import Upstream version 1.2.2
[quagga-debian.git] / vtysh / vtysh_config.c
1 /* Configuration generator.
2    Copyright (C) 2000 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 it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 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 Free
18 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 02111-1307, USA.  */
20
21 #include <zebra.h>
22
23 #include "command.h"
24 #include "linklist.h"
25 #include "memory.h"
26
27 #include "vtysh/vtysh.h"
28
29 vector configvec;
30
31 extern int vtysh_writeconfig_integrated;
32
33 struct config
34 {
35   /* Configuration node name. */
36   char *name;
37
38   /* Configuration string line. */
39   struct list *line;
40
41   /* Configuration can be nest. */
42   struct config *config;
43
44   /* Index of this config. */
45   u_int32_t index;
46 };
47
48 struct list *config_top;
49
50 static int
51 line_cmp (char *c1, char *c2)
52 {
53   return strcmp (c1, c2);
54 }
55
56 static void
57 line_del (char *line)
58 {
59   XFREE (MTYPE_VTYSH_CONFIG_LINE, line);
60 }
61
62 static struct config *
63 config_new ()
64 {
65   struct config *config;
66   config = XCALLOC (MTYPE_VTYSH_CONFIG, sizeof (struct config));
67   return config;
68 }
69
70 static int
71 config_cmp (struct config *c1, struct config *c2)
72 {
73   return strcmp (c1->name, c2->name);
74 }
75
76 static void
77 config_del (struct config* config)
78 {
79   list_delete (config->line);
80   if (config->name)
81     XFREE (MTYPE_VTYSH_CONFIG_LINE, config->name);
82   XFREE (MTYPE_VTYSH_CONFIG, config);
83 }
84
85 static struct config *
86 config_get (int index, const char *line)
87 {
88   struct config *config;
89   struct config *config_loop;
90   struct list *master;
91   struct listnode *node, *nnode;
92
93   config = config_loop = NULL;
94
95   master = vector_lookup_ensure (configvec, index);
96
97   if (! master)
98     {
99       master = list_new ();
100       master->del = (void (*) (void *))config_del;
101       master->cmp = (int (*)(void *, void *)) config_cmp;
102       vector_set_index (configvec, index, master);
103     }
104   
105   for (ALL_LIST_ELEMENTS (master, node, nnode, config_loop))
106     {
107       if (strcmp (config_loop->name, line) == 0)
108         config = config_loop;
109     }
110
111   if (! config)
112     {
113       config = config_new ();
114       config->line = list_new ();
115       config->line->del = (void (*) (void *))line_del;
116       config->line->cmp = (int (*)(void *, void *)) line_cmp;
117       config->name = XSTRDUP (MTYPE_VTYSH_CONFIG_LINE, line);
118       config->index = index;
119       listnode_add (master, config);
120     }
121   return config;
122 }
123
124 static void
125 config_add_line (struct list *config, const char *line)
126 {
127   listnode_add (config, XSTRDUP (MTYPE_VTYSH_CONFIG_LINE, line));
128 }
129
130 static void
131 config_add_line_uniq (struct list *config, const char *line)
132 {
133   struct listnode *node, *nnode;
134   char *pnt;
135
136   for (ALL_LIST_ELEMENTS (config, node, nnode, pnt))
137     {
138       if (strcmp (pnt, line) == 0)
139         return;
140     }
141   listnode_add_sort (config, XSTRDUP (MTYPE_VTYSH_CONFIG_LINE, line));
142 }
143
144 static void
145 vtysh_config_parse_line (const char *line)
146 {
147   char c;
148   static struct config *config = NULL;
149
150   if (! line)
151     return;
152
153   c = line[0];
154
155   if (c == '\0')
156     return;
157
158   /* printf ("[%s]\n", line); */
159
160   switch (c)
161     {
162     case '!':
163     case '#':
164       break;
165     case ' ':
166       /* Store line to current configuration. */
167       if (config)
168         {
169           if (strncmp (line, " address-family vpnv4",
170               strlen (" address-family vpnv4")) == 0)
171             config = config_get (BGP_VPNV4_NODE, line);
172           else if (strncmp (line, " address-family vpn6",
173               strlen (" address-family vpn6")) == 0)
174             config = config_get (BGP_VPNV6_NODE, line);
175           else if (strncmp (line, " address-family encapv6",
176               strlen (" address-family encapv6")) == 0)
177             config = config_get (BGP_ENCAPV6_NODE, line);
178           else if (strncmp (line, " address-family encap",
179               strlen (" address-family encap")) == 0)
180             config = config_get (BGP_ENCAP_NODE, line);
181           else if (strncmp (line, " address-family ipv4 multicast",
182                    strlen (" address-family ipv4 multicast")) == 0)
183             config = config_get (BGP_IPV4M_NODE, line);
184           else if (strncmp (line, " address-family ipv6",
185                    strlen (" address-family ipv6")) == 0)
186             config = config_get (BGP_IPV6_NODE, line);
187           else if (strncmp (line, " link-params", strlen (" link-params")) == 0)
188             {
189               config_add_line (config->line, line);
190               config->index = LINK_PARAMS_NODE;
191             }
192           else if (config->index == LINK_PARAMS_NODE &&
193                    strncmp (line, "  exit-link-params", strlen ("  exit")) == 0)
194             {
195               config_add_line (config->line, line);
196               config->index = INTERFACE_NODE;
197             }
198           else if (config->index == RMAP_NODE ||
199               config->index == INTERFACE_NODE ||
200               config->index == VTY_NODE)
201             config_add_line_uniq (config->line, line);
202           else
203             config_add_line (config->line, line);
204         }
205       else
206         config_add_line (config_top, line);
207       break;
208     default:
209       if (strncmp (line, "interface", strlen ("interface")) == 0)
210         config = config_get (INTERFACE_NODE, line);
211       else if (strncmp (line, "router-id", strlen ("router-id")) == 0)
212         config = config_get (ZEBRA_NODE, line);
213       else if (strncmp (line, "router rip", strlen ("router rip")) == 0)
214         config = config_get (RIP_NODE, line);
215       else if (strncmp (line, "router ripng", strlen ("router ripng")) == 0)
216         config = config_get (RIPNG_NODE, line);
217       else if (strncmp (line, "router ospf", strlen ("router ospf")) == 0)
218         config = config_get (OSPF_NODE, line);
219       else if (strncmp (line, "router ospf6", strlen ("router ospf6")) == 0)
220         config = config_get (OSPF6_NODE, line);
221       else if (strncmp (line, "router bgp", strlen ("router bgp")) == 0)
222         config = config_get (BGP_NODE, line);
223       else if (strncmp (line, "router isis", strlen ("router isis")) == 0)
224         config = config_get (ISIS_NODE, line);
225       else if (strncmp (line, "router bgp", strlen ("router bgp")) == 0)
226         config = config_get (BGP_NODE, line);
227       else if (strncmp (line, "route-map", strlen ("route-map")) == 0)
228         config = config_get (RMAP_NODE, line);
229       else if (strncmp (line, "access-list", strlen ("access-list")) == 0)
230         config = config_get (ACCESS_NODE, line);
231       else if (strncmp (line, "ipv6 access-list",
232                strlen ("ipv6 access-list")) == 0)
233         config = config_get (ACCESS_IPV6_NODE, line);
234       else if (strncmp (line, "ip prefix-list",
235                strlen ("ip prefix-list")) == 0)
236         config = config_get (PREFIX_NODE, line);
237       else if (strncmp (line, "ipv6 prefix-list",
238                strlen ("ipv6 prefix-list")) == 0)
239         config = config_get (PREFIX_IPV6_NODE, line);
240       else if (strncmp (line, "ip as-path access-list",
241                strlen ("ip as-path access-list")) == 0)
242         config = config_get (AS_LIST_NODE, line);
243       else if (strncmp (line, "ip community-list",
244                strlen ("ip community-list")) == 0)
245         config = config_get (COMMUNITY_LIST_NODE, line);
246       else if (strncmp (line, "ip route", strlen ("ip route")) == 0)
247         config = config_get (IP_NODE, line);
248       else if (strncmp (line, "ipv6 route", strlen ("ipv6 route")) == 0)
249         config = config_get (IP_NODE, line);
250       else if (strncmp (line, "key", strlen ("key")) == 0)
251         config = config_get (KEYCHAIN_NODE, line);
252       else if (strncmp (line, "line", strlen ("line")) == 0)
253         config = config_get (VTY_NODE, line);
254       else if ( (strncmp (line, "ipv6 forwarding",
255                  strlen ("ipv6 forwarding")) == 0)
256                || (strncmp (line, "ip forwarding",
257                    strlen ("ip forwarding")) == 0) )
258         config = config_get (FORWARDING_NODE, line);
259       else if (strncmp (line, "service", strlen ("service")) == 0)
260         config = config_get (SERVICE_NODE, line);
261       else if (strncmp (line, "debug", strlen ("debug")) == 0)
262         config = config_get (DEBUG_NODE, line);
263       else if (strncmp (line, "password", strlen ("password")) == 0
264                || strncmp (line, "enable password",
265                            strlen ("enable password")) == 0)
266         config = config_get (AAA_NODE, line);
267       else if (strncmp (line, "ip protocol", strlen ("ip protocol")) == 0)
268         config = config_get (PROTOCOL_NODE, line);
269       else
270         {
271           if (strncmp (line, "log", strlen ("log")) == 0
272               || strncmp (line, "hostname", strlen ("hostname")) == 0
273              )
274             config_add_line_uniq (config_top, line);
275           else
276             config_add_line (config_top, line);
277           config = NULL;
278         }
279       break;
280     }
281 }
282
283 void
284 vtysh_config_parse (char *line)
285 {
286   char *begin;
287   char *pnt;
288   
289   begin = pnt = line;
290
291   while (*pnt != '\0')
292     {
293       if (*pnt == '\n')
294         {
295           *pnt++ = '\0';
296           vtysh_config_parse_line (begin);
297           begin = pnt;
298         }
299       else
300         {
301           pnt++;
302         }
303     }
304 }
305
306 /* Macro to check delimiter is needed between each configuration line
307  * or not. */
308 #define NO_DELIMITER(I)  \
309   ((I) == ACCESS_NODE || (I) == PREFIX_NODE || (I) == IP_NODE \
310    || (I) == AS_LIST_NODE || (I) == COMMUNITY_LIST_NODE || \
311    (I) == ACCESS_IPV6_NODE || (I) == PREFIX_IPV6_NODE \
312    || (I) == SERVICE_NODE || (I) == FORWARDING_NODE || (I) == DEBUG_NODE \
313    || (I) == AAA_NODE)
314
315 /* Display configuration to file pointer. */
316 void
317 vtysh_config_dump (FILE *fp)
318 {
319   struct listnode *node, *nnode;
320   struct listnode *mnode, *mnnode;
321   struct config *config;
322   struct list *master;
323   char *line;
324   unsigned int i;
325
326   for (ALL_LIST_ELEMENTS (config_top, node, nnode, line))
327     {
328       fprintf (fp, "%s\n", line);
329       fflush (fp);
330     }
331   fprintf (fp, "!\n");
332   fflush (fp);
333
334   for (i = 0; i < vector_active (configvec); i++)
335     if ((master = vector_slot (configvec, i)) != NULL)
336       {
337         for (ALL_LIST_ELEMENTS (master, node, nnode, config))
338           {
339             fprintf (fp, "%s\n", config->name);
340             fflush (fp);
341
342             for (ALL_LIST_ELEMENTS (config->line, mnode, mnnode, line))
343               {
344                 fprintf  (fp, "%s\n", line);
345                 fflush (fp);
346               }
347             if (! NO_DELIMITER (i))
348               {
349                 fprintf (fp, "!\n");
350                 fflush (fp);
351               }
352           }
353         if (NO_DELIMITER (i))
354           {
355             fprintf (fp, "!\n");
356             fflush (fp);
357           }
358       }
359
360   for (i = 0; i < vector_active (configvec); i++)
361     if ((master = vector_slot (configvec, i)) != NULL)
362       {
363         list_delete (master);
364         vector_slot (configvec, i) = NULL;
365       }
366   list_delete_all_node (config_top);
367 }
368
369 /* Read up configuration file from file_name. */
370 static void
371 vtysh_read_file (FILE *confp)
372 {
373   int ret;
374   struct vty *vty;
375
376   vty = vty_new ();
377   vty->fd = 0;                  /* stdout */
378   vty->type = VTY_TERM;
379   vty->node = CONFIG_NODE;
380   
381   vtysh_execute_no_pager ("enable");
382   vtysh_execute_no_pager ("configure terminal");
383
384   /* Execute configuration file. */
385   ret = vtysh_config_from_file (vty, confp);
386
387   vtysh_execute_no_pager ("end");
388   vtysh_execute_no_pager ("disable");
389
390   vty_close (vty);
391
392   if (ret != CMD_SUCCESS) 
393     {
394       switch (ret)
395         {
396         case CMD_ERR_AMBIGUOUS:
397           fprintf (stderr, "Ambiguous command.\n");
398           break;
399         case CMD_ERR_NO_MATCH:
400           fprintf (stderr, "There is no such command.\n");
401           break;
402         }
403       fprintf (stderr, "Error occured during reading below line.\n%s\n", 
404                vty->buf);
405       exit (1);
406     }
407 }
408
409 /* Read up configuration file from config_default_dir. */
410 int
411 vtysh_read_config (char *config_default_dir)
412 {
413   FILE *confp = NULL;
414
415   confp = fopen (config_default_dir, "r");
416   if (confp == NULL)
417     return (1);
418
419   vtysh_read_file (confp);
420   fclose (confp);
421   host_config_set (config_default_dir);
422
423   return (0);
424 }
425
426 /* We don't write vtysh specific into file from vtysh. vtysh.conf should
427  * be edited by hand. So, we handle only "write terminal" case here and
428  * integrate vtysh specific conf with conf from daemons.
429  */
430 void
431 vtysh_config_write ()
432 {
433   char line[81];
434   extern struct host host;
435
436   if (host.name)
437     {
438       sprintf (line, "hostname %s", host.name);
439       vtysh_config_parse_line(line);
440     }
441   if (vtysh_writeconfig_integrated)
442     vtysh_config_parse_line ("service integrated-vtysh-config");
443 }
444
445 void
446 vtysh_config_init ()
447 {
448   config_top = list_new ();
449   config_top->del = (void (*) (void *))line_del;
450   configvec = vector_init (1);
451 }