blob: 28af1ca241a6b7150d37a2714879107015131eb8 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* Configuration generator.
2 Copyright (C) 2000 Kunihiro Ishiguro
3
4This file is part of GNU Zebra.
5
6GNU Zebra is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by the
8Free Software Foundation; either version 2, or (at your option) any
9later version.
10
11GNU Zebra is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Zebra; see the file COPYING. If not, write to the Free
18Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
1902111-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
29vector configvec;
30
31struct config
32{
33 /* Configuration node name. */
34 char *name;
35
36 /* Configuration string line. */
37 struct list *line;
38
39 /* Configuration can be nest. */
40 struct config *config;
41
42 /* Index of this config. */
43 u_int32_t index;
44};
45
46struct list *config_top;
47
48int
49line_cmp (char *c1, char *c2)
50{
51 return strcmp (c1, c2);
52}
53
54void
55line_del (char *line)
56{
57 XFREE (MTYPE_VTYSH_CONFIG_LINE, line);
58}
59
60struct config *
61config_new ()
62{
63 struct config *config;
64 config = XCALLOC (MTYPE_VTYSH_CONFIG, sizeof (struct config));
65 return config;
66}
67
68int
69config_cmp (struct config *c1, struct config *c2)
70{
71 return strcmp (c1->name, c2->name);
72}
73
74void
75config_del (struct config* config)
76{
77 list_delete (config->line);
78 if (config->name)
79 XFREE (MTYPE_VTYSH_CONFIG_LINE, config->name);
80 XFREE (MTYPE_VTYSH_CONFIG, config);
81}
82
83struct config *
84config_get (int index, char *line)
85{
86 struct config *config;
87 struct config *config_loop;
88 struct list *master;
89 struct listnode *nn;
90
91 config = config_loop = NULL;
92
93 master = vector_lookup_ensure (configvec, index);
94
95 if (! master)
96 {
97 master = list_new ();
98 master->del = (void (*) (void *))config_del;
99 master->cmp = (int (*)(void *, void *)) config_cmp;
100 vector_set_index (configvec, index, master);
101 }
102
103 LIST_LOOP (master, config_loop, nn)
104 {
105 if (strcmp (config_loop->name, line) == 0)
106 config = config_loop;
107 }
108
109 if (! config)
110 {
111 config = config_new ();
112 config->line = list_new ();
113 config->line->del = (void (*) (void *))line_del;
114 config->line->cmp = (int (*)(void *, void *)) line_cmp;
115 config->name = XSTRDUP (MTYPE_VTYSH_CONFIG_LINE, line);
116 config->index = index;
117 listnode_add (master, config);
118 }
119 return config;
120}
121
122void
123config_add_line (struct list *config, char *line)
124{
125 listnode_add (config, XSTRDUP (MTYPE_VTYSH_CONFIG_LINE, line));
126}
127
128void
129config_add_line_uniq (struct list *config, char *line)
130{
131 struct listnode *nn;
132 char *pnt;
133
134 LIST_LOOP (config, pnt, nn)
135 {
136 if (strcmp (pnt, line) == 0)
137 return;
138 }
139 listnode_add_sort (config, XSTRDUP (MTYPE_VTYSH_CONFIG_LINE, line));
140}
141
142void
143vtysh_config_parse_line (char *line)
144{
145 char c;
146 static struct config *config = NULL;
147
148 if (! line)
149 return;
150
151 c = line[0];
152
153 if (c == '\0')
154 return;
155
156 /* printf ("[%s]\n", line); */
157
158 switch (c)
159 {
160 case '!':
161 case '#':
162 break;
163 case ' ':
164 /* Store line to current configuration. */
165 if (config)
166 {
167 if (strncmp (line, " address-family vpnv4", strlen (" address-family vpnv4")) == 0)
168 config = config_get (BGP_VPNV4_NODE, line);
169 else if (strncmp (line, " address-family ipv4 multicast", strlen (" address-family ipv4 multicast")) == 0)
170 config = config_get (BGP_IPV4M_NODE, line);
171 else if (strncmp (line, " address-family ipv6", strlen (" address-family ipv6")) == 0)
172 config = config_get (BGP_IPV6_NODE, line);
paul97e1c4d2003-03-28 02:25:23 +0000173 else if (config->index == RMAP_NODE || config->index == INTERFACE_NODE )
paul718e3742002-12-13 20:15:29 +0000174 config_add_line_uniq (config->line, line);
175 else
176 config_add_line (config->line, line);
177 }
178 else
179 config_add_line (config_top, line);
180 break;
181 default:
182 if (strncmp (line, "interface", strlen ("interface")) == 0)
183 config = config_get (INTERFACE_NODE, line);
184 else if (strncmp (line, "router rip", strlen ("router rip")) == 0)
185 config = config_get (RIP_NODE, line);
paul97e1c4d2003-03-28 02:25:23 +0000186 else if (strncmp (line, "router ripng", strlen ("router ripng")) == 0)
187 config = config_get (RIPNG_NODE, line);
paul718e3742002-12-13 20:15:29 +0000188 else if (strncmp (line, "router ospf", strlen ("router ospf")) == 0)
paul97e1c4d2003-03-28 02:25:23 +0000189 config = config_get (OSPF_NODE, line);
190 else if (strncmp (line, "router ospf6", strlen ("router ospf6")) == 0)
191 config = config_get (OSPF6_NODE, line);
paul718e3742002-12-13 20:15:29 +0000192 else if (strncmp (line, "router bgp", strlen ("router bgp")) == 0)
193 config = config_get (BGP_NODE, line);
hassoc25e4582003-12-23 10:39:08 +0000194 else if (strncmp (line, "router isis", strlen ("router bgp")) == 0)
195 config = config_get (ISIS_NODE, line);
paul718e3742002-12-13 20:15:29 +0000196 else if (strncmp (line, "router", strlen ("router")) == 0)
197 config = config_get (BGP_NODE, line);
198 else if (strncmp (line, "route-map", strlen ("route-map")) == 0)
199 config = config_get (RMAP_NODE, line);
200 else if (strncmp (line, "access-list", strlen ("access-list")) == 0)
201 config = config_get (ACCESS_NODE, line);
paul97e1c4d2003-03-28 02:25:23 +0000202 else if (strncmp (line, "ipv6 access-list", strlen ("ipv6 access-list")) == 0)
203 config = config_get (ACCESS_IPV6_NODE, line);
paul718e3742002-12-13 20:15:29 +0000204 else if (strncmp (line, "ip prefix-list", strlen ("ip prefix-list")) == 0)
205 config = config_get (PREFIX_NODE, line);
paul97e1c4d2003-03-28 02:25:23 +0000206 else if (strncmp (line, "ipv6 prefix-list", strlen ("ipv6 prefix-list")) == 0)
207 config = config_get (PREFIX_IPV6_NODE, line);
paul718e3742002-12-13 20:15:29 +0000208 else if (strncmp (line, "ip as-path access-list", strlen ("ip as-path access-list")) == 0)
209 config = config_get (AS_LIST_NODE, line);
210 else if (strncmp (line, "ip community-list", strlen ("ip community-list")) == 0)
211 config = config_get (COMMUNITY_LIST_NODE, line);
212 else if (strncmp (line, "ip route", strlen ("ip route")) == 0)
213 config = config_get (IP_NODE, line);
paul97e1c4d2003-03-28 02:25:23 +0000214 else if (strncmp (line, "ipv6 route", strlen ("ipv6 route")) == 0)
215 config = config_get (IP_NODE, line);
paul718e3742002-12-13 20:15:29 +0000216 else if (strncmp (line, "key", strlen ("key")) == 0)
217 config = config_get (KEYCHAIN_NODE, line);
218 else
219 {
220 if (strncmp (line, "log", strlen ("log")) == 0
221 || strncmp (line, "hostname", strlen ("hostname")) == 0
222 || strncmp (line, "password", strlen ("hostname")) == 0)
223 config_add_line_uniq (config_top, line);
224 else
225 config_add_line (config_top, line);
226 config = NULL;
227 }
228 break;
229 }
230}
231
232void
233vtysh_config_parse (char *line)
234{
235 char *begin;
236 char *pnt;
237
238 begin = pnt = line;
239
240 while (*pnt != '\0')
241 {
242 if (*pnt == '\n')
243 {
244 *pnt++ = '\0';
245 vtysh_config_parse_line (begin);
246 begin = pnt;
247 }
248 else
249 {
250 pnt++;
251 }
252 }
253}
254
255/* Macro to check delimiter is needed between each configuration line
256 or not. */
257#define NO_DELIMITER(I) \
258 ((I) == ACCESS_NODE || (I) == PREFIX_NODE || (I) == IP_NODE \
paul97e1c4d2003-03-28 02:25:23 +0000259 || (I) == AS_LIST_NODE || (I) == COMMUNITY_LIST_NODE || \
260 (I) == ACCESS_IPV6_NODE || (I) == PREFIX_IPV6_NODE)
paul718e3742002-12-13 20:15:29 +0000261
262/* Display configuration to file pointer. */
263void
264vtysh_config_dump (FILE *fp)
265{
266 struct listnode *nn;
267 struct listnode *nm;
268 struct config *config;
269 struct list *master;
270 char *line;
271 int i;
272
273 LIST_LOOP (config_top, line, nn)
274 {
275 fprintf (fp, "%s\n", line);
276 fflush (fp);
277 }
278 fprintf (fp, "!\n");
279 fflush (fp);
280
281 for (i = 0; i < vector_max (configvec); i++)
282 if ((master = vector_slot (configvec, i)) != NULL)
283 {
284 LIST_LOOP (master, config, nn)
285 {
286 fprintf (fp, "%s\n", config->name);
287 fflush (fp);
288
289 LIST_LOOP (config->line, line, nm)
290 {
291 fprintf (fp, "%s\n", line);
292 fflush (fp);
293 }
294 if (! NO_DELIMITER (i))
295 {
296 fprintf (fp, "!\n");
297 fflush (fp);
298 }
299 }
300 if (NO_DELIMITER (i))
301 {
302 fprintf (fp, "!\n");
303 fflush (fp);
304 }
305 }
306
307 for (i = 0; i < vector_max (configvec); i++)
308 if ((master = vector_slot (configvec, i)) != NULL)
309 {
310 list_delete (master);
311 vector_slot (configvec, i) = NULL;
312 }
313 list_delete_all_node (config_top);
314}
315
316/* Read up configuration file from file_name. */
317static void
318vtysh_read_file (FILE *confp)
319{
320 int ret;
321 struct vty *vty;
322
323 vty = vty_new ();
324 vty->fd = 0; /* stdout */
325 vty->type = VTY_TERM;
326 vty->node = CONFIG_NODE;
327
328 vtysh_execute_no_pager ("enable");
329 vtysh_execute_no_pager ("configure terminal");
330
331 /* Execute configuration file */
332 ret = vtysh_config_from_file (vty, confp);
333
334 vtysh_execute_no_pager ("end");
335 vtysh_execute_no_pager ("disable");
336
337 vty_close (vty);
338
339 if (ret != CMD_SUCCESS)
340 {
341 switch (ret)
342 {
343 case CMD_ERR_AMBIGUOUS:
344 fprintf (stderr, "Ambiguous command.\n");
345 break;
346 case CMD_ERR_NO_MATCH:
347 fprintf (stderr, "There is no such command.\n");
348 break;
349 }
350 fprintf (stderr, "Error occured during reading below line.\n%s\n",
351 vty->buf);
352 exit (1);
353 }
354}
355
356/* Read up configuration file from file_name. */
357void
358vtysh_read_config (char *config_file,
359 char *config_current_dir,
360 char *config_default_dir)
361{
362 char *cwd;
363 FILE *confp = NULL;
364 char *fullpath;
365
366 /* If -f flag specified. */
367 if (config_file != NULL)
368 {
369 if (! IS_DIRECTORY_SEP (config_file[0]))
370 {
371 cwd = getcwd (NULL, MAXPATHLEN);
372 fullpath = XMALLOC (MTYPE_TMP,
373 strlen (cwd) + strlen (config_file) + 2);
374 sprintf (fullpath, "%s/%s", cwd, config_file);
375 }
376 else
377 fullpath = config_file;
378
379 confp = fopen (fullpath, "r");
380
381 if (confp == NULL)
382 {
383 fprintf (stderr, "can't open configuration file [%s]\n",
384 config_file);
385 exit(1);
386 }
387 }
388 else
389 {
390 /* Relative path configuration file open. */
391 if (config_current_dir)
392 confp = fopen (config_current_dir, "r");
393
394 /* If there is no relative path exists, open system default file. */
395 if (confp == NULL)
396 {
397 confp = fopen (config_default_dir, "r");
398 if (confp == NULL)
399 {
400 fprintf (stderr, "can't open configuration file [%s]\n",
401 config_default_dir);
402 exit (1);
403 }
404 else
405 fullpath = config_default_dir;
406 }
407 else
408 {
409 /* Rleative path configuration file. */
410 cwd = getcwd (NULL, MAXPATHLEN);
411 fullpath = XMALLOC (MTYPE_TMP,
412 strlen (cwd) + strlen (config_current_dir) + 2);
413 sprintf (fullpath, "%s/%s", cwd, config_current_dir);
414 }
415 }
416 vtysh_read_file (confp);
417
418 fclose (confp);
419
420 host_config_set (fullpath);
421}
422
423void
424vtysh_config_write (FILE *fp)
425{
426 extern struct host host;
427
428 if (host.name)
429 fprintf (fp, "hostname %s\n", host.name);
430 fprintf (fp, "!\n");
431}
432
433void
434vtysh_config_init ()
435{
436 config_top = list_new ();
437 config_top->del = (void (*) (void *))line_del;
438 configvec = vector_init (1);
439}