]> git.proxmox.com Git - mirror_frr.git/blob - vtysh/vtysh_config.c
New way to handle secondary addresses from Gilad Arnold.
[mirror_frr.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 struct 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
46 struct list *config_top;
47
48 int
49 line_cmp (char *c1, char *c2)
50 {
51 return strcmp (c1, c2);
52 }
53
54 void
55 line_del (char *line)
56 {
57 XFREE (MTYPE_VTYSH_CONFIG_LINE, line);
58 }
59
60 struct config *
61 config_new ()
62 {
63 struct config *config;
64 config = XCALLOC (MTYPE_VTYSH_CONFIG, sizeof (struct config));
65 return config;
66 }
67
68 int
69 config_cmp (struct config *c1, struct config *c2)
70 {
71 return strcmp (c1->name, c2->name);
72 }
73
74 void
75 config_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
83 struct config *
84 config_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
122 void
123 config_add_line (struct list *config, char *line)
124 {
125 listnode_add (config, XSTRDUP (MTYPE_VTYSH_CONFIG_LINE, line));
126 }
127
128 void
129 config_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
142 void
143 vtysh_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",
168 strlen (" address-family vpnv4")) == 0)
169 config = config_get (BGP_VPNV4_NODE, line);
170 else if (strncmp (line, " address-family ipv4 multicast",
171 strlen (" address-family ipv4 multicast")) == 0)
172 config = config_get (BGP_IPV4M_NODE, line);
173 else if (strncmp (line, " address-family ipv6",
174 strlen (" address-family ipv6")) == 0)
175 config = config_get (BGP_IPV6_NODE, line);
176 else if (config->index == RMAP_NODE ||
177 config->index == INTERFACE_NODE )
178 config_add_line_uniq (config->line, line);
179 else
180 config_add_line (config->line, line);
181 }
182 else
183 config_add_line (config_top, line);
184 break;
185 default:
186 if (strncmp (line, "interface", strlen ("interface")) == 0)
187 config = config_get (INTERFACE_NODE, line);
188 else if (strncmp (line, "router rip", strlen ("router rip")) == 0)
189 config = config_get (RIP_NODE, line);
190 else if (strncmp (line, "router ripng", strlen ("router ripng")) == 0)
191 config = config_get (RIPNG_NODE, line);
192 else if (strncmp (line, "router ospf", strlen ("router ospf")) == 0)
193 config = config_get (OSPF_NODE, line);
194 else if (strncmp (line, "router ospf6", strlen ("router ospf6")) == 0)
195 config = config_get (OSPF6_NODE, line);
196 else if (strncmp (line, "router bgp", strlen ("router bgp")) == 0)
197 config = config_get (BGP_NODE, line);
198 else if (strncmp (line, "router isis", strlen ("router isis")) == 0)
199 config = config_get (ISIS_NODE, line);
200 else if (strncmp (line, "router", strlen ("router")) == 0)
201 config = config_get (BGP_NODE, line);
202 else if (strncmp (line, "route-map", strlen ("route-map")) == 0)
203 config = config_get (RMAP_NODE, line);
204 else if (strncmp (line, "access-list", strlen ("access-list")) == 0)
205 config = config_get (ACCESS_NODE, line);
206 else if (strncmp (line, "ipv6 access-list",
207 strlen ("ipv6 access-list")) == 0)
208 config = config_get (ACCESS_IPV6_NODE, line);
209 else if (strncmp (line, "ip prefix-list",
210 strlen ("ip prefix-list")) == 0)
211 config = config_get (PREFIX_NODE, line);
212 else if (strncmp (line, "ipv6 prefix-list",
213 strlen ("ipv6 prefix-list")) == 0)
214 config = config_get (PREFIX_IPV6_NODE, line);
215 else if (strncmp (line, "ip as-path access-list",
216 strlen ("ip as-path access-list")) == 0)
217 config = config_get (AS_LIST_NODE, line);
218 else if (strncmp (line, "ip community-list",
219 strlen ("ip community-list")) == 0)
220 config = config_get (COMMUNITY_LIST_NODE, line);
221 else if (strncmp (line, "ip route", strlen ("ip route")) == 0)
222 config = config_get (IP_NODE, line);
223 else if (strncmp (line, "ipv6 route", strlen ("ipv6 route")) == 0)
224 config = config_get (IP_NODE, line);
225 else if (strncmp (line, "key", strlen ("key")) == 0)
226 config = config_get (KEYCHAIN_NODE, line);
227 else
228 {
229 if (strncmp (line, "log", strlen ("log")) == 0
230 || strncmp (line, "hostname", strlen ("hostname")) == 0
231 || strncmp (line, "password", strlen ("password")) == 0
232 || strncmp (line, "enable password",
233 strlen ("enable password")) == 0)
234 config_add_line_uniq (config_top, line);
235 else
236 config_add_line (config_top, line);
237 config = NULL;
238 }
239 break;
240 }
241 }
242
243 void
244 vtysh_config_parse (char *line)
245 {
246 char *begin;
247 char *pnt;
248
249 begin = pnt = line;
250
251 while (*pnt != '\0')
252 {
253 if (*pnt == '\n')
254 {
255 *pnt++ = '\0';
256 vtysh_config_parse_line (begin);
257 begin = pnt;
258 }
259 else
260 {
261 pnt++;
262 }
263 }
264 }
265
266 /* Macro to check delimiter is needed between each configuration line
267 * or not. */
268 #define NO_DELIMITER(I) \
269 ((I) == ACCESS_NODE || (I) == PREFIX_NODE || (I) == IP_NODE \
270 || (I) == AS_LIST_NODE || (I) == COMMUNITY_LIST_NODE || \
271 (I) == ACCESS_IPV6_NODE || (I) == PREFIX_IPV6_NODE)
272
273 /* Display configuration to file pointer. */
274 void
275 vtysh_config_dump (FILE *fp)
276 {
277 struct listnode *nn;
278 struct listnode *nm;
279 struct config *config;
280 struct list *master;
281 char *line;
282 int i;
283
284 LIST_LOOP (config_top, line, nn)
285 {
286 fprintf (fp, "%s\n", line);
287 fflush (fp);
288 }
289 fprintf (fp, "!\n");
290 fflush (fp);
291
292 for (i = 0; i < vector_max (configvec); i++)
293 if ((master = vector_slot (configvec, i)) != NULL)
294 {
295 LIST_LOOP (master, config, nn)
296 {
297 fprintf (fp, "%s\n", config->name);
298 fflush (fp);
299
300 LIST_LOOP (config->line, line, nm)
301 {
302 fprintf (fp, "%s\n", line);
303 fflush (fp);
304 }
305 if (! NO_DELIMITER (i))
306 {
307 fprintf (fp, "!\n");
308 fflush (fp);
309 }
310 }
311 if (NO_DELIMITER (i))
312 {
313 fprintf (fp, "!\n");
314 fflush (fp);
315 }
316 }
317
318 for (i = 0; i < vector_max (configvec); i++)
319 if ((master = vector_slot (configvec, i)) != NULL)
320 {
321 list_delete (master);
322 vector_slot (configvec, i) = NULL;
323 }
324 list_delete_all_node (config_top);
325 }
326
327 /* Read up configuration file from file_name. */
328 static void
329 vtysh_read_file (FILE *confp)
330 {
331 int ret;
332 struct vty *vty;
333
334 vty = vty_new ();
335 vty->fd = 0; /* stdout */
336 vty->type = VTY_TERM;
337 vty->node = CONFIG_NODE;
338
339 vtysh_execute_no_pager ("enable");
340 vtysh_execute_no_pager ("configure terminal");
341
342 /* Execute configuration file. */
343 ret = vtysh_config_from_file (vty, confp);
344
345 vtysh_execute_no_pager ("end");
346 vtysh_execute_no_pager ("disable");
347
348 vty_close (vty);
349
350 if (ret != CMD_SUCCESS)
351 {
352 switch (ret)
353 {
354 case CMD_ERR_AMBIGUOUS:
355 fprintf (stderr, "Ambiguous command.\n");
356 break;
357 case CMD_ERR_NO_MATCH:
358 fprintf (stderr, "There is no such command.\n");
359 break;
360 }
361 fprintf (stderr, "Error occured during reading below line.\n%s\n",
362 vty->buf);
363 exit (1);
364 }
365 }
366
367 /* Read up configuration file from file_name. */
368 void
369 vtysh_read_config (char *config_file,
370 char *config_default_dir)
371 {
372 char *cwd;
373 FILE *confp = NULL;
374 char *fullpath;
375
376 /* If -f flag specified. */
377 if (config_file != NULL)
378 {
379 if (! IS_DIRECTORY_SEP (config_file[0]))
380 {
381 cwd = getcwd (NULL, MAXPATHLEN);
382 fullpath = XMALLOC (MTYPE_TMP,
383 strlen (cwd) + strlen (config_file) + 2);
384 sprintf (fullpath, "%s/%s", cwd, config_file);
385 }
386 else
387 fullpath = config_file;
388
389 confp = fopen (fullpath, "r");
390
391 if (confp == NULL)
392 {
393 fprintf (stderr, "can't open configuration file [%s]\n",
394 config_file);
395 exit(1);
396 }
397 }
398 else
399 {
400 /* No configuration specified from command line. Open system
401 * default file. */
402 confp = fopen (config_default_dir, "r");
403 if (confp == NULL)
404 {
405 fprintf (stderr, "can't open configuration file [%s]\n",
406 config_default_dir);
407 exit (1);
408 }
409 else
410 fullpath = config_default_dir;
411 }
412
413 vtysh_read_file (confp);
414
415 fclose (confp);
416
417 host_config_set (fullpath);
418 }
419
420 void
421 vtysh_config_write (FILE *fp)
422 {
423 extern struct host host;
424
425 if (host.name)
426 fprintf (fp, "hostname %s\n", host.name);
427 fprintf (fp, "!\n");
428 }
429
430 void
431 vtysh_config_init ()
432 {
433 config_top = list_new ();
434 config_top->del = (void (*) (void *))line_del;
435 configvec = vector_init (1);
436 }