vtysh_config.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. /* Configuration generator.
  2. Copyright (C) 2000 Kunihiro Ishiguro
  3. This file is part of GNU Zebra.
  4. GNU Zebra is free software; you can redistribute it and/or modify it
  5. under the terms of the GNU General Public License as published by the
  6. Free Software Foundation; either version 2, or (at your option) any
  7. later version.
  8. GNU Zebra is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNU Zebra; see the file COPYING. If not, write to the Free
  14. Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  15. 02111-1307, USA. */
  16. #include <zebra.h>
  17. #include "command.h"
  18. #include "linklist.h"
  19. #include "memory.h"
  20. #include "vtysh/vtysh.h"
  21. vector configvec;
  22. extern int vtysh_writeconfig_integrated;
  23. struct config
  24. {
  25. /* Configuration node name. */
  26. char *name;
  27. /* Configuration string line. */
  28. struct list *line;
  29. /* Configuration can be nest. */
  30. struct config *config;
  31. /* Index of this config. */
  32. u_int32_t index;
  33. };
  34. struct list *config_top;
  35. static int
  36. line_cmp (char *c1, char *c2)
  37. {
  38. return strcmp (c1, c2);
  39. }
  40. static void
  41. line_del (char *line)
  42. {
  43. XFREE (MTYPE_VTYSH_CONFIG_LINE, line);
  44. }
  45. static struct config *
  46. config_new ()
  47. {
  48. struct config *config;
  49. config = XCALLOC (MTYPE_VTYSH_CONFIG, sizeof (struct config));
  50. return config;
  51. }
  52. static int
  53. config_cmp (struct config *c1, struct config *c2)
  54. {
  55. return strcmp (c1->name, c2->name);
  56. }
  57. static void
  58. config_del (struct config* config)
  59. {
  60. list_delete (config->line);
  61. if (config->name)
  62. XFREE (MTYPE_VTYSH_CONFIG_LINE, config->name);
  63. XFREE (MTYPE_VTYSH_CONFIG, config);
  64. }
  65. static struct config *
  66. config_get (int index, const char *line)
  67. {
  68. struct config *config;
  69. struct config *config_loop;
  70. struct list *master;
  71. struct listnode *node, *nnode;
  72. config = config_loop = NULL;
  73. master = vector_lookup_ensure (configvec, index);
  74. if (! master)
  75. {
  76. master = list_new ();
  77. master->del = (void (*) (void *))config_del;
  78. master->cmp = (int (*)(void *, void *)) config_cmp;
  79. vector_set_index (configvec, index, master);
  80. }
  81. for (ALL_LIST_ELEMENTS (master, node, nnode, config_loop))
  82. {
  83. if (strcmp (config_loop->name, line) == 0)
  84. config = config_loop;
  85. }
  86. if (! config)
  87. {
  88. config = config_new ();
  89. config->line = list_new ();
  90. config->line->del = (void (*) (void *))line_del;
  91. config->line->cmp = (int (*)(void *, void *)) line_cmp;
  92. config->name = XSTRDUP (MTYPE_VTYSH_CONFIG_LINE, line);
  93. config->index = index;
  94. listnode_add (master, config);
  95. }
  96. return config;
  97. }
  98. static void
  99. config_add_line (struct list *config, const char *line)
  100. {
  101. listnode_add (config, XSTRDUP (MTYPE_VTYSH_CONFIG_LINE, line));
  102. }
  103. static void
  104. config_add_line_uniq (struct list *config, const char *line)
  105. {
  106. struct listnode *node, *nnode;
  107. char *pnt;
  108. for (ALL_LIST_ELEMENTS (config, node, nnode, pnt))
  109. {
  110. if (strcmp (pnt, line) == 0)
  111. return;
  112. }
  113. listnode_add_sort (config, XSTRDUP (MTYPE_VTYSH_CONFIG_LINE, line));
  114. }
  115. static void
  116. vtysh_config_parse_line (const char *line)
  117. {
  118. char c;
  119. static struct config *config = NULL;
  120. if (! line)
  121. return;
  122. c = line[0];
  123. if (c == '\0')
  124. return;
  125. /* printf ("[%s]\n", line); */
  126. switch (c)
  127. {
  128. case '!':
  129. case '#':
  130. break;
  131. case ' ':
  132. /* Store line to current configuration. */
  133. if (config)
  134. {
  135. if (strncmp (line, " address-family vpnv4",
  136. strlen (" address-family vpnv4")) == 0)
  137. config = config_get (BGP_VPNV4_NODE, line);
  138. else if (strncmp (line, " address-family vpn6",
  139. strlen (" address-family vpn6")) == 0)
  140. config = config_get (BGP_VPNV6_NODE, line);
  141. else if (strncmp (line, " address-family encapv6",
  142. strlen (" address-family encapv6")) == 0)
  143. config = config_get (BGP_ENCAPV6_NODE, line);
  144. else if (strncmp (line, " address-family encap",
  145. strlen (" address-family encap")) == 0)
  146. config = config_get (BGP_ENCAP_NODE, line);
  147. else if (strncmp (line, " address-family ipv4 multicast",
  148. strlen (" address-family ipv4 multicast")) == 0)
  149. config = config_get (BGP_IPV4M_NODE, line);
  150. else if (strncmp (line, " address-family ipv6",
  151. strlen (" address-family ipv6")) == 0)
  152. config = config_get (BGP_IPV6_NODE, line);
  153. else if (strncmp (line, " link-params", strlen (" link-params")) == 0)
  154. {
  155. config_add_line (config->line, line);
  156. config->index = LINK_PARAMS_NODE;
  157. }
  158. else if (config->index == LINK_PARAMS_NODE &&
  159. strncmp (line, " exit-link-params", strlen (" exit")) == 0)
  160. {
  161. config_add_line (config->line, line);
  162. config->index = INTERFACE_NODE;
  163. }
  164. else if (config->index == RMAP_NODE ||
  165. config->index == INTERFACE_NODE ||
  166. config->index == VTY_NODE)
  167. config_add_line_uniq (config->line, line);
  168. else
  169. config_add_line (config->line, line);
  170. }
  171. else
  172. config_add_line (config_top, line);
  173. break;
  174. default:
  175. if (strncmp (line, "interface", strlen ("interface")) == 0)
  176. config = config_get (INTERFACE_NODE, line);
  177. else if (strncmp (line, "router-id", strlen ("router-id")) == 0)
  178. config = config_get (ZEBRA_NODE, line);
  179. else if (strncmp (line, "router rip", strlen ("router rip")) == 0)
  180. config = config_get (RIP_NODE, line);
  181. else if (strncmp (line, "router ripng", strlen ("router ripng")) == 0)
  182. config = config_get (RIPNG_NODE, line);
  183. else if (strncmp (line, "router ospf", strlen ("router ospf")) == 0)
  184. config = config_get (OSPF_NODE, line);
  185. else if (strncmp (line, "router ospf6", strlen ("router ospf6")) == 0)
  186. config = config_get (OSPF6_NODE, line);
  187. else if (strncmp (line, "router bgp", strlen ("router bgp")) == 0)
  188. config = config_get (BGP_NODE, line);
  189. else if (strncmp (line, "router isis", strlen ("router isis")) == 0)
  190. config = config_get (ISIS_NODE, line);
  191. else if (strncmp (line, "router bgp", strlen ("router bgp")) == 0)
  192. config = config_get (BGP_NODE, line);
  193. else if (strncmp (line, "route-map", strlen ("route-map")) == 0)
  194. config = config_get (RMAP_NODE, line);
  195. else if (strncmp (line, "access-list", strlen ("access-list")) == 0)
  196. config = config_get (ACCESS_NODE, line);
  197. else if (strncmp (line, "ipv6 access-list",
  198. strlen ("ipv6 access-list")) == 0)
  199. config = config_get (ACCESS_IPV6_NODE, line);
  200. else if (strncmp (line, "ip prefix-list",
  201. strlen ("ip prefix-list")) == 0)
  202. config = config_get (PREFIX_NODE, line);
  203. else if (strncmp (line, "ipv6 prefix-list",
  204. strlen ("ipv6 prefix-list")) == 0)
  205. config = config_get (PREFIX_IPV6_NODE, line);
  206. else if (strncmp (line, "ip as-path access-list",
  207. strlen ("ip as-path access-list")) == 0)
  208. config = config_get (AS_LIST_NODE, line);
  209. else if (strncmp (line, "ip community-list",
  210. 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);
  214. else if (strncmp (line, "ipv6 route", strlen ("ipv6 route")) == 0)
  215. config = config_get (IP_NODE, line);
  216. else if (strncmp (line, "key", strlen ("key")) == 0)
  217. config = config_get (KEYCHAIN_NODE, line);
  218. else if (strncmp (line, "line", strlen ("line")) == 0)
  219. config = config_get (VTY_NODE, line);
  220. else if ( (strncmp (line, "ipv6 forwarding",
  221. strlen ("ipv6 forwarding")) == 0)
  222. || (strncmp (line, "ip forwarding",
  223. strlen ("ip forwarding")) == 0) )
  224. config = config_get (FORWARDING_NODE, line);
  225. else if (strncmp (line, "service", strlen ("service")) == 0)
  226. config = config_get (SERVICE_NODE, line);
  227. else if (strncmp (line, "debug", strlen ("debug")) == 0)
  228. config = config_get (DEBUG_NODE, line);
  229. else if (strncmp (line, "password", strlen ("password")) == 0
  230. || strncmp (line, "enable password",
  231. strlen ("enable password")) == 0)
  232. config = config_get (AAA_NODE, line);
  233. else if (strncmp (line, "ip protocol", strlen ("ip protocol")) == 0)
  234. config = config_get (PROTOCOL_NODE, line);
  235. else
  236. {
  237. if (strncmp (line, "log", strlen ("log")) == 0
  238. || strncmp (line, "hostname", strlen ("hostname")) == 0
  239. )
  240. config_add_line_uniq (config_top, line);
  241. else
  242. config_add_line (config_top, line);
  243. config = NULL;
  244. }
  245. break;
  246. }
  247. }
  248. void
  249. vtysh_config_parse (char *line)
  250. {
  251. char *begin;
  252. char *pnt;
  253. begin = pnt = line;
  254. while (*pnt != '\0')
  255. {
  256. if (*pnt == '\n')
  257. {
  258. *pnt++ = '\0';
  259. vtysh_config_parse_line (begin);
  260. begin = pnt;
  261. }
  262. else
  263. {
  264. pnt++;
  265. }
  266. }
  267. }
  268. /* Macro to check delimiter is needed between each configuration line
  269. * or not. */
  270. #define NO_DELIMITER(I) \
  271. ((I) == ACCESS_NODE || (I) == PREFIX_NODE || (I) == IP_NODE \
  272. || (I) == AS_LIST_NODE || (I) == COMMUNITY_LIST_NODE || \
  273. (I) == ACCESS_IPV6_NODE || (I) == PREFIX_IPV6_NODE \
  274. || (I) == SERVICE_NODE || (I) == FORWARDING_NODE || (I) == DEBUG_NODE \
  275. || (I) == AAA_NODE)
  276. /* Display configuration to file pointer. */
  277. void
  278. vtysh_config_dump (FILE *fp)
  279. {
  280. struct listnode *node, *nnode;
  281. struct listnode *mnode, *mnnode;
  282. struct config *config;
  283. struct list *master;
  284. char *line;
  285. unsigned int i;
  286. for (ALL_LIST_ELEMENTS (config_top, node, nnode, line))
  287. {
  288. fprintf (fp, "%s\n", line);
  289. fflush (fp);
  290. }
  291. fprintf (fp, "!\n");
  292. fflush (fp);
  293. for (i = 0; i < vector_active (configvec); i++)
  294. if ((master = vector_slot (configvec, i)) != NULL)
  295. {
  296. for (ALL_LIST_ELEMENTS (master, node, nnode, config))
  297. {
  298. fprintf (fp, "%s\n", config->name);
  299. fflush (fp);
  300. for (ALL_LIST_ELEMENTS (config->line, mnode, mnnode, line))
  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. for (i = 0; i < vector_active (configvec); i++)
  318. if ((master = vector_slot (configvec, i)) != NULL)
  319. {
  320. list_delete (master);
  321. vector_slot (configvec, i) = NULL;
  322. }
  323. list_delete_all_node (config_top);
  324. }
  325. /* Read up configuration file from file_name. */
  326. static void
  327. vtysh_read_file (FILE *confp)
  328. {
  329. int ret;
  330. struct vty *vty;
  331. vty = vty_new ();
  332. vty->fd = 0; /* stdout */
  333. vty->type = VTY_TERM;
  334. vty->node = CONFIG_NODE;
  335. vtysh_execute_no_pager ("enable");
  336. vtysh_execute_no_pager ("configure terminal");
  337. /* Execute configuration file. */
  338. ret = vtysh_config_from_file (vty, confp);
  339. vtysh_execute_no_pager ("end");
  340. vtysh_execute_no_pager ("disable");
  341. vty_close (vty);
  342. if (ret != CMD_SUCCESS)
  343. {
  344. switch (ret)
  345. {
  346. case CMD_ERR_AMBIGUOUS:
  347. fprintf (stderr, "Ambiguous command.\n");
  348. break;
  349. case CMD_ERR_NO_MATCH:
  350. fprintf (stderr, "There is no such command.\n");
  351. break;
  352. }
  353. fprintf (stderr, "Error occurred during reading below line.\n%s\n",
  354. vty->buf);
  355. exit (1);
  356. }
  357. }
  358. /* Read up configuration file from config_default_dir. */
  359. int
  360. vtysh_read_config (char *config_default_dir)
  361. {
  362. FILE *confp = NULL;
  363. confp = fopen (config_default_dir, "r");
  364. if (confp == NULL)
  365. return (1);
  366. vtysh_read_file (confp);
  367. fclose (confp);
  368. host_config_set (config_default_dir);
  369. return (0);
  370. }
  371. /* We don't write vtysh specific into file from vtysh. vtysh.conf should
  372. * be edited by hand. So, we handle only "write terminal" case here and
  373. * integrate vtysh specific conf with conf from daemons.
  374. */
  375. void
  376. vtysh_config_write ()
  377. {
  378. char line[81];
  379. extern struct host host;
  380. if (host.name)
  381. {
  382. sprintf (line, "hostname %s", host.name);
  383. vtysh_config_parse_line(line);
  384. }
  385. if (vtysh_writeconfig_integrated)
  386. vtysh_config_parse_line ("service integrated-vtysh-config");
  387. }
  388. void
  389. vtysh_config_init ()
  390. {
  391. config_top = list_new ();
  392. config_top->del = (void (*) (void *))line_del;
  393. configvec = vector_init (1);
  394. }