]> git.proxmox.com Git - mirror_frr.git/blame - vtysh/vtysh_config.c
Merge pull request #8619 from donaldsharp/sharp_redistribute
[mirror_frr.git] / vtysh / vtysh_config.c
CommitLineData
718e3744 1/* Configuration generator.
896014f4
DL
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 along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
718e3744 20
21#include <zebra.h>
22
23#include "command.h"
24#include "linklist.h"
25#include "memory.h"
a7982412 26#include "typesafe.h"
718e3744 27
28#include "vtysh/vtysh.h"
88177fe3 29#include "vtysh/vtysh_user.h"
718e3744 30
bf8d3d6a
DL
31DEFINE_MGROUP(MVTYSH, "vtysh");
32DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CONFIG, "Vtysh configuration");
33DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CONFIG_LINE, "Vtysh configuration line");
4a1ab8e4 34
718e3744 35vector configvec;
36
703dc64c 37PREDECL_LIST(config_master);
ece0e6ef 38PREDECL_HASH(config_master_hash);
a7982412 39
d62a17ae 40struct config {
41 /* Configuration node name. */
42 char *name;
718e3744 43
d62a17ae 44 /* Configuration string line. */
45 struct list *line;
718e3744 46
d62a17ae 47 /* Configuration can be nest. */
48 struct config *config;
718e3744 49
d62a17ae 50 /* Index of this config. */
d7c0a89a 51 uint32_t index;
a7982412
JW
52
53 /* Node entry for the typed Red-black tree */
54 struct config_master_item rbt_item;
ece0e6ef 55 struct config_master_hash_item hash_item;
718e3744 56};
57
58struct list *config_top;
95e735b5 59
d62a17ae 60static int line_cmp(char *c1, char *c2)
718e3744 61{
d62a17ae 62 return strcmp(c1, c2);
718e3744 63}
64
d62a17ae 65static void line_del(char *line)
718e3744 66{
d62a17ae 67 XFREE(MTYPE_VTYSH_CONFIG_LINE, line);
718e3744 68}
69
d62a17ae 70static struct config *config_new(void)
718e3744 71{
d62a17ae 72 struct config *config;
73 config = XCALLOC(MTYPE_VTYSH_CONFIG, sizeof(struct config));
74 return config;
718e3744 75}
76
d62a17ae 77static void config_del(struct config *config)
718e3744 78{
6a154c88 79 list_delete(&config->line);
0a22ddfb 80 XFREE(MTYPE_VTYSH_CONFIG_LINE, config->name);
d62a17ae 81 XFREE(MTYPE_VTYSH_CONFIG, config);
718e3744 82}
83
ece0e6ef
DS
84static int config_cmp(const struct config *c1, const struct config *c2)
85{
86 return strcmp(c1->name, c2->name);
87}
88
89static uint32_t config_hash(const struct config *c)
90{
91 return string_hash_make(c->name);
92}
93
960b9a53 94DECLARE_LIST(config_master, struct config, rbt_item);
ece0e6ef 95DECLARE_HASH(config_master_hash, struct config, hash_item, config_cmp,
960b9a53 96 config_hash);
ece0e6ef
DS
97
98/*
99 * The config_master_head is a list for order of receipt
100 * The hash is for quick lookup under this NODE
101 */
102struct configuration {
103 struct config_master_head master;
104 struct config_master_hash_head hash_master;
105};
a7982412 106
d62a17ae 107static struct config *config_get(int index, const char *line)
718e3744 108{
703dc64c 109 struct config *config, *config_loop;
ece0e6ef
DS
110 struct configuration *configuration;
111 struct config lookup;
d62a17ae 112
703dc64c
DS
113 config = config_loop = NULL;
114
ece0e6ef 115 configuration = vector_lookup_ensure(configvec, index);
d62a17ae 116
ece0e6ef
DS
117 if (!configuration) {
118 configuration = XMALLOC(MTYPE_VTYSH_CONFIG,
119 sizeof(struct configuration));
120 config_master_init(&configuration->master);
121 config_master_hash_init(&configuration->hash_master);
122 vector_set_index(configvec, index, configuration);
d62a17ae 123 }
124
ece0e6ef
DS
125 lookup.name = (char *)line;
126 config = config_master_hash_find(&configuration->hash_master, &lookup);
d62a17ae 127
128 if (!config) {
129 config = config_new();
130 config->line = list_new();
131 config->line->del = (void (*)(void *))line_del;
132 config->line->cmp = (int (*)(void *, void *))line_cmp;
133 config->name = XSTRDUP(MTYPE_VTYSH_CONFIG_LINE, line);
134 config->index = index;
ece0e6ef
DS
135 config_master_add_tail(&configuration->master, config);
136 config_master_hash_add(&configuration->hash_master, config);
d62a17ae 137 }
138 return config;
718e3744 139}
140
d62a17ae 141void config_add_line(struct list *config, const char *line)
718e3744 142{
d62a17ae 143 listnode_add(config, XSTRDUP(MTYPE_VTYSH_CONFIG_LINE, line));
718e3744 144}
145
d62a17ae 146static void config_add_line_uniq(struct list *config, const char *line)
718e3744 147{
d62a17ae 148 struct listnode *node, *nnode;
149 char *pnt;
150
151 for (ALL_LIST_ELEMENTS(config, node, nnode, pnt)) {
152 if (strcmp(pnt, line) == 0)
153 return;
154 }
155 listnode_add_sort(config, XSTRDUP(MTYPE_VTYSH_CONFIG_LINE, line));
718e3744 156}
157
a3c1db5e 158/*
e8be380a
QY
159 * Add a line that should only be shown once, and always show at the end of the
160 * config block.
161 *
162 * If the line already exists, it will be moved to the end of the block. If it
163 * does not exist, it will be added at the end of the block.
164 *
165 * Note that this only makes sense when there is just one such line that should
166 * show up at the very end of a config block. Furthermore, if the same block
167 * can show up from multiple daemons, all of them must make sure to print the
168 * line at the end of their config, otherwise the line will show at the end of
169 * the config for the last daemon that printed it.
170 *
171 * Here is a motivating example with the 'exit-vrf' command. Suppose we receive
172 * a config from Zebra like so:
173 *
174 * vrf BLUE
175 * ip route A
176 * ip route B
177 * exit-vrf
178 *
179 * Then suppose we later receive this config from PIM:
180 *
181 * vrf BLUE
182 * ip msdp mesh-group MyGroup member 1.2.3.4
183 * exit-vrf
184 *
185 * Then we will combine them into one config block like so:
186 *
187 * vrf BLUE
188 * ip route A
189 * ip route B
190 * ip msdp mesh-group MyGroup member 1.2.3.4
191 * exit-vrf
192 *
193 * Because PIM also sent us an 'exit-vrf', we noticed that we already had one
194 * under the 'vrf BLUE' config block and so we moved it to the end of the
195 * config block again. If PIM had neglected to send us 'exit-vrf', the result
196 * would be this:
197 *
198 * vrf BLUE
199 * ip route A
200 * ip route B
201 * exit-vrf
202 * ip msdp mesh-group MyGroup member 1.2.3.4
203 *
204 * Therefore, daemons that share config blocks must take care to consistently
205 * print the same block terminators.
206 *
207 * Ideally this would be solved by adding a string to struct config that is
208 * always printed at the end when dumping a config. However, this would only
209 * work when the user is using integrated config. In the non-integrated config
210 * case, daemons are responsible for writing their own config files, and so the
211 * must be able to print these blocks correctly independently of vtysh, which
212 * means they are the ones that need to handle printing the block terminators
213 * and VTYSH needs to be smart enough to combine them properly.
214 *
215 * ---
216 *
217 * config
218 * The config to add the line to
219 *
220 * line
221 * The line to add to the end of the config
a3c1db5e 222 */
e8be380a 223static void config_add_line_uniq_end(struct list *config, const char *line)
a3c1db5e
DS
224{
225 struct listnode *node;
e8be380a 226 char *pnt;
a3c1db5e 227
e8be380a
QY
228 for (ALL_LIST_ELEMENTS_RO(config, node, pnt)) {
229 if (strcmp(pnt, line) == 0)
230 break;
231 }
232
233 if (!node)
234 config_add_line(config, line);
235 else
a3c1db5e
DS
236 listnode_move_to_tail(config, node);
237}
238
d62a17ae 239void vtysh_config_parse_line(void *arg, const char *line)
718e3744 240{
d62a17ae 241 char c;
242 static struct config *config = NULL;
243
244 if (!line)
245 return;
246
247 c = line[0];
248
249 if (c == '\0')
250 return;
251
d62a17ae 252 switch (c) {
253 /* Suppress exclamation points ! and commented lines. The !s are
254 * generated
255 * dynamically in vtysh_config_dump() */
256 case '!':
257 case '#':
258 break;
259 case ' ':
260 /* Store line to current configuration. */
261 if (config) {
262 if (strncmp(line, " link-params",
263 strlen(" link-params"))
264 == 0) {
265 config_add_line(config->line, line);
266 config->index = LINK_PARAMS_NODE;
996c9314
LB
267 } else if (strncmp(line, " ip multicast boundary",
268 strlen(" ip multicast boundary"))
269 == 0) {
e8be380a 270 config_add_line_uniq_end(config->line, line);
61a7a236
DS
271 } else if (strncmp(line, " ip igmp query-interval",
272 strlen(" ip igmp query-interval")) == 0) {
e8be380a 273 config_add_line_uniq_end(config->line, line);
d62a17ae 274 } else if (config->index == LINK_PARAMS_NODE
275 && strncmp(line, " exit-link-params",
276 strlen(" exit"))
277 == 0) {
278 config_add_line(config->line, line);
279 config->index = INTERFACE_NODE;
c319e19d
QY
280 } else if (config->index == VRF_NODE
281 && strncmp(line, " exit-vrf",
282 strlen(" exit-vrf"))
283 == 0) {
e8be380a 284 config_add_line_uniq_end(config->line, line);
18ca2e1f
QY
285 } else if (!strncmp(line, " vrrp", strlen(" vrrp"))
286 || !strncmp(line, " no vrrp",
287 strlen(" no vrrp"))) {
288 config_add_line(config->line, line);
c552f61e
DS
289 } else if (!strncmp(line, " ip mroute", strlen(" ip mroute"))) {
290 config_add_line_uniq_end(config->line, line);
d62a17ae 291 } else if (config->index == RMAP_NODE
292 || config->index == INTERFACE_NODE
d62a17ae 293 || config->index == VTY_NODE
3741c4ba
DS
294 || config->index == VRF_NODE
295 || config->index == NH_GROUP_NODE)
d62a17ae 296 config_add_line_uniq(config->line, line);
1d4cfa5d 297 else
d62a17ae 298 config_add_line(config->line, line);
299 } else
300 config_add_line(config_top, line);
301 break;
302 default:
303 if (strncmp(line, "interface", strlen("interface")) == 0)
304 config = config_get(INTERFACE_NODE, line);
2dd0d726
RW
305 else if (strncmp(line, "pseudowire", strlen("pseudowire")) == 0)
306 config = config_get(PW_NODE, line);
d62a17ae 307 else if (strncmp(line, "vrf", strlen("vrf")) == 0)
308 config = config_get(VRF_NODE, line);
e5c83d9b
DS
309 else if (strncmp(line, "nexthop-group", strlen("nexthop-group"))
310 == 0)
311 config = config_get(NH_GROUP_NODE, line);
d62a17ae 312 else if (strncmp(line, "router-id", strlen("router-id")) == 0)
313 config = config_get(ZEBRA_NODE, line);
314 else if (strncmp(line, "router rip", strlen("router rip")) == 0)
315 config = config_get(RIP_NODE, line);
316 else if (strncmp(line, "router ripng", strlen("router ripng"))
317 == 0)
318 config = config_get(RIPNG_NODE, line);
319 else if (strncmp(line, "router eigrp", strlen("router eigrp"))
320 == 0)
321 config = config_get(EIGRP_NODE, line);
322 else if (strncmp(line, "router babel", strlen("router babel"))
323 == 0)
324 config = config_get(BABEL_NODE, line);
325 else if (strncmp(line, "router ospf", strlen("router ospf"))
326 == 0)
327 config = config_get(OSPF_NODE, line);
328 else if (strncmp(line, "router ospf6", strlen("router ospf6"))
329 == 0)
330 config = config_get(OSPF6_NODE, line);
331 else if (strncmp(line, "mpls ldp", strlen("mpls ldp")) == 0)
332 config = config_get(LDP_NODE, line);
333 else if (strncmp(line, "l2vpn", strlen("l2vpn")) == 0)
334 config = config_get(LDP_L2VPN_NODE, line);
335 else if (strncmp(line, "router bgp", strlen("router bgp")) == 0)
336 config = config_get(BGP_NODE, line);
337 else if (strncmp(line, "router isis", strlen("router isis"))
338 == 0)
339 config = config_get(ISIS_NODE, line);
770ccdf8
CF
340 else if (strncmp(line, "router openfabric", strlen("router openfabric"))
341 == 0)
342 config = config_get(OPENFABRIC_NODE, line);
d62a17ae 343 else if (strncmp(line, "route-map", strlen("route-map")) == 0)
344 config = config_get(RMAP_NODE, line);
38133c4a
IR
345 else if (strncmp(line, "no route-map", strlen("no route-map"))
346 == 0)
347 config = config_get(RMAP_NODE, line);
e5c83d9b
DS
348 else if (strncmp(line, "pbr-map", strlen("pbr-map")) == 0)
349 config = config_get(PBRMAP_NODE, line);
d62a17ae 350 else if (strncmp(line, "access-list", strlen("access-list"))
351 == 0)
352 config = config_get(ACCESS_NODE, line);
353 else if (strncmp(line, "ipv6 access-list",
354 strlen("ipv6 access-list"))
355 == 0)
356 config = config_get(ACCESS_IPV6_NODE, line);
d37ba549
MK
357 else if (strncmp(line, "mac access-list",
358 strlen("mac access-list"))
359 == 0)
360 config = config_get(ACCESS_MAC_NODE, line);
d62a17ae 361 else if (strncmp(line, "ip prefix-list",
362 strlen("ip prefix-list"))
363 == 0)
364 config = config_get(PREFIX_NODE, line);
365 else if (strncmp(line, "ipv6 prefix-list",
366 strlen("ipv6 prefix-list"))
367 == 0)
368 config = config_get(PREFIX_IPV6_NODE, line);
7336e101
SP
369 else if (strncmp(line, "bgp as-path access-list",
370 strlen("bgp as-path access-list"))
d62a17ae 371 == 0)
372 config = config_get(AS_LIST_NODE, line);
7336e101
SP
373 else if (strncmp(line, "bgp community-list",
374 strlen("bgp community-list"))
d62a17ae 375 == 0
7336e101
SP
376 || strncmp(line, "bgp extcommunity-list",
377 strlen("bgp extcommunity-list"))
996c9314 378 == 0
7336e101
SP
379 || strncmp(line, "bgp large-community-list",
380 strlen("bgp large-community-list"))
996c9314 381 == 0)
d62a17ae 382 config = config_get(COMMUNITY_LIST_NODE, line);
383 else if (strncmp(line, "ip route", strlen("ip route")) == 0)
384 config = config_get(IP_NODE, line);
385 else if (strncmp(line, "ipv6 route", strlen("ipv6 route")) == 0)
386 config = config_get(IP_NODE, line);
387 else if (strncmp(line, "key", strlen("key")) == 0)
388 config = config_get(KEYCHAIN_NODE, line);
389 else if (strncmp(line, "line", strlen("line")) == 0)
390 config = config_get(VTY_NODE, line);
391 else if ((strncmp(line, "ipv6 forwarding",
392 strlen("ipv6 forwarding"))
393 == 0)
394 || (strncmp(line, "ip forwarding",
395 strlen("ip forwarding"))
396 == 0))
397 config = config_get(FORWARDING_NODE, line);
d62a17ae 398 else if (strncmp(line, "debug vrf", strlen("debug vrf")) == 0)
399 config = config_get(VRF_DEBUG_NODE, line);
1c2facd1
RW
400 else if (strncmp(line, "debug northbound",
401 strlen("debug northbound"))
402 == 0)
403 config = config_get(NORTHBOUND_DEBUG_NODE, line);
e3ab8170
AD
404 else if (strncmp(line, "debug route-map",
405 strlen("debug route-map"))
406 == 0)
407 config = config_get(RMAP_DEBUG_NODE, line);
fe9e7b71
DL
408 else if (strncmp(line, "debug resolver",
409 strlen("debug resolver")) == 0)
410 config = config_get(RESOLVER_DEBUG_NODE, line);
d62a17ae 411 else if (strncmp(line, "debug", strlen("debug")) == 0)
412 config = config_get(DEBUG_NODE, line);
413 else if (strncmp(line, "password", strlen("password")) == 0
414 || strncmp(line, "enable password",
415 strlen("enable password"))
416 == 0)
417 config = config_get(AAA_NODE, line);
418 else if (strncmp(line, "ip protocol", strlen("ip protocol"))
419 == 0)
420 config = config_get(PROTOCOL_NODE, line);
421 else if (strncmp(line, "ipv6 protocol", strlen("ipv6 protocol"))
422 == 0)
423 config = config_get(PROTOCOL_NODE, line);
424 else if (strncmp(line, "ip nht", strlen("ip nht")) == 0)
425 config = config_get(PROTOCOL_NODE, line);
426 else if (strncmp(line, "ipv6 nht", strlen("ipv6 nht")) == 0)
427 config = config_get(PROTOCOL_NODE, line);
428 else if (strncmp(line, "mpls", strlen("mpls")) == 0)
429 config = config_get(MPLS_NODE, line);
c2f29cf3
RZ
430 else if (strncmp(line, "bfd", strlen("bfd")) == 0)
431 config = config_get(BFD_NODE, line);
d62a17ae 432 else {
433 if (strncmp(line, "log", strlen("log")) == 0
cf8c3965
IR
434 || strncmp(line, "hostname", strlen("hostname")) == 0
435 || strncmp(line, "domainname", strlen("domainname")) == 0
d62a17ae 436 || strncmp(line, "frr", strlen("frr")) == 0
437 || strncmp(line, "agentx", strlen("agentx")) == 0
c0e83672
IR
438 || strncmp(line, "no log", strlen("no log")) == 0
439 || strncmp(line, "no ip prefix-list", strlen("no ip prefix-list")) == 0
440 || strncmp(line, "no ipv6 prefix-list", strlen("no ipv6 prefix-list")) == 0)
d62a17ae 441 config_add_line_uniq(config_top, line);
442 else
443 config_add_line(config_top, line);
444 config = NULL;
445 }
446 break;
718e3744 447 }
718e3744 448}
449
718e3744 450/* Macro to check delimiter is needed between each configuration line
95e735b5 451 * or not. */
d62a17ae 452#define NO_DELIMITER(I) \
453 ((I) == ACCESS_NODE || (I) == PREFIX_NODE || (I) == IP_NODE \
454 || (I) == AS_LIST_NODE || (I) == COMMUNITY_LIST_NODE \
d37ba549 455 || (I) == ACCESS_IPV6_NODE || (I) == ACCESS_MAC_NODE \
f108d487
QY
456 || (I) == PREFIX_IPV6_NODE || (I) == FORWARDING_NODE \
457 || (I) == DEBUG_NODE || (I) == AAA_NODE || (I) == VRF_DEBUG_NODE \
e3ab8170 458 || (I) == NORTHBOUND_DEBUG_NODE || (I) == RMAP_DEBUG_NODE \
fe9e7b71 459 || (I) == RESOLVER_DEBUG_NODE || (I) == MPLS_NODE)
718e3744 460
95e735b5 461/* Display configuration to file pointer. */
0a334343 462void vtysh_config_dump(void)
718e3744 463{
d62a17ae 464 struct listnode *node, *nnode;
465 struct listnode *mnode, *mnnode;
466 struct config *config;
ece0e6ef 467 struct configuration *configuration;
d62a17ae 468 char *line;
469 unsigned int i;
470
2cddf2ff
QY
471 for (ALL_LIST_ELEMENTS(config_top, node, nnode, line))
472 vty_out(vty, "%s\n", line);
473
474 vty_out(vty, "!\n");
d62a17ae 475
476 for (i = 0; i < vector_active(configvec); i++)
ece0e6ef
DS
477 if ((configuration = vector_slot(configvec, i)) != NULL) {
478 while ((config = config_master_pop(
479 &configuration->master))) {
480 config_master_hash_del(
481 &configuration->hash_master, config);
1d72e48a 482 /* Don't print empty sections for interface.
d62a17ae 483 * Route maps on the
484 * other hand could have a legitimate empty
485 * section at the end.
1d72e48a 486 * VRF is handled in the backend, we could have
487 * "configured" VRFs with static routes which
488 * are not under the VRF node.
d62a17ae 489 */
1d72e48a 490 if (config->index == INTERFACE_NODE
40ab4111
IR
491 && list_isempty(config->line)) {
492 config_del(config);
d62a17ae 493 continue;
40ab4111 494 }
d62a17ae 495
2cddf2ff 496 vty_out(vty, "%s\n", config->name);
d62a17ae 497
498 for (ALL_LIST_ELEMENTS(config->line, mnode,
2cddf2ff
QY
499 mnnode, line))
500 vty_out(vty, "%s\n", line);
501 if (!NO_DELIMITER(i))
502 vty_out(vty, "!\n");
a7982412
JW
503
504 config_del(config);
d62a17ae 505 }
2cddf2ff
QY
506 if (NO_DELIMITER(i))
507 vty_out(vty, "!\n");
d62a17ae 508 }
509
510 for (i = 0; i < vector_active(configvec); i++)
ece0e6ef
DS
511 if ((configuration = vector_slot(configvec, i)) != NULL) {
512 config_master_fini(&configuration->master);
513 config_master_hash_fini(&configuration->hash_master);
514 XFREE(MTYPE_VTYSH_CONFIG, configuration);
d62a17ae 515 vector_slot(configvec, i) = NULL;
516 }
517 list_delete_all_node(config_top);
718e3744 518}
519
520/* Read up configuration file from file_name. */
77f7b4b0 521static int vtysh_read_file(FILE *confp, bool dry_run)
718e3744 522{
d62a17ae 523 struct vty *vty;
524 int ret;
525
526 vty = vty_new();
4a9746fd 527 vty->wfd = STDERR_FILENO;
d62a17ae 528 vty->type = VTY_TERM;
529 vty->node = CONFIG_NODE;
718e3744 530
d62a17ae 531 vtysh_execute_no_pager("enable");
532 vtysh_execute_no_pager("configure terminal");
718e3744 533
77f7b4b0
DS
534 if (!dry_run)
535 vtysh_execute_no_pager("XFRR_start_configuration");
f8e6ada8 536
d62a17ae 537 /* Execute configuration file. */
538 ret = vtysh_config_from_file(vty, confp);
718e3744 539
77f7b4b0
DS
540 if (!dry_run)
541 vtysh_execute_no_pager("XFRR_end_configuration");
f8e6ada8 542
d62a17ae 543 vtysh_execute_no_pager("end");
544 vtysh_execute_no_pager("disable");
718e3744 545
d62a17ae 546 vty_close(vty);
3221dca8 547
d62a17ae 548 return (ret);
718e3744 549}
550
e7168df4 551/* Read up configuration file from config_default_dir. */
77f7b4b0 552int vtysh_read_config(const char *config_default_dir, bool dry_run)
718e3744 553{
d62a17ae 554 FILE *confp = NULL;
555 int ret;
556
557 confp = fopen(config_default_dir, "r");
558 if (confp == NULL) {
559 fprintf(stderr,
560 "%% Can't open configuration file %s due to '%s'.\n",
561 config_default_dir, safe_strerror(errno));
95f7965d 562 return CMD_ERR_NO_FILE;
d62a17ae 563 }
67e29abc 564
77f7b4b0 565 ret = vtysh_read_file(confp, dry_run);
d62a17ae 566 fclose(confp);
718e3744 567
d62a17ae 568 return (ret);
718e3744 569}
570
e7168df4 571/* We don't write vtysh specific into file from vtysh. vtysh.conf should
572 * be edited by hand. So, we handle only "write terminal" case here and
573 * integrate vtysh specific conf with conf from daemons.
574 */
4d762f26 575void vtysh_config_write(void)
718e3744 576{
63e653a2 577 char line[512];
d62a17ae 578
6b3ee3a0 579 if (cmd_hostname_get()) {
63e653a2 580 snprintf(line, sizeof(line), "hostname %s", cmd_hostname_get());
d62a17ae 581 vtysh_config_parse_line(NULL, line);
582 }
3b103fec
MK
583
584 if (cmd_domainname_get()) {
772270f3
QY
585 snprintf(line, sizeof(line), "domainname %s",
586 cmd_domainname_get());
3b103fec
MK
587 vtysh_config_parse_line(NULL, line);
588 }
d62a17ae 589 if (vtysh_write_integrated == WRITE_INTEGRATED_NO)
590 vtysh_config_parse_line(NULL,
591 "no service integrated-vtysh-config");
592 if (vtysh_write_integrated == WRITE_INTEGRATED_YES)
593 vtysh_config_parse_line(NULL,
594 "service integrated-vtysh-config");
595
596 user_config_write();
718e3744 597}
598
4d762f26 599void vtysh_config_init(void)
718e3744 600{
d62a17ae 601 config_top = list_new();
602 config_top->del = (void (*)(void *))line_del;
603 configvec = vector_init(1);
718e3744 604}