]> git.proxmox.com Git - mirror_frr.git/blame - vtysh/vtysh_config.c
tests: clean up all_proto_startup a bit
[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
07679ad9
IR
275 && strncmp(line, " exit-link-params",
276 strlen(" exit"))
d62a17ae 277 == 0) {
278 config_add_line(config->line, line);
279 config->index = INTERFACE_NODE;
18ca2e1f
QY
280 } else if (!strncmp(line, " vrrp", strlen(" vrrp"))
281 || !strncmp(line, " no vrrp",
282 strlen(" no vrrp"))) {
283 config_add_line(config->line, line);
c552f61e
DS
284 } else if (!strncmp(line, " ip mroute", strlen(" ip mroute"))) {
285 config_add_line_uniq_end(config->line, line);
d62a17ae 286 } else if (config->index == RMAP_NODE
287 || config->index == INTERFACE_NODE
d62a17ae 288 || config->index == VTY_NODE
3741c4ba 289 || config->index == NH_GROUP_NODE)
d62a17ae 290 config_add_line_uniq(config->line, line);
1d4cfa5d 291 else
d62a17ae 292 config_add_line(config->line, line);
293 } else
294 config_add_line(config_top, line);
295 break;
296 default:
07679ad9
IR
297 if (strncmp(line, "exit", strlen("exit")) == 0) {
298 if (config)
299 config_add_line_uniq_end(config->line, line);
300 } else if (strncmp(line, "interface", strlen("interface")) == 0)
d62a17ae 301 config = config_get(INTERFACE_NODE, line);
2dd0d726
RW
302 else if (strncmp(line, "pseudowire", strlen("pseudowire")) == 0)
303 config = config_get(PW_NODE, line);
d62a17ae 304 else if (strncmp(line, "vrf", strlen("vrf")) == 0)
305 config = config_get(VRF_NODE, line);
e5c83d9b
DS
306 else if (strncmp(line, "nexthop-group", strlen("nexthop-group"))
307 == 0)
308 config = config_get(NH_GROUP_NODE, line);
d62a17ae 309 else if (strncmp(line, "router-id", strlen("router-id")) == 0)
310 config = config_get(ZEBRA_NODE, line);
311 else if (strncmp(line, "router rip", strlen("router rip")) == 0)
312 config = config_get(RIP_NODE, line);
313 else if (strncmp(line, "router ripng", strlen("router ripng"))
314 == 0)
315 config = config_get(RIPNG_NODE, line);
316 else if (strncmp(line, "router eigrp", strlen("router eigrp"))
317 == 0)
318 config = config_get(EIGRP_NODE, line);
319 else if (strncmp(line, "router babel", strlen("router babel"))
320 == 0)
321 config = config_get(BABEL_NODE, line);
322 else if (strncmp(line, "router ospf", strlen("router ospf"))
323 == 0)
324 config = config_get(OSPF_NODE, line);
325 else if (strncmp(line, "router ospf6", strlen("router ospf6"))
326 == 0)
327 config = config_get(OSPF6_NODE, line);
328 else if (strncmp(line, "mpls ldp", strlen("mpls ldp")) == 0)
329 config = config_get(LDP_NODE, line);
330 else if (strncmp(line, "l2vpn", strlen("l2vpn")) == 0)
331 config = config_get(LDP_L2VPN_NODE, line);
332 else if (strncmp(line, "router bgp", strlen("router bgp")) == 0)
333 config = config_get(BGP_NODE, line);
334 else if (strncmp(line, "router isis", strlen("router isis"))
335 == 0)
336 config = config_get(ISIS_NODE, line);
770ccdf8
CF
337 else if (strncmp(line, "router openfabric", strlen("router openfabric"))
338 == 0)
339 config = config_get(OPENFABRIC_NODE, line);
d62a17ae 340 else if (strncmp(line, "route-map", strlen("route-map")) == 0)
341 config = config_get(RMAP_NODE, line);
38133c4a
IR
342 else if (strncmp(line, "no route-map", strlen("no route-map"))
343 == 0)
344 config = config_get(RMAP_NODE, line);
e5c83d9b
DS
345 else if (strncmp(line, "pbr-map", strlen("pbr-map")) == 0)
346 config = config_get(PBRMAP_NODE, line);
d62a17ae 347 else if (strncmp(line, "access-list", strlen("access-list"))
348 == 0)
349 config = config_get(ACCESS_NODE, line);
350 else if (strncmp(line, "ipv6 access-list",
351 strlen("ipv6 access-list"))
352 == 0)
353 config = config_get(ACCESS_IPV6_NODE, line);
d37ba549
MK
354 else if (strncmp(line, "mac access-list",
355 strlen("mac access-list"))
356 == 0)
357 config = config_get(ACCESS_MAC_NODE, line);
d62a17ae 358 else if (strncmp(line, "ip prefix-list",
359 strlen("ip prefix-list"))
360 == 0)
361 config = config_get(PREFIX_NODE, line);
362 else if (strncmp(line, "ipv6 prefix-list",
363 strlen("ipv6 prefix-list"))
364 == 0)
365 config = config_get(PREFIX_IPV6_NODE, line);
7336e101
SP
366 else if (strncmp(line, "bgp as-path access-list",
367 strlen("bgp as-path access-list"))
d62a17ae 368 == 0)
369 config = config_get(AS_LIST_NODE, line);
7336e101
SP
370 else if (strncmp(line, "bgp community-list",
371 strlen("bgp community-list"))
d62a17ae 372 == 0
7336e101
SP
373 || strncmp(line, "bgp extcommunity-list",
374 strlen("bgp extcommunity-list"))
996c9314 375 == 0
7336e101
SP
376 || strncmp(line, "bgp large-community-list",
377 strlen("bgp large-community-list"))
996c9314 378 == 0)
d62a17ae 379 config = config_get(COMMUNITY_LIST_NODE, line);
ed0e57e3
DA
380 else if (strncmp(line, "bgp community alias",
381 strlen("bgp community alias")) == 0)
382 config = config_get(COMMUNITY_ALIAS_NODE, line);
d62a17ae 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);
6c0a7c09
HS
430 else if (strncmp(line, "segment-routing",
431 strlen("segment-routing"))
432 == 0)
433 config = config_get(SEGMENT_ROUTING_NODE, line);
c2f29cf3
RZ
434 else if (strncmp(line, "bfd", strlen("bfd")) == 0)
435 config = config_get(BFD_NODE, line);
d62a17ae 436 else {
437 if (strncmp(line, "log", strlen("log")) == 0
cf8c3965
IR
438 || strncmp(line, "hostname", strlen("hostname")) == 0
439 || strncmp(line, "domainname", strlen("domainname")) == 0
d62a17ae 440 || strncmp(line, "frr", strlen("frr")) == 0
441 || strncmp(line, "agentx", strlen("agentx")) == 0
c0e83672
IR
442 || strncmp(line, "no log", strlen("no log")) == 0
443 || strncmp(line, "no ip prefix-list", strlen("no ip prefix-list")) == 0
444 || strncmp(line, "no ipv6 prefix-list", strlen("no ipv6 prefix-list")) == 0)
d62a17ae 445 config_add_line_uniq(config_top, line);
446 else
447 config_add_line(config_top, line);
448 config = NULL;
449 }
450 break;
718e3744 451 }
718e3744 452}
453
718e3744 454/* Macro to check delimiter is needed between each configuration line
95e735b5 455 * or not. */
d62a17ae 456#define NO_DELIMITER(I) \
457 ((I) == ACCESS_NODE || (I) == PREFIX_NODE || (I) == IP_NODE \
458 || (I) == AS_LIST_NODE || (I) == COMMUNITY_LIST_NODE \
ed0e57e3
DA
459 || (I) == COMMUNITY_ALIAS_NODE || (I) == ACCESS_IPV6_NODE \
460 || (I) == ACCESS_MAC_NODE || (I) == PREFIX_IPV6_NODE \
461 || (I) == FORWARDING_NODE || (I) == DEBUG_NODE || (I) == AAA_NODE \
462 || (I) == VRF_DEBUG_NODE || (I) == NORTHBOUND_DEBUG_NODE \
463 || (I) == RMAP_DEBUG_NODE || (I) == RESOLVER_DEBUG_NODE \
464 || (I) == MPLS_NODE)
718e3744 465
95e735b5 466/* Display configuration to file pointer. */
0a334343 467void vtysh_config_dump(void)
718e3744 468{
d62a17ae 469 struct listnode *node, *nnode;
470 struct listnode *mnode, *mnnode;
471 struct config *config;
ece0e6ef 472 struct configuration *configuration;
d62a17ae 473 char *line;
474 unsigned int i;
475
2cddf2ff
QY
476 for (ALL_LIST_ELEMENTS(config_top, node, nnode, line))
477 vty_out(vty, "%s\n", line);
478
479 vty_out(vty, "!\n");
d62a17ae 480
481 for (i = 0; i < vector_active(configvec); i++)
ece0e6ef
DS
482 if ((configuration = vector_slot(configvec, i)) != NULL) {
483 while ((config = config_master_pop(
484 &configuration->master))) {
485 config_master_hash_del(
486 &configuration->hash_master, config);
1d72e48a 487 /* Don't print empty sections for interface.
d62a17ae 488 * Route maps on the
489 * other hand could have a legitimate empty
490 * section at the end.
1d72e48a 491 * VRF is handled in the backend, we could have
492 * "configured" VRFs with static routes which
493 * are not under the VRF node.
d62a17ae 494 */
1d72e48a 495 if (config->index == INTERFACE_NODE
07679ad9
IR
496 && (listcount(config->line) == 1)
497 && (line = listnode_head(config->line))
498 && strmatch(line, "exit")) {
40ab4111 499 config_del(config);
d62a17ae 500 continue;
40ab4111 501 }
d62a17ae 502
2cddf2ff 503 vty_out(vty, "%s\n", config->name);
d62a17ae 504
505 for (ALL_LIST_ELEMENTS(config->line, mnode,
2cddf2ff
QY
506 mnnode, line))
507 vty_out(vty, "%s\n", line);
508 if (!NO_DELIMITER(i))
509 vty_out(vty, "!\n");
a7982412
JW
510
511 config_del(config);
d62a17ae 512 }
2cddf2ff
QY
513 if (NO_DELIMITER(i))
514 vty_out(vty, "!\n");
d62a17ae 515 }
516
517 for (i = 0; i < vector_active(configvec); i++)
ece0e6ef
DS
518 if ((configuration = vector_slot(configvec, i)) != NULL) {
519 config_master_fini(&configuration->master);
520 config_master_hash_fini(&configuration->hash_master);
521 XFREE(MTYPE_VTYSH_CONFIG, configuration);
d62a17ae 522 vector_slot(configvec, i) = NULL;
523 }
524 list_delete_all_node(config_top);
718e3744 525}
526
527/* Read up configuration file from file_name. */
77f7b4b0 528static int vtysh_read_file(FILE *confp, bool dry_run)
718e3744 529{
d62a17ae 530 struct vty *vty;
531 int ret;
532
533 vty = vty_new();
4a9746fd 534 vty->wfd = STDERR_FILENO;
d62a17ae 535 vty->type = VTY_TERM;
536 vty->node = CONFIG_NODE;
718e3744 537
d62a17ae 538 vtysh_execute_no_pager("enable");
539 vtysh_execute_no_pager("configure terminal");
718e3744 540
77f7b4b0
DS
541 if (!dry_run)
542 vtysh_execute_no_pager("XFRR_start_configuration");
f8e6ada8 543
d62a17ae 544 /* Execute configuration file. */
545 ret = vtysh_config_from_file(vty, confp);
718e3744 546
77f7b4b0
DS
547 if (!dry_run)
548 vtysh_execute_no_pager("XFRR_end_configuration");
f8e6ada8 549
d62a17ae 550 vtysh_execute_no_pager("end");
551 vtysh_execute_no_pager("disable");
718e3744 552
d62a17ae 553 vty_close(vty);
3221dca8 554
d62a17ae 555 return (ret);
718e3744 556}
557
e7168df4 558/* Read up configuration file from config_default_dir. */
77f7b4b0 559int vtysh_read_config(const char *config_default_dir, bool dry_run)
718e3744 560{
d62a17ae 561 FILE *confp = NULL;
744bc17d 562 bool save;
d62a17ae 563 int ret;
564
565 confp = fopen(config_default_dir, "r");
566 if (confp == NULL) {
567 fprintf(stderr,
568 "%% Can't open configuration file %s due to '%s'.\n",
569 config_default_dir, safe_strerror(errno));
95f7965d 570 return CMD_ERR_NO_FILE;
d62a17ae 571 }
67e29abc 572
744bc17d
CH
573 save = vtysh_add_timestamp;
574 vtysh_add_timestamp = false;
575
77f7b4b0 576 ret = vtysh_read_file(confp, dry_run);
d62a17ae 577 fclose(confp);
718e3744 578
744bc17d
CH
579 vtysh_add_timestamp = save;
580
d62a17ae 581 return (ret);
718e3744 582}
583
e7168df4 584/* We don't write vtysh specific into file from vtysh. vtysh.conf should
585 * be edited by hand. So, we handle only "write terminal" case here and
586 * integrate vtysh specific conf with conf from daemons.
587 */
4d762f26 588void vtysh_config_write(void)
718e3744 589{
63e653a2 590 char line[512];
d62a17ae 591
6b3ee3a0 592 if (cmd_hostname_get()) {
63e653a2 593 snprintf(line, sizeof(line), "hostname %s", cmd_hostname_get());
d62a17ae 594 vtysh_config_parse_line(NULL, line);
595 }
3b103fec
MK
596
597 if (cmd_domainname_get()) {
772270f3
QY
598 snprintf(line, sizeof(line), "domainname %s",
599 cmd_domainname_get());
3b103fec
MK
600 vtysh_config_parse_line(NULL, line);
601 }
d62a17ae 602 if (vtysh_write_integrated == WRITE_INTEGRATED_NO)
603 vtysh_config_parse_line(NULL,
604 "no service integrated-vtysh-config");
605 if (vtysh_write_integrated == WRITE_INTEGRATED_YES)
606 vtysh_config_parse_line(NULL,
607 "service integrated-vtysh-config");
608
609 user_config_write();
718e3744 610}
611
4d762f26 612void vtysh_config_init(void)
718e3744 613{
d62a17ae 614 config_top = list_new();
615 config_top->del = (void (*)(void *))line_del;
616 configvec = vector_init(1);
718e3744 617}