parse.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604
  1. /*
  2. * Copyright (c) 2002-2004 MontaVista Software, Inc.
  3. *
  4. * All rights reserved.
  5. *
  6. * Author: Steven Dake (sdake@mvista.com)
  7. *
  8. * This software licensed under BSD license, the text of which follows:
  9. *
  10. * Redistribution and use in source and binary forms, with or without
  11. * modification, are permitted provided that the following conditions are met:
  12. *
  13. * - Redistributions of source code must retain the above copyright notice,
  14. * this list of conditions and the following disclaimer.
  15. * - Redistributions in binary form must reproduce the above copyright notice,
  16. * this list of conditions and the following disclaimer in the documentation
  17. * and/or other materials provided with the distribution.
  18. * - Neither the name of the MontaVista Software, Inc. nor the names of its
  19. * contributors may be used to endorse or promote products derived from this
  20. * software without specific prior written permission.
  21. *
  22. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  23. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  26. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  27. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  28. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  29. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  30. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  31. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  32. * THE POSSIBILITY OF SUCH DAMAGE.
  33. */
  34. #include <stdio.h>
  35. #include <string.h>
  36. #include <stdlib.h>
  37. #include <errno.h>
  38. #include <assert.h>
  39. #include <sys/socket.h>
  40. #include <netinet/in.h>
  41. #include <arpa/inet.h>
  42. #include "../include/ais_types.h"
  43. #include "../include/list.h"
  44. #include "util.h"
  45. #include "parse.h"
  46. #include "mempool.h"
  47. #include "print.h"
  48. DECLARE_LIST_INIT (saAmfGroupHead);
  49. static char error_string_response[512];
  50. typedef enum {
  51. AMF_HEAD,
  52. AMF_GROUP,
  53. AMF_UNIT,
  54. AMF_PROTECTION,
  55. AMF_COMPONENT
  56. } amf_parse_t;
  57. typedef enum {
  58. MAIN_HEAD,
  59. MAIN_NETWORK,
  60. MAIN_LOGGING,
  61. MAIN_KEY
  62. } main_parse_t;
  63. void setSaNameT (SaNameT *name, char *str) {
  64. strncpy ((char *)name->value, str, SA_MAX_NAME_LENGTH);
  65. if (strlen ((char *)name->value) > SA_MAX_NAME_LENGTH) {
  66. name->length = SA_MAX_NAME_LENGTH;
  67. } else {
  68. name->length = strlen (str);
  69. }
  70. }
  71. int SaNameTisEqual (SaNameT *str1, char *str2) {
  72. if (str1->length == strlen (str2)) {
  73. return ((strncmp ((char *)str1->value, (char *)str2,
  74. str1->length)) == 0);
  75. } else {
  76. return 0;
  77. }
  78. }
  79. struct saAmfComponent *findComponent (SaNameT *name)
  80. {
  81. struct list_head *AmfGroupList = 0;
  82. struct list_head *AmfUnitList = 0;
  83. struct list_head *AmfComponentList = 0;
  84. struct saAmfGroup *saAmfGroup = 0;
  85. struct saAmfUnit *AmfUnit = 0;
  86. struct saAmfComponent *AmfComponent = 0;
  87. int found = 0;
  88. /*
  89. * Search all groups
  90. */
  91. for (AmfGroupList = saAmfGroupHead.next;
  92. AmfGroupList != &saAmfGroupHead && found == 0;
  93. AmfGroupList = AmfGroupList->next) {
  94. saAmfGroup = list_entry (AmfGroupList,
  95. struct saAmfGroup, saAmfGroupList);
  96. /*
  97. * Search all units
  98. */
  99. for (AmfUnitList = saAmfGroup->saAmfUnitHead.next;
  100. AmfUnitList != &saAmfGroup->saAmfUnitHead && found == 0;
  101. AmfUnitList = AmfUnitList->next) {
  102. AmfUnit = list_entry (AmfUnitList,
  103. struct saAmfUnit, saAmfUnitList);
  104. /*
  105. * Search all components
  106. */
  107. for (AmfComponentList = AmfUnit->saAmfComponentHead.next;
  108. AmfComponentList != &AmfUnit->saAmfComponentHead && found == 0;
  109. AmfComponentList = AmfComponentList->next) {
  110. AmfComponent = list_entry (AmfComponentList,
  111. struct saAmfComponent, saAmfComponentList);
  112. if (name_match (name, &AmfComponent->name)) {
  113. found = 1;
  114. }
  115. }
  116. }
  117. }
  118. if (found) {
  119. return (AmfComponent);
  120. } else {
  121. return (0);
  122. }
  123. }
  124. char *
  125. strstr_rs (const char *haystack, const char *needle)
  126. {
  127. char *end_address;
  128. char *new_needle;
  129. new_needle = (char *)mempool_strdup (needle);
  130. new_needle[strlen(new_needle) - 1] = '\0';
  131. end_address = strstr (haystack, new_needle);
  132. if (end_address) {
  133. end_address += strlen (new_needle);
  134. end_address = strstr (end_address, needle + strlen (new_needle));
  135. }
  136. if (end_address) {
  137. end_address += 1; /* skip past { or = */
  138. do {
  139. if (*end_address == '\t' || *end_address == ' ') {
  140. end_address++;
  141. } else {
  142. break;
  143. }
  144. } while (*end_address != '\0');
  145. }
  146. mempool_free (new_needle);
  147. return (end_address);
  148. }
  149. extern int openais_amf_config_read (char **error_string)
  150. {
  151. char line[255];
  152. FILE *fp;
  153. amf_parse_t current_parse = AMF_HEAD;
  154. int line_number = 0;
  155. char *loc;
  156. int i;
  157. struct saAmfGroup *saAmfGroup = 0;
  158. struct saAmfUnit *saAmfUnit = 0;
  159. struct saAmfProtectionGroup *saAmfProtectionGroup = 0;
  160. struct saAmfComponent *saAmfComponent = 0;
  161. struct list_head *findAmfUnitList = 0;
  162. struct list_head *findAmfComponentList = 0;
  163. struct saAmfUnit *findAmfUnit = 0;
  164. struct saAmfComponent *findAmfComponent = 0;
  165. SaNameT componentName;
  166. fp = fopen ("/etc/ais/groups.conf", "r");
  167. if (fp == 0) {
  168. sprintf (error_string_response,
  169. "Can't read /etc/ais/groups.conf file reason = (%s).\n", strerror (errno));
  170. *error_string = error_string_response;
  171. return (-1);
  172. }
  173. while (fgets (line, 255, fp)) {
  174. line_number += 1;
  175. line[strlen(line) - 1] = '\0';
  176. /*
  177. * Clear out white space and tabs
  178. */
  179. for (i = strlen (line) - 1; i > -1; i--) {
  180. if (line[i] == '\t' || line[i] == ' ') {
  181. line[i] = '\0';
  182. } else {
  183. break;
  184. }
  185. }
  186. /*
  187. * Clear out comments and empty lines
  188. */
  189. if (line[0] == '#' || line[0] == '\0') {
  190. continue;
  191. }
  192. switch (current_parse) {
  193. case AMF_HEAD:
  194. if (strstr_rs (line, "group{")) {
  195. saAmfGroup = (struct saAmfGroup *)mempool_malloc (sizeof (struct saAmfGroup));
  196. memset (saAmfGroup, 0, sizeof (struct saAmfGroup));
  197. list_init (&saAmfGroup->saAmfGroupList);
  198. list_init (&saAmfGroup->saAmfUnitHead);
  199. list_init (&saAmfGroup->saAmfProtectionGroupHead);
  200. list_add (&saAmfGroup->saAmfGroupList, &saAmfGroupHead);
  201. current_parse = AMF_GROUP;
  202. } else
  203. if (strcmp (line, "") == 0) {
  204. } else {
  205. goto parse_error;
  206. }
  207. break;
  208. case AMF_GROUP:
  209. if ((loc = strstr_rs (line, "name=")) != 0) {
  210. setSaNameT (&saAmfGroup->name, loc);
  211. } else
  212. if ((loc = strstr_rs (line, "model=")) != 0) {
  213. if (strcmp (loc, "2n") == 0) {
  214. saAmfGroup->model = GROUPCAPABILITYMODEL_2N;
  215. } else
  216. if (strcmp (loc, "nplusm") == 0) {
  217. saAmfGroup->model = GROUPCAPABILITYMODEL_NPLUSM;
  218. } else
  219. if (strcmp (loc, "nway") == 0) {
  220. printf ("nway redundancy model not supported.\n");
  221. goto parse_error;
  222. } else
  223. if (strcmp (loc, "nwayactive") == 0) {
  224. printf ("nway active redundancy model not supported.\n");
  225. goto parse_error;
  226. } else
  227. if (strcmp (loc, "noredundancy") == 0) {
  228. saAmfGroup->model = GROUPCAPABILITYMODEL_NOREDUNDANCY;
  229. } else {
  230. goto parse_error;
  231. }
  232. } else
  233. if ((loc = strstr_rs (line, "active-units=")) != 0) {
  234. saAmfGroup->saAmfActiveUnitsDesired = atoi (loc);
  235. } else
  236. if ((loc = strstr_rs (line, "backup-units=")) != 0) {
  237. saAmfGroup->saAmfStandbyUnitsDesired = atoi (loc);
  238. } else
  239. if (strstr_rs (line, "unit{")) {
  240. saAmfUnit = (struct saAmfUnit *)mempool_malloc (sizeof (struct saAmfUnit));
  241. memset (saAmfUnit, 0, sizeof (struct saAmfUnit));
  242. saAmfUnit->saAmfGroup = saAmfGroup;
  243. list_init (&saAmfUnit->saAmfComponentHead);
  244. list_add (&saAmfUnit->saAmfUnitList, &saAmfGroup->saAmfUnitHead);
  245. current_parse = AMF_UNIT;
  246. } else
  247. if (strstr_rs (line, "protection{")) {
  248. saAmfProtectionGroup = (struct saAmfProtectionGroup *)mempool_malloc (sizeof (struct saAmfProtectionGroup));
  249. memset (saAmfProtectionGroup, 0, sizeof (struct saAmfProtectionGroup));
  250. list_init (&saAmfProtectionGroup->saAmfMembersHead);
  251. list_init (&saAmfProtectionGroup->saAmfProtectionGroupList);
  252. list_add (&saAmfProtectionGroup->saAmfProtectionGroupList, &saAmfGroup->saAmfProtectionGroupHead);
  253. current_parse = AMF_PROTECTION;
  254. } else
  255. if (strstr_rs (line, "}")) {
  256. current_parse = AMF_HEAD;
  257. } else {
  258. goto parse_error;
  259. }
  260. break;
  261. case AMF_UNIT:
  262. if ((loc = strstr_rs (line, "name=")) != 0) {
  263. setSaNameT (&saAmfUnit->name, loc);
  264. } else
  265. if ((loc = strstr_rs (line, "component{")) != 0) {
  266. saAmfComponent = (struct saAmfComponent *)mempool_malloc (sizeof (struct saAmfComponent));
  267. memset (saAmfComponent, 0, sizeof (struct saAmfComponent));
  268. saAmfComponent->saAmfUnit = saAmfUnit;
  269. saAmfComponent->currentReadinessState = SA_AMF_OUT_OF_SERVICE;
  270. saAmfComponent->newReadinessState = SA_AMF_OUT_OF_SERVICE;
  271. saAmfComponent->currentHAState = SA_AMF_QUIESCED;
  272. saAmfComponent->newHAState = SA_AMF_QUIESCED;
  273. saAmfComponent->healthcheckInterval = 100;
  274. list_init (&saAmfComponent->saAmfComponentList);
  275. list_init (&saAmfComponent->saAmfProtectionGroupList);
  276. list_add (&saAmfComponent->saAmfComponentList, &saAmfUnit->saAmfComponentHead);
  277. current_parse = AMF_COMPONENT;
  278. } else
  279. if (strstr_rs (line, "}")) {
  280. current_parse = AMF_GROUP;
  281. } else {
  282. goto parse_error;
  283. }
  284. break;
  285. case AMF_COMPONENT:
  286. if ((loc = strstr_rs (line, "name=")) != 0) {
  287. setSaNameT (&saAmfComponent->name, loc);
  288. } else
  289. if ((loc = strstr_rs (line, "model=")) != 0) {
  290. if (strcmp (loc, "x_active_and_y_standby") == 0) {
  291. saAmfComponent->componentCapabilityModel = SA_AMF_COMPONENT_CAPABILITY_X_ACTIVE_AND_Y_STANDBY;
  292. } else
  293. if (strcmp (loc, "x_active_or_y_standby") == 0) {
  294. saAmfComponent->componentCapabilityModel = SA_AMF_COMPONENT_CAPABILITY_X_ACTIVE_OR_Y_STANDBY;
  295. } else
  296. if (strcmp (loc, "1_active_or_y_standby") == 0) {
  297. saAmfComponent->componentCapabilityModel = SA_AMF_COMPONENT_CAPABILITY_1_ACTIVE_OR_Y_STANDBY;
  298. } else
  299. if (strcmp (loc, "1_active_or_1_standby") == 0) {
  300. saAmfComponent->componentCapabilityModel = SA_AMF_COMPONENT_CAPABILITY_1_ACTIVE_OR_1_STANDBY;
  301. } else
  302. if (strcmp (loc, "x_active") == 0) {
  303. saAmfComponent->componentCapabilityModel = SA_AMF_COMPONENT_CAPABILITY_X_ACTIVE;
  304. } else
  305. if (strcmp (loc, "1_active") == 0) {
  306. saAmfComponent->componentCapabilityModel = SA_AMF_COMPONENT_CAPABILITY_1_ACTIVE;
  307. } else
  308. if (strcmp (loc, "no_active") == 0) {
  309. saAmfComponent->componentCapabilityModel = SA_AMF_COMPONENT_CAPABILITY_NO_ACTIVE;
  310. } else {
  311. goto parse_error;
  312. }
  313. } else
  314. if (strstr_rs (line, "}")) {
  315. current_parse = AMF_UNIT;
  316. } else {
  317. goto parse_error;
  318. }
  319. break;
  320. case AMF_PROTECTION:
  321. if ((loc = strstr_rs (line, "name=")) != 0) {
  322. setSaNameT (&saAmfProtectionGroup->name, loc);
  323. } else
  324. if ((loc = strstr_rs (line, "member=")) != 0) {
  325. for (findAmfUnitList = saAmfGroup->saAmfUnitHead.next;
  326. findAmfUnitList != &saAmfGroup->saAmfUnitHead;
  327. findAmfUnitList = findAmfUnitList->next) {
  328. findAmfUnit = list_entry (findAmfUnitList,
  329. struct saAmfUnit, saAmfUnitList);
  330. for (findAmfComponentList = findAmfUnit->saAmfComponentHead.next;
  331. findAmfComponentList != &findAmfUnit->saAmfComponentHead;
  332. findAmfComponentList = findAmfComponentList->next) {
  333. findAmfComponent = list_entry (findAmfComponentList,
  334. struct saAmfComponent, saAmfComponentList);
  335. if (SaNameTisEqual (&findAmfComponent->name, loc)) {
  336. list_add (&findAmfComponent->saAmfProtectionGroupList,
  337. &saAmfProtectionGroup->saAmfMembersHead);
  338. }
  339. }
  340. /*
  341. * Connect component to protection group
  342. */
  343. setSaNameT (&componentName, loc);
  344. saAmfComponent = findComponent (&componentName);
  345. saAmfComponent->saAmfProtectionGroup = saAmfProtectionGroup;
  346. }
  347. } else
  348. if (strstr_rs (line, "}")) {
  349. current_parse = AMF_GROUP;
  350. } else {
  351. goto parse_error;
  352. }
  353. break;
  354. default:
  355. printf ("Invalid state\n");
  356. goto parse_error;
  357. break;
  358. }
  359. }
  360. fclose (fp);
  361. return (0);
  362. parse_error:
  363. sprintf (error_string_response,
  364. "parse error at /etc/groups.conf:%d.\n", line_number);
  365. *error_string = error_string_response;
  366. fclose (fp);
  367. return (-1);
  368. }
  369. extern int openais_main_config_read (char **error_string,
  370. struct openais_config *openais_config,
  371. int interface_max)
  372. {
  373. FILE *fp;
  374. int line_number = 0;
  375. main_parse_t parse = MAIN_HEAD;
  376. int network_parsed = 0;
  377. int logging_parsed = 0;
  378. int key_parsed = 0;
  379. char *loc;
  380. int i;
  381. int parse_done = 0;
  382. char line[512];
  383. char *error_reason = error_string_response;
  384. memset (openais_config, 0, sizeof (struct openais_config));
  385. openais_config->interfaces = malloc (sizeof (struct totem_interface) * interface_max);
  386. if (openais_config->interfaces == 0) {
  387. parse_done = 1;
  388. *error_string = "Out of memory trying to allocate ethernet interface storage area";
  389. return -1;
  390. }
  391. memset (openais_config->interfaces, 0,
  392. sizeof (struct totem_interface) * interface_max);
  393. openais_config->mcast_addr.sin_family = AF_INET;
  394. fp = fopen ("/etc/ais/openais.conf", "r");
  395. if (fp == 0) {
  396. parse_done = 1;
  397. sprintf (error_reason, "Can't read file reason = (%s)\n", strerror (errno));
  398. *error_string = error_reason;
  399. return -1;
  400. }
  401. while (fgets (line, 255, fp)) {
  402. line_number += 1;
  403. line[strlen(line) - 1] = '\0';
  404. /*
  405. * Clear out white space and tabs
  406. */
  407. for (i = strlen (line) - 1; i > -1; i--) {
  408. if (line[i] == '\t' || line[i] == ' ') {
  409. line[i] = '\0';
  410. } else {
  411. break;
  412. }
  413. }
  414. /*
  415. * Clear out comments and empty lines
  416. */
  417. if (line[0] == '#' || line[0] == '\0') {
  418. continue;
  419. }
  420. line_number += 1;
  421. switch (parse) {
  422. case MAIN_HEAD:
  423. if (network_parsed == 0 && strstr_rs (line, "network{")) {
  424. network_parsed = 1;
  425. parse = MAIN_NETWORK;
  426. } else
  427. if (logging_parsed == 0 && strstr_rs (line, "logging{")) {
  428. logging_parsed = 1;
  429. parse = MAIN_LOGGING;
  430. } else
  431. if (key_parsed == 0 && strstr_rs (line, "key{")) {
  432. key_parsed = 1;
  433. parse = MAIN_KEY;
  434. } else {
  435. goto parse_error;
  436. }
  437. break;
  438. case MAIN_NETWORK:
  439. if ((loc = strstr_rs (line, "mcastaddr:"))) {
  440. inet_aton (loc, &openais_config->mcast_addr.sin_addr);
  441. } else
  442. if ((loc = strstr_rs (line, "mcastport:"))) {
  443. openais_config->mcast_addr.sin_port = htons (atoi (loc));
  444. } else
  445. if ((loc = strstr_rs (line, "bindnetaddr:"))) {
  446. if (interface_max == openais_config->interface_count) {
  447. sprintf (error_reason,
  448. "%d is too many interfaces in /etc/ais/network.conf",
  449. openais_config->interface_count);
  450. goto parse_error;
  451. }
  452. inet_aton (loc,
  453. &openais_config->interfaces[openais_config->interface_count].bindnet.sin_addr);
  454. openais_config->interface_count += 1;
  455. } else
  456. if ((loc = strstr_rs (line, "}"))) {
  457. parse = MAIN_HEAD;
  458. } else {
  459. goto parse_error;
  460. }
  461. break;
  462. case MAIN_LOGGING:
  463. if ((loc = strstr_rs (line, "logoutput:"))) {
  464. if (strcmp (loc, "file") == 0) {
  465. openais_config->logmode |= LOG_MODE_FILE;
  466. } else
  467. if (strcmp (loc, "syslog") == 0) {
  468. openais_config->logmode |= LOG_MODE_SYSLOG;
  469. } else
  470. if (strcmp (loc, "stderr") == 0) {
  471. openais_config->logmode |= LOG_MODE_STDERR;
  472. } else {
  473. goto parse_error;
  474. }
  475. } else
  476. if ((loc = strstr_rs (line, "debug:"))) {
  477. if (strcmp (loc, "on") == 0) {
  478. openais_config->logmode |= LOG_MODE_DEBUG;
  479. } else
  480. if (strcmp (loc, "off") == 0) {
  481. openais_config->logmode &= ~LOG_MODE_DEBUG;
  482. } else {
  483. goto parse_error;
  484. }
  485. } else
  486. if ((loc = strstr_rs (line, "timestamp:"))) {
  487. if (strcmp (loc, "on") == 0) {
  488. openais_config->logmode |= LOG_MODE_TIMESTAMP;
  489. } else
  490. if (strcmp (loc, "off") == 0) {
  491. openais_config->logmode &= ~LOG_MODE_TIMESTAMP;
  492. } else {
  493. goto parse_error;
  494. }
  495. } else
  496. if ((loc = strstr_rs (line, "logfile:"))) {
  497. openais_config->logfile = strdup (loc);
  498. } else
  499. if ((loc = strstr_rs (line, "}"))) {
  500. parse = MAIN_HEAD;
  501. } else {
  502. goto parse_error;
  503. }
  504. break;
  505. default:
  506. assert (0 == 1); /* SHOULDN'T HAPPEN */
  507. break;
  508. }
  509. }
  510. /*
  511. * Some error checking of parsed data to make sure its valid
  512. */
  513. parse_done = 1;
  514. if (openais_config->mcast_addr.sin_addr.s_addr == 0) {
  515. error_reason = "No multicast address specified";
  516. goto parse_error;
  517. }
  518. if (openais_config->mcast_addr.sin_port == 0) {
  519. error_reason = "No multicast port specified";
  520. goto parse_error;
  521. }
  522. if (openais_config->interface_count == 0) {
  523. error_reason = "No bindnet specified";
  524. goto parse_error;
  525. }
  526. if ((openais_config->logmode & LOG_MODE_FILE) && openais_config->logfile == 0) {
  527. error_reason = "logmode set to 'file' but no logfile specified";
  528. goto parse_error;
  529. }
  530. if (parse == MAIN_HEAD) {
  531. fclose (fp);
  532. return (0);
  533. } else {
  534. error_reason = "Missing closing brace";
  535. goto parse_error;
  536. }
  537. parse_error:
  538. if (parse_done) {
  539. sprintf (error_string_response,
  540. "parse error in /etc/ais/openais.conf: %s.\n", error_reason);
  541. } else {
  542. sprintf (error_string_response,
  543. "parse error in /etc/ais/openais.conf: %s (line %d).\n",
  544. error_reason, line_number);
  545. }
  546. *error_string = error_string_response;
  547. fclose (fp);
  548. return (-1);
  549. }