vtysh_config.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  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. struct config
  23. {
  24. /* Configuration node name. */
  25. char *name;
  26. /* Configuration string line. */
  27. struct list *line;
  28. /* Configuration can be nest. */
  29. struct config *config;
  30. /* Index of this config. */
  31. u_int32_t index;
  32. };
  33. struct list *config_top;
  34. int
  35. line_cmp (char *c1, char *c2)
  36. {
  37. return strcmp (c1, c2);
  38. }
  39. void
  40. line_del (char *line)
  41. {
  42. XFREE (MTYPE_VTYSH_CONFIG_LINE, line);
  43. }
  44. struct config *
  45. config_new ()
  46. {
  47. struct config *config;
  48. config = XCALLOC (MTYPE_VTYSH_CONFIG, sizeof (struct config));
  49. return config;
  50. }
  51. int
  52. config_cmp (struct config *c1, struct config *c2)
  53. {
  54. return strcmp (c1->name, c2->name);
  55. }
  56. void
  57. config_del (struct config* config)
  58. {
  59. list_delete (config->line);
  60. if (config->name)
  61. XFREE (MTYPE_VTYSH_CONFIG_LINE, config->name);
  62. XFREE (MTYPE_VTYSH_CONFIG, config);
  63. }
  64. struct config *
  65. config_get (int index, char *line)
  66. {
  67. struct config *config;
  68. struct config *config_loop;
  69. struct list *master;
  70. struct listnode *nn;
  71. config = config_loop = NULL;
  72. master = vector_lookup_ensure (configvec, index);
  73. if (! master)
  74. {
  75. master = list_new ();
  76. master->del = (void (*) (void *))config_del;
  77. master->cmp = (int (*)(void *, void *)) config_cmp;
  78. vector_set_index (configvec, index, master);
  79. }
  80. LIST_LOOP (master, config_loop, nn)
  81. {
  82. if (strcmp (config_loop->name, line) == 0)
  83. config = config_loop;
  84. }
  85. if (! config)
  86. {
  87. config = config_new ();
  88. config->line = list_new ();
  89. config->line->del = (void (*) (void *))line_del;
  90. config->line->cmp = (int (*)(void *, void *)) line_cmp;
  91. config->name = XSTRDUP (MTYPE_VTYSH_CONFIG_LINE, line);
  92. config->index = index;
  93. listnode_add (master, config);
  94. }
  95. return config;
  96. }
  97. void
  98. config_add_line (struct list *config, char *line)
  99. {
  100. listnode_add (config, XSTRDUP (MTYPE_VTYSH_CONFIG_LINE, line));
  101. }
  102. void
  103. config_add_line_uniq (struct list *config, char *line)
  104. {
  105. struct listnode *nn;
  106. char *pnt;
  107. LIST_LOOP (config, pnt, nn)
  108. {
  109. if (strcmp (pnt, line) == 0)
  110. return;
  111. }
  112. listnode_add_sort (config, XSTRDUP (MTYPE_VTYSH_CONFIG_LINE, line));
  113. }
  114. void
  115. vtysh_config_parse_line (char *line)
  116. {
  117. char c;
  118. static struct config *config = NULL;
  119. if (! line)
  120. return;
  121. c = line[0];
  122. if (c == '\0')
  123. return;
  124. /* printf ("[%s]\n", line); */
  125. switch (c)
  126. {
  127. case '!':
  128. case '#':
  129. break;
  130. case ' ':
  131. /* Store line to current configuration. */
  132. if (config)
  133. {
  134. if (strncmp (line, " address-family vpnv4", strlen (" address-family vpnv4")) == 0)
  135. config = config_get (BGP_VPNV4_NODE, line);
  136. else if (strncmp (line, " address-family ipv4 multicast", strlen (" address-family ipv4 multicast")) == 0)
  137. config = config_get (BGP_IPV4M_NODE, line);
  138. else if (strncmp (line, " address-family ipv6", strlen (" address-family ipv6")) == 0)
  139. config = config_get (BGP_IPV6_NODE, line);
  140. else if (config->index == RMAP_NODE || config->index == INTERFACE_NODE )
  141. config_add_line_uniq (config->line, line);
  142. else
  143. config_add_line (config->line, line);
  144. }
  145. else
  146. config_add_line (config_top, line);
  147. break;
  148. default:
  149. if (strncmp (line, "interface", strlen ("interface")) == 0)
  150. config = config_get (INTERFACE_NODE, line);
  151. else if (strncmp (line, "router rip", strlen ("router rip")) == 0)
  152. config = config_get (RIP_NODE, line);
  153. else if (strncmp (line, "router ripng", strlen ("router ripng")) == 0)
  154. config = config_get (RIPNG_NODE, line);
  155. else if (strncmp (line, "router ospf", strlen ("router ospf")) == 0)
  156. config = config_get (OSPF_NODE, line);
  157. else if (strncmp (line, "router ospf6", strlen ("router ospf6")) == 0)
  158. config = config_get (OSPF6_NODE, line);
  159. else if (strncmp (line, "router bgp", strlen ("router bgp")) == 0)
  160. config = config_get (BGP_NODE, line);
  161. else if (strncmp (line, "router isis", strlen ("router bgp")) == 0)
  162. config = config_get (ISIS_NODE, line);
  163. else if (strncmp (line, "router", strlen ("router")) == 0)
  164. config = config_get (BGP_NODE, line);
  165. else if (strncmp (line, "route-map", strlen ("route-map")) == 0)
  166. config = config_get (RMAP_NODE, line);
  167. else if (strncmp (line, "access-list", strlen ("access-list")) == 0)
  168. config = config_get (ACCESS_NODE, line);
  169. else if (strncmp (line, "ipv6 access-list", strlen ("ipv6 access-list")) == 0)
  170. config = config_get (ACCESS_IPV6_NODE, line);
  171. else if (strncmp (line, "ip prefix-list", strlen ("ip prefix-list")) == 0)
  172. config = config_get (PREFIX_NODE, line);
  173. else if (strncmp (line, "ipv6 prefix-list", strlen ("ipv6 prefix-list")) == 0)
  174. config = config_get (PREFIX_IPV6_NODE, line);
  175. else if (strncmp (line, "ip as-path access-list", strlen ("ip as-path access-list")) == 0)
  176. config = config_get (AS_LIST_NODE, line);
  177. else if (strncmp (line, "ip community-list", strlen ("ip community-list")) == 0)
  178. config = config_get (COMMUNITY_LIST_NODE, line);
  179. else if (strncmp (line, "ip route", strlen ("ip route")) == 0)
  180. config = config_get (IP_NODE, line);
  181. else if (strncmp (line, "ipv6 route", strlen ("ipv6 route")) == 0)
  182. config = config_get (IP_NODE, line);
  183. else if (strncmp (line, "key", strlen ("key")) == 0)
  184. config = config_get (KEYCHAIN_NODE, line);
  185. else
  186. {
  187. if (strncmp (line, "log", strlen ("log")) == 0
  188. || strncmp (line, "hostname", strlen ("hostname")) == 0
  189. || strncmp (line, "password", strlen ("hostname")) == 0)
  190. config_add_line_uniq (config_top, line);
  191. else
  192. config_add_line (config_top, line);
  193. config = NULL;
  194. }
  195. break;
  196. }
  197. }
  198. void
  199. vtysh_config_parse (char *line)
  200. {
  201. char *begin;
  202. char *pnt;
  203. begin = pnt = line;
  204. while (*pnt != '\0')
  205. {
  206. if (*pnt == '\n')
  207. {
  208. *pnt++ = '\0';
  209. vtysh_config_parse_line (begin);
  210. begin = pnt;
  211. }
  212. else
  213. {
  214. pnt++;
  215. }
  216. }
  217. }
  218. /* Macro to check delimiter is needed between each configuration line
  219. or not. */
  220. #define NO_DELIMITER(I) \
  221. ((I) == ACCESS_NODE || (I) == PREFIX_NODE || (I) == IP_NODE \
  222. || (I) == AS_LIST_NODE || (I) == COMMUNITY_LIST_NODE || \
  223. (I) == ACCESS_IPV6_NODE || (I) == PREFIX_IPV6_NODE)
  224. /* Display configuration to file pointer. */
  225. void
  226. vtysh_config_dump (FILE *fp)
  227. {
  228. struct listnode *nn;
  229. struct listnode *nm;
  230. struct config *config;
  231. struct list *master;
  232. char *line;
  233. int i;
  234. LIST_LOOP (config_top, line, nn)
  235. {
  236. fprintf (fp, "%s\n", line);
  237. fflush (fp);
  238. }
  239. fprintf (fp, "!\n");
  240. fflush (fp);
  241. for (i = 0; i < vector_max (configvec); i++)
  242. if ((master = vector_slot (configvec, i)) != NULL)
  243. {
  244. LIST_LOOP (master, config, nn)
  245. {
  246. fprintf (fp, "%s\n", config->name);
  247. fflush (fp);
  248. LIST_LOOP (config->line, line, nm)
  249. {
  250. fprintf (fp, "%s\n", line);
  251. fflush (fp);
  252. }
  253. if (! NO_DELIMITER (i))
  254. {
  255. fprintf (fp, "!\n");
  256. fflush (fp);
  257. }
  258. }
  259. if (NO_DELIMITER (i))
  260. {
  261. fprintf (fp, "!\n");
  262. fflush (fp);
  263. }
  264. }
  265. for (i = 0; i < vector_max (configvec); i++)
  266. if ((master = vector_slot (configvec, i)) != NULL)
  267. {
  268. list_delete (master);
  269. vector_slot (configvec, i) = NULL;
  270. }
  271. list_delete_all_node (config_top);
  272. }
  273. /* Read up configuration file from file_name. */
  274. static void
  275. vtysh_read_file (FILE *confp)
  276. {
  277. int ret;
  278. struct vty *vty;
  279. vty = vty_new ();
  280. vty->fd = 0; /* stdout */
  281. vty->type = VTY_TERM;
  282. vty->node = CONFIG_NODE;
  283. vtysh_execute_no_pager ("enable");
  284. vtysh_execute_no_pager ("configure terminal");
  285. /* Execute configuration file */
  286. ret = vtysh_config_from_file (vty, confp);
  287. vtysh_execute_no_pager ("end");
  288. vtysh_execute_no_pager ("disable");
  289. vty_close (vty);
  290. if (ret != CMD_SUCCESS)
  291. {
  292. switch (ret)
  293. {
  294. case CMD_ERR_AMBIGUOUS:
  295. fprintf (stderr, "Ambiguous command.\n");
  296. break;
  297. case CMD_ERR_NO_MATCH:
  298. fprintf (stderr, "There is no such command.\n");
  299. break;
  300. }
  301. fprintf (stderr, "Error occured during reading below line.\n%s\n",
  302. vty->buf);
  303. exit (1);
  304. }
  305. }
  306. /* Read up configuration file from file_name. */
  307. void
  308. vtysh_read_config (char *config_file,
  309. char *config_current_dir,
  310. char *config_default_dir)
  311. {
  312. char *cwd;
  313. FILE *confp = NULL;
  314. char *fullpath;
  315. /* If -f flag specified. */
  316. if (config_file != NULL)
  317. {
  318. if (! IS_DIRECTORY_SEP (config_file[0]))
  319. {
  320. cwd = getcwd (NULL, MAXPATHLEN);
  321. fullpath = XMALLOC (MTYPE_TMP,
  322. strlen (cwd) + strlen (config_file) + 2);
  323. sprintf (fullpath, "%s/%s", cwd, config_file);
  324. }
  325. else
  326. fullpath = config_file;
  327. confp = fopen (fullpath, "r");
  328. if (confp == NULL)
  329. {
  330. fprintf (stderr, "can't open configuration file [%s]\n",
  331. config_file);
  332. exit(1);
  333. }
  334. }
  335. else
  336. {
  337. /* Relative path configuration file open. */
  338. if (config_current_dir)
  339. confp = fopen (config_current_dir, "r");
  340. /* If there is no relative path exists, open system default file. */
  341. if (confp == NULL)
  342. {
  343. confp = fopen (config_default_dir, "r");
  344. if (confp == NULL)
  345. {
  346. fprintf (stderr, "can't open configuration file [%s]\n",
  347. config_default_dir);
  348. exit (1);
  349. }
  350. else
  351. fullpath = config_default_dir;
  352. }
  353. else
  354. {
  355. /* Rleative path configuration file. */
  356. cwd = getcwd (NULL, MAXPATHLEN);
  357. fullpath = XMALLOC (MTYPE_TMP,
  358. strlen (cwd) + strlen (config_current_dir) + 2);
  359. sprintf (fullpath, "%s/%s", cwd, config_current_dir);
  360. }
  361. }
  362. vtysh_read_file (confp);
  363. fclose (confp);
  364. host_config_set (fullpath);
  365. }
  366. void
  367. vtysh_config_write (FILE *fp)
  368. {
  369. extern struct host host;
  370. if (host.name)
  371. fprintf (fp, "hostname %s\n", host.name);
  372. fprintf (fp, "!\n");
  373. }
  374. void
  375. vtysh_config_init ()
  376. {
  377. config_top = list_new ();
  378. config_top->del = (void (*) (void *))line_del;
  379. configvec = vector_init (1);
  380. }