]> git.proxmox.com Git - mirror_frr.git/blame - vtysh/vtysh_config.c
*: split & distribute memtypes and stop (re|ab)using lib/ MTYPEs
[mirror_frr.git] / vtysh / vtysh_config.c
CommitLineData
718e3744 1/* 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"
88177fe3 28#include "vtysh/vtysh_user.h"
718e3744 29
4a1ab8e4
DL
30DEFINE_MGROUP(MVTYSH, "vtysh")
31DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CONFIG, "Vtysh configuration")
32DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CONFIG_LINE, "Vtysh configuration line")
33
718e3744 34vector configvec;
35
e7168df4 36extern int vtysh_writeconfig_integrated;
37
718e3744 38struct config
39{
40 /* Configuration node name. */
41 char *name;
42
43 /* Configuration string line. */
44 struct list *line;
45
46 /* Configuration can be nest. */
47 struct config *config;
48
49 /* Index of this config. */
50 u_int32_t index;
51};
52
53struct list *config_top;
95e735b5 54
4201dd11 55static int
718e3744 56line_cmp (char *c1, char *c2)
57{
58 return strcmp (c1, c2);
59}
60
4201dd11 61static void
718e3744 62line_del (char *line)
63{
64 XFREE (MTYPE_VTYSH_CONFIG_LINE, line);
65}
66
4201dd11 67static struct config *
35dece84 68config_new (void)
718e3744 69{
70 struct config *config;
71 config = XCALLOC (MTYPE_VTYSH_CONFIG, sizeof (struct config));
72 return config;
73}
74
4201dd11 75static int
718e3744 76config_cmp (struct config *c1, struct config *c2)
77{
78 return strcmp (c1->name, c2->name);
79}
80
4201dd11 81static void
718e3744 82config_del (struct config* config)
83{
84 list_delete (config->line);
85 if (config->name)
86 XFREE (MTYPE_VTYSH_CONFIG_LINE, config->name);
87 XFREE (MTYPE_VTYSH_CONFIG, config);
88}
89
4201dd11 90static struct config *
dda09522 91config_get (int index, const char *line)
718e3744 92{
93 struct config *config;
94 struct config *config_loop;
95 struct list *master;
1eb8ef25 96 struct listnode *node, *nnode;
718e3744 97
98 config = config_loop = NULL;
99
100 master = vector_lookup_ensure (configvec, index);
101
102 if (! master)
103 {
104 master = list_new ();
105 master->del = (void (*) (void *))config_del;
106 master->cmp = (int (*)(void *, void *)) config_cmp;
107 vector_set_index (configvec, index, master);
108 }
109
1eb8ef25 110 for (ALL_LIST_ELEMENTS (master, node, nnode, config_loop))
718e3744 111 {
112 if (strcmp (config_loop->name, line) == 0)
113 config = config_loop;
114 }
115
116 if (! config)
117 {
118 config = config_new ();
119 config->line = list_new ();
120 config->line->del = (void (*) (void *))line_del;
121 config->line->cmp = (int (*)(void *, void *)) line_cmp;
122 config->name = XSTRDUP (MTYPE_VTYSH_CONFIG_LINE, line);
123 config->index = index;
124 listnode_add (master, config);
125 }
126 return config;
127}
128
129void
dda09522 130config_add_line (struct list *config, const char *line)
718e3744 131{
132 listnode_add (config, XSTRDUP (MTYPE_VTYSH_CONFIG_LINE, line));
133}
134
4201dd11 135static void
dda09522 136config_add_line_uniq (struct list *config, const char *line)
718e3744 137{
1eb8ef25 138 struct listnode *node, *nnode;
718e3744 139 char *pnt;
140
1eb8ef25 141 for (ALL_LIST_ELEMENTS (config, node, nnode, pnt))
718e3744 142 {
143 if (strcmp (pnt, line) == 0)
144 return;
145 }
146 listnode_add_sort (config, XSTRDUP (MTYPE_VTYSH_CONFIG_LINE, line));
147}
148
4201dd11 149static void
dda09522 150vtysh_config_parse_line (const char *line)
718e3744 151{
152 char c;
153 static struct config *config = NULL;
154
155 if (! line)
156 return;
157
158 c = line[0];
159
160 if (c == '\0')
161 return;
162
163 /* printf ("[%s]\n", line); */
164
165 switch (c)
166 {
0b960b4d
DW
167 /* Suppress exclamation points ! and commented lines. The !s are generated
168 * dynamically in vtysh_config_dump() */
718e3744 169 case '!':
170 case '#':
171 break;
172 case ' ':
173 /* Store line to current configuration. */
174 if (config)
175 {
e9d94ea7 176 if (config->index == RMAP_NODE ||
e7168df4 177 config->index == INTERFACE_NODE ||
13460c44 178 config->index == NS_NODE ||
e9d94ea7 179 config->index == VRF_NODE ||
e7168df4 180 config->index == VTY_NODE)
718e3744 181 config_add_line_uniq (config->line, line);
182 else
183 config_add_line (config->line, line);
184 }
185 else
186 config_add_line (config_top, line);
187 break;
188 default:
189 if (strncmp (line, "interface", strlen ("interface")) == 0)
190 config = config_get (INTERFACE_NODE, line);
c253dcb5 191 else if (strncmp (line, "logical-router", strlen ("ns")) == 0)
13460c44 192 config = config_get (NS_NODE, line);
e9d94ea7
DS
193 else if (strncmp (line, "vrf", strlen ("vrf")) == 0)
194 config = config_get (VRF_NODE, line);
dfbb9124 195 else if (strncmp (line, "router-id", strlen ("router-id")) == 0)
196 config = config_get (ZEBRA_NODE, line);
718e3744 197 else if (strncmp (line, "router rip", strlen ("router rip")) == 0)
198 config = config_get (RIP_NODE, line);
97e1c4dc 199 else if (strncmp (line, "router ripng", strlen ("router ripng")) == 0)
b094d260 200 config = config_get (RIPNG_NODE, line);
718e3744 201 else if (strncmp (line, "router ospf", strlen ("router ospf")) == 0)
b094d260 202 config = config_get (OSPF_NODE, line);
97e1c4dc 203 else if (strncmp (line, "router ospf6", strlen ("router ospf6")) == 0)
b094d260 204 config = config_get (OSPF6_NODE, line);
718e3744 205 else if (strncmp (line, "router bgp", strlen ("router bgp")) == 0)
206 config = config_get (BGP_NODE, line);
13b8baad 207 else if (strncmp (line, "router isis", strlen ("router isis")) == 0)
c25e458a 208 config = config_get (ISIS_NODE, line);
718e3744 209 else if (strncmp (line, "route-map", strlen ("route-map")) == 0)
210 config = config_get (RMAP_NODE, line);
211 else if (strncmp (line, "access-list", strlen ("access-list")) == 0)
212 config = config_get (ACCESS_NODE, line);
95e735b5 213 else if (strncmp (line, "ipv6 access-list",
214 strlen ("ipv6 access-list")) == 0)
b094d260 215 config = config_get (ACCESS_IPV6_NODE, line);
95e735b5 216 else if (strncmp (line, "ip prefix-list",
217 strlen ("ip prefix-list")) == 0)
718e3744 218 config = config_get (PREFIX_NODE, line);
95e735b5 219 else if (strncmp (line, "ipv6 prefix-list",
220 strlen ("ipv6 prefix-list")) == 0)
b094d260 221 config = config_get (PREFIX_IPV6_NODE, line);
95e735b5 222 else if (strncmp (line, "ip as-path access-list",
223 strlen ("ip as-path access-list")) == 0)
718e3744 224 config = config_get (AS_LIST_NODE, line);
eb2674af
DW
225 else if (strncmp (line, "ip community-list", strlen ("ip community-list")) == 0 ||
226 strncmp (line, "ip extcommunity-list", strlen ("ip extcommunity-list")) == 0)
718e3744 227 config = config_get (COMMUNITY_LIST_NODE, line);
228 else if (strncmp (line, "ip route", strlen ("ip route")) == 0)
229 config = config_get (IP_NODE, line);
97e1c4dc 230 else if (strncmp (line, "ipv6 route", strlen ("ipv6 route")) == 0)
231 config = config_get (IP_NODE, line);
718e3744 232 else if (strncmp (line, "key", strlen ("key")) == 0)
233 config = config_get (KEYCHAIN_NODE, line);
e7168df4 234 else if (strncmp (line, "line", strlen ("line")) == 0)
235 config = config_get (VTY_NODE, line);
236 else if ( (strncmp (line, "ipv6 forwarding",
237 strlen ("ipv6 forwarding")) == 0)
238 || (strncmp (line, "ip forwarding",
239 strlen ("ip forwarding")) == 0) )
240 config = config_get (FORWARDING_NODE, line);
241 else if (strncmp (line, "service", strlen ("service")) == 0)
242 config = config_get (SERVICE_NODE, line);
19dc275e
DS
243 else if (strncmp (line, "debug vrf", strlen ("debug vrf")) == 0)
244 config = config_get (VRF_DEBUG_NODE, line);
dfbb9124 245 else if (strncmp (line, "debug", strlen ("debug")) == 0)
246 config = config_get (DEBUG_NODE, line);
060d438c 247 else if (strncmp (line, "password", strlen ("password")) == 0
248 || strncmp (line, "enable password",
249 strlen ("enable password")) == 0)
250 config = config_get (AAA_NODE, line);
6e79f8bb
CC
251 else if (strncmp (line, "ip protocol", strlen ("ip protocol")) == 0)
252 config = config_get (PROTOCOL_NODE, line);
80b55c57 253 else if (strncmp (line, "ipv6 protocol", strlen ("ipv6 protocol")) == 0)
254 config = config_get (PROTOCOL_NODE, line);
255 else if (strncmp (line, "ip nht", strlen ("ip nht")) == 0)
256 config = config_get (PROTOCOL_NODE, line);
257 else if (strncmp (line, "ipv6 nht", strlen ("ipv6 nht")) == 0)
258 config = config_get (PROTOCOL_NODE, line);
718e3744 259 else
260 {
261 if (strncmp (line, "log", strlen ("log")) == 0
262 || strncmp (line, "hostname", strlen ("hostname")) == 0
e7168df4 263 )
718e3744 264 config_add_line_uniq (config_top, line);
265 else
266 config_add_line (config_top, line);
267 config = NULL;
268 }
269 break;
270 }
271}
272
273void
274vtysh_config_parse (char *line)
275{
276 char *begin;
277 char *pnt;
278
279 begin = pnt = line;
280
281 while (*pnt != '\0')
282 {
283 if (*pnt == '\n')
284 {
285 *pnt++ = '\0';
286 vtysh_config_parse_line (begin);
287 begin = pnt;
288 }
289 else
290 {
291 pnt++;
292 }
293 }
294}
295
296/* Macro to check delimiter is needed between each configuration line
95e735b5 297 * or not. */
718e3744 298#define NO_DELIMITER(I) \
299 ((I) == ACCESS_NODE || (I) == PREFIX_NODE || (I) == IP_NODE \
97e1c4dc 300 || (I) == AS_LIST_NODE || (I) == COMMUNITY_LIST_NODE || \
e7168df4 301 (I) == ACCESS_IPV6_NODE || (I) == PREFIX_IPV6_NODE \
060d438c 302 || (I) == SERVICE_NODE || (I) == FORWARDING_NODE || (I) == DEBUG_NODE \
19dc275e 303 || (I) == AAA_NODE || (I) == VRF_DEBUG_NODE)
718e3744 304
95e735b5 305/* Display configuration to file pointer. */
718e3744 306void
307vtysh_config_dump (FILE *fp)
308{
1eb8ef25 309 struct listnode *node, *nnode;
310 struct listnode *mnode, *mnnode;
718e3744 311 struct config *config;
312 struct list *master;
313 char *line;
dda09522 314 unsigned int i;
718e3744 315
1eb8ef25 316 for (ALL_LIST_ELEMENTS (config_top, node, nnode, line))
718e3744 317 {
318 fprintf (fp, "%s\n", line);
319 fflush (fp);
320 }
321 fprintf (fp, "!\n");
322 fflush (fp);
323
55468c86 324 for (i = 0; i < vector_active (configvec); i++)
718e3744 325 if ((master = vector_slot (configvec, i)) != NULL)
326 {
1eb8ef25 327 for (ALL_LIST_ELEMENTS (master, node, nnode, config))
5be7afc8
DD
328 {
329 /* Don't print empty sections for interface/vrf. Route maps on the
330 * other hand could have a legitimate empty section at the end.
331 */
332 if ((config->index == INTERFACE_NODE || (config->index == VRF_NODE))
333 && list_isempty (config->line))
334 continue;
335
718e3744 336 fprintf (fp, "%s\n", config->name);
b094d260 337 fflush (fp);
718e3744 338
1eb8ef25 339 for (ALL_LIST_ELEMENTS (config->line, mnode, mnnode, line))
718e3744 340 {
341 fprintf (fp, "%s\n", line);
342 fflush (fp);
343 }
344 if (! NO_DELIMITER (i))
345 {
346 fprintf (fp, "!\n");
347 fflush (fp);
348 }
349 }
350 if (NO_DELIMITER (i))
351 {
352 fprintf (fp, "!\n");
353 fflush (fp);
354 }
355 }
356
55468c86 357 for (i = 0; i < vector_active (configvec); i++)
718e3744 358 if ((master = vector_slot (configvec, i)) != NULL)
359 {
360 list_delete (master);
361 vector_slot (configvec, i) = NULL;
362 }
363 list_delete_all_node (config_top);
364}
365
366/* Read up configuration file from file_name. */
3221dca8 367static int
718e3744 368vtysh_read_file (FILE *confp)
369{
718e3744 370 struct vty *vty;
3221dca8 371 int ret;
718e3744 372
373 vty = vty_new ();
374 vty->fd = 0; /* stdout */
375 vty->type = VTY_TERM;
376 vty->node = CONFIG_NODE;
377
378 vtysh_execute_no_pager ("enable");
379 vtysh_execute_no_pager ("configure terminal");
380
95e735b5 381 /* Execute configuration file. */
3221dca8 382 ret = vtysh_config_from_file (vty, confp);
718e3744 383
384 vtysh_execute_no_pager ("end");
385 vtysh_execute_no_pager ("disable");
386
387 vty_close (vty);
3221dca8
DS
388
389 return (ret);
718e3744 390}
391
e7168df4 392/* Read up configuration file from config_default_dir. */
393int
c0e8c16f 394vtysh_read_config (const char *config_default_dir)
718e3744 395{
718e3744 396 FILE *confp = NULL;
3221dca8 397 int ret;
718e3744 398
e4421165 399 host_config_set (config_default_dir);
e7168df4 400 confp = fopen (config_default_dir, "r");
401 if (confp == NULL)
1db63918
DS
402 {
403 fprintf (stderr, "%% Can't open configuration file %s due to '%s'.\n",
404 config_default_dir, safe_strerror (errno));
405 return (CMD_ERR_NO_FILE);
406 }
67e29abc 407
3221dca8 408 ret = vtysh_read_file (confp);
718e3744 409 fclose (confp);
410
3221dca8 411 return (ret);
718e3744 412}
413
e7168df4 414/* We don't write vtysh specific into file from vtysh. vtysh.conf should
415 * be edited by hand. So, we handle only "write terminal" case here and
416 * integrate vtysh specific conf with conf from daemons.
417 */
718e3744 418void
e7168df4 419vtysh_config_write ()
718e3744 420{
dda09522 421 char line[81];
718e3744 422 extern struct host host;
423
424 if (host.name)
e7168df4 425 {
426 sprintf (line, "hostname %s", host.name);
427 vtysh_config_parse_line(line);
428 }
f013eacd
DD
429 if (!vtysh_writeconfig_integrated)
430 vtysh_config_parse_line ("no service integrated-vtysh-config");
a7222276
DS
431
432 user_config_write ();
718e3744 433}
434
435void
436vtysh_config_init ()
437{
438 config_top = list_new ();
439 config_top->del = (void (*) (void *))line_del;
440 configvec = vector_init (1);
441}