PageRenderTime 56ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/src/common/parse_config.c

https://github.com/cfenoy/slurm
C | 1384 lines | 995 code | 137 blank | 252 comment | 313 complexity | 79c9fce4a3b84587d90d1292057bb024 MD5 | raw file
Possible License(s): GPL-2.0, AGPL-1.0
  1. /*****************************************************************************\
  2. * parse_config.c - parse any slurm.conf-like configuration file
  3. *
  4. * NOTE: when you see the prefix "s_p_", think "slurm parser".
  5. *****************************************************************************
  6. * Copyright (C) 2006-2007 The Regents of the University of California.
  7. * Copyright (C) 2008-2009 Lawrence Livermore National Security.
  8. * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
  9. * Written by Christopher J. Morrone <morrone2@llnl.gov>.
  10. * CODE-OCEC-09-009. All rights reserved.
  11. *
  12. * This file is part of SLURM, a resource management program.
  13. * For details, see <http://www.schedmd.com/slurmdocs/>.
  14. * Please also read the included file: DISCLAIMER.
  15. *
  16. * SLURM is free software; you can redistribute it and/or modify it under
  17. * the terms of the GNU General Public License as published by the Free
  18. * Software Foundation; either version 2 of the License, or (at your option)
  19. * any later version.
  20. *
  21. * In addition, as a special exception, the copyright holders give permission
  22. * to link the code of portions of this program with the OpenSSL library under
  23. * certain conditions as described in each individual source file, and
  24. * distribute linked combinations including the two. You must obey the GNU
  25. * General Public License in all respects for all of the code used other than
  26. * OpenSSL. If you modify file(s) with this exception, you may extend this
  27. * exception to your version of the file(s), but you are not obligated to do
  28. * so. If you do not wish to do so, delete this exception statement from your
  29. * version. If you delete this exception statement from all source files in
  30. * the program, then also delete it here.
  31. *
  32. * SLURM is distributed in the hope that it will be useful, but WITHOUT ANY
  33. * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  34. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  35. * details.
  36. *
  37. * You should have received a copy of the GNU General Public License along
  38. * with SLURM; if not, write to the Free Software Foundation, Inc.,
  39. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  40. \*****************************************************************************/
  41. #ifdef HAVE_CONFIG_H
  42. # include "config.h"
  43. #endif
  44. #include <ctype.h>
  45. #include <regex.h>
  46. #include <string.h>
  47. #include <sys/stat.h>
  48. #include <sys/types.h>
  49. #include <stdint.h>
  50. #include <stdlib.h>
  51. #include <unistd.h>
  52. /* #include "src/common/slurm_protocol_defs.h" */
  53. #include "src/common/log.h"
  54. #include "src/common/macros.h"
  55. #include "src/common/xmalloc.h"
  56. #include "src/common/xstring.h"
  57. #include "src/common/xassert.h"
  58. /* #include "src/common/slurm_rlimits_info.h" */
  59. #include "src/common/parse_config.h"
  60. #include "slurm/slurm.h"
  61. strong_alias(s_p_get_string, slurm_s_p_get_string);
  62. strong_alias(s_p_get_uint32, slurm_s_p_get_uint32);
  63. strong_alias(s_p_hashtbl_create, slurm_s_p_hashtbl_create);
  64. strong_alias(s_p_hashtbl_destroy, slurm_s_p_hashtbl_destroy);
  65. strong_alias(s_p_parse_file, slurm_s_p_parse_file);
  66. #define BUFFER_SIZE 4096
  67. #define CONF_HASH_LEN 26
  68. static regex_t keyvalue_re;
  69. static char *keyvalue_pattern =
  70. "^[[:space:]]*"
  71. "([[:alnum:]]+)" /* key */
  72. "[[:space:]]*=[[:space:]]*"
  73. "((\"([^\"]*)\")|([^[:space:]]+))" /* value: quoted with whitespace,
  74. * or unquoted and no whitespace */
  75. "([[:space:]]|$)";
  76. static bool keyvalue_initialized = false;
  77. struct s_p_values {
  78. char *key;
  79. int type;
  80. int data_count;
  81. void *data;
  82. int (*handler)(void **data, slurm_parser_enum_t type,
  83. const char *key, const char *value,
  84. const char *line, char **leftover);
  85. void (*destroy)(void *data);
  86. s_p_values_t *next;
  87. };
  88. /*
  89. * NOTE - "key" is case insensitive.
  90. */
  91. static int _conf_hashtbl_index(const char *key)
  92. {
  93. int i;
  94. int idx = 0;
  95. xassert(key);
  96. for (i = 0; i < 10; i++) {
  97. if (key[i] == '\0')
  98. break;
  99. idx += tolower((int)key[i]);
  100. }
  101. return idx % CONF_HASH_LEN;
  102. }
  103. static void _conf_hashtbl_insert(s_p_hashtbl_t *hashtbl,
  104. s_p_values_t *value)
  105. {
  106. int idx;
  107. xassert(value);
  108. idx = _conf_hashtbl_index(value->key);
  109. value->next = hashtbl[idx];
  110. hashtbl[idx] = value;
  111. }
  112. /*
  113. * NOTE - "key" is case insensitive.
  114. */
  115. static s_p_values_t *_conf_hashtbl_lookup(
  116. const s_p_hashtbl_t *hashtbl, const char *key)
  117. {
  118. int idx;
  119. s_p_values_t *p;
  120. xassert(key);
  121. if (hashtbl == NULL)
  122. return NULL;
  123. idx = _conf_hashtbl_index(key);
  124. for (p = hashtbl[idx]; p != NULL; p = p->next) {
  125. if (strcasecmp(p->key, key) == 0)
  126. return p;
  127. }
  128. return NULL;
  129. }
  130. s_p_hashtbl_t *s_p_hashtbl_create(s_p_options_t options[])
  131. {
  132. s_p_options_t *op = NULL;
  133. s_p_values_t *value = NULL;
  134. s_p_hashtbl_t *hashtbl = NULL;
  135. int len;
  136. len = CONF_HASH_LEN * sizeof(s_p_values_t *);
  137. hashtbl = (s_p_hashtbl_t *)xmalloc(len);
  138. for (op = options; op->key != NULL; op++) {
  139. value = xmalloc(sizeof(s_p_values_t));
  140. value->key = xstrdup(op->key);
  141. value->type = op->type;
  142. value->data_count = 0;
  143. value->data = NULL;
  144. value->next = NULL;
  145. value->handler = op->handler;
  146. value->destroy = op->destroy;
  147. _conf_hashtbl_insert(hashtbl, value);
  148. }
  149. return hashtbl;
  150. }
  151. /* Swap the data in two data structures without changing the linked list
  152. * pointers */
  153. static void _conf_hashtbl_swap_data(s_p_values_t *data_1,
  154. s_p_values_t *data_2)
  155. {
  156. s_p_values_t *next_1, *next_2;
  157. s_p_values_t tmp_values;
  158. next_1 = data_1->next;
  159. next_2 = data_2->next;
  160. memcpy(&tmp_values, data_1, sizeof(s_p_values_t));
  161. memcpy(data_1, data_2, sizeof(s_p_values_t));
  162. memcpy(data_2, &tmp_values, sizeof(s_p_values_t));
  163. data_1->next = next_1;
  164. data_2->next = next_2;
  165. }
  166. static void _conf_file_values_free(s_p_values_t *p)
  167. {
  168. int i;
  169. if (p->data_count > 0) {
  170. switch(p->type) {
  171. case S_P_ARRAY:
  172. for (i = 0; i < p->data_count; i++) {
  173. void **ptr_array = (void **)p->data;
  174. if (p->destroy != NULL) {
  175. p->destroy(ptr_array[i]);
  176. } else {
  177. xfree(ptr_array[i]);
  178. }
  179. }
  180. xfree(p->data);
  181. break;
  182. default:
  183. if (p->destroy != NULL) {
  184. p->destroy(p->data);
  185. } else {
  186. xfree(p->data);
  187. }
  188. break;
  189. }
  190. }
  191. xfree(p->key);
  192. xfree(p);
  193. }
  194. void s_p_hashtbl_destroy(s_p_hashtbl_t *hashtbl) {
  195. int i;
  196. s_p_values_t *p, *next;
  197. for (i = 0; i < CONF_HASH_LEN; i++) {
  198. for (p = hashtbl[i]; p != NULL; p = next) {
  199. next = p->next;
  200. _conf_file_values_free(p);
  201. }
  202. }
  203. xfree(hashtbl);
  204. }
  205. static void _keyvalue_regex_init(void)
  206. {
  207. if (!keyvalue_initialized) {
  208. if (regcomp(&keyvalue_re, keyvalue_pattern,
  209. REG_EXTENDED) != 0) {
  210. /* FIXME - should be fatal? */
  211. error("keyvalue regex compilation failed");
  212. }
  213. keyvalue_initialized = true;
  214. }
  215. }
  216. /*
  217. * IN line - string to be search for a key=value pair
  218. * OUT key - pointer to the key string (caller must free with xfree())
  219. * OUT value - pointer to the value string (caller must free with xfree())
  220. * OUT remaining - pointer into the "line" string denoting the start
  221. * of the unsearched portion of the string
  222. * Return 0 when a key-value pair is found, and -1 otherwise.
  223. */
  224. static int _keyvalue_regex(const char *line,
  225. char **key, char **value, char **remaining)
  226. {
  227. size_t nmatch = 8;
  228. regmatch_t pmatch[8];
  229. *key = NULL;
  230. *value = NULL;
  231. *remaining = (char *)line;
  232. memset(pmatch, 0, sizeof(regmatch_t)*nmatch);
  233. if (regexec(&keyvalue_re, line, nmatch, pmatch, 0)
  234. == REG_NOMATCH) {
  235. return -1;
  236. }
  237. *key = (char *)(xstrndup(line + pmatch[1].rm_so,
  238. pmatch[1].rm_eo - pmatch[1].rm_so));
  239. if (pmatch[4].rm_so != -1) {
  240. *value = (char *)(xstrndup(line + pmatch[4].rm_so,
  241. pmatch[4].rm_eo - pmatch[4].rm_so));
  242. } else if (pmatch[5].rm_so != -1) {
  243. *value = (char *)(xstrndup(line + pmatch[5].rm_so,
  244. pmatch[5].rm_eo - pmatch[5].rm_so));
  245. } else {
  246. *value = xstrdup("");
  247. }
  248. *remaining = (char *)(line + pmatch[2].rm_eo);
  249. return 0;
  250. }
  251. static int _strip_continuation(char *buf, int len)
  252. {
  253. char *ptr;
  254. int bs = 0;
  255. for (ptr = buf+len-1; ptr >= buf; ptr--) {
  256. if (*ptr == '\\')
  257. bs++;
  258. else if (isspace((int)*ptr) && bs == 0)
  259. continue;
  260. else
  261. break;
  262. }
  263. /* Check for an odd number of contiguous backslashes at
  264. the end of the line */
  265. if (bs % 2 == 1) {
  266. ptr = ptr + bs;
  267. *ptr = '\0';
  268. return (ptr - buf);
  269. } else {
  270. return len; /* no continuation */
  271. }
  272. }
  273. /*
  274. * Strip out trailing carriage returns and newlines
  275. */
  276. static void _strip_cr_nl(char *line)
  277. {
  278. int len = strlen(line);
  279. char *ptr;
  280. for (ptr = line+len-1; ptr >= line; ptr--) {
  281. if (*ptr=='\r' || *ptr=='\n') {
  282. *ptr = '\0';
  283. } else {
  284. return;
  285. }
  286. }
  287. }
  288. /* Strip comments from a line by terminating the string
  289. * where the comment begins.
  290. * Everything after a non-escaped "#" is a comment.
  291. */
  292. static void _strip_comments(char *line)
  293. {
  294. int i;
  295. int len = strlen(line);
  296. int bs_count = 0;
  297. for (i = 0; i < len; i++) {
  298. /* if # character is preceded by an even number of
  299. * escape characters '\' */
  300. if (line[i] == '#' && (bs_count%2) == 0) {
  301. line[i] = '\0';
  302. break;
  303. } else if (line[i] == '\\') {
  304. bs_count++;
  305. } else {
  306. bs_count = 0;
  307. }
  308. }
  309. }
  310. /*
  311. * Strips any escape characters, "\". If you WANT a back-slash,
  312. * it must be escaped, "\\".
  313. */
  314. static void _strip_escapes(char *line)
  315. {
  316. int i, j;
  317. int len = strlen(line);
  318. for (i = 0, j = 0; i < len+1; i++, j++) {
  319. if (line[i] == '\\')
  320. i++;
  321. line[j] = line[i];
  322. }
  323. }
  324. /* This can be used to make sure files are the same across nodes if
  325. * needed */
  326. static void _compute_hash_val(uint32_t *hash_val, char *line)
  327. {
  328. int idx, i, len;
  329. if(!hash_val)
  330. return;
  331. len = strlen(line);
  332. for (i = 0; i < len; i++) {
  333. (*hash_val) = ( (*hash_val) ^ line[i] << 8 );
  334. for (idx = 0; idx < 8; ++idx) {
  335. if ((*hash_val) & 0x8000) {
  336. (*hash_val) <<= 1;
  337. (*hash_val) = (*hash_val) ^ 4129;
  338. } else
  339. (*hash_val) <<= 1;
  340. }
  341. }
  342. }
  343. /*
  344. * Reads the next line from the "file" into buffer "buf".
  345. *
  346. * Concatonates together lines that are continued on
  347. * the next line by a trailing "\". Strips out comments,
  348. * replaces escaped "\#" with "#", and replaces "\\" with "\".
  349. */
  350. static int _get_next_line(char *buf, int buf_size,
  351. uint32_t *hash_val, FILE *file)
  352. {
  353. char *ptr = buf;
  354. int leftover = buf_size;
  355. int read_size, new_size;
  356. int lines = 0;
  357. while (fgets(ptr, leftover, file)) {
  358. lines++;
  359. _compute_hash_val(hash_val, ptr);
  360. _strip_comments(ptr);
  361. read_size = strlen(ptr);
  362. new_size = _strip_continuation(ptr, read_size);
  363. if (new_size < read_size) {
  364. ptr += new_size;
  365. leftover -= new_size;
  366. } else { /* no continuation */
  367. break;
  368. }
  369. }
  370. /* _strip_cr_nl(buf); */ /* not necessary */
  371. _strip_escapes(buf);
  372. return lines;
  373. }
  374. static int _handle_string(s_p_values_t *v,
  375. const char *value, const char *line, char **leftover)
  376. {
  377. if (v->data_count != 0) {
  378. error("%s specified more than once, latest value used",
  379. v->key);
  380. xfree(v->data);
  381. v->data_count = 0;
  382. }
  383. if (v->handler != NULL) {
  384. /* call the handler function */
  385. int rc;
  386. rc = v->handler(&v->data, v->type, v->key, value,
  387. line, leftover);
  388. if (rc != 1)
  389. return rc == 0 ? 0 : -1;
  390. } else {
  391. v->data = xstrdup(value);
  392. }
  393. v->data_count = 1;
  394. return 1;
  395. }
  396. static int _handle_long(s_p_values_t *v,
  397. const char *value, const char *line, char **leftover)
  398. {
  399. if (v->data_count != 0) {
  400. error("%s specified more than once, latest value used",
  401. v->key);
  402. xfree(v->data);
  403. v->data_count = 0;
  404. }
  405. if (v->handler != NULL) {
  406. /* call the handler function */
  407. int rc;
  408. rc = v->handler(&v->data, v->type, v->key, value,
  409. line, leftover);
  410. if (rc != 1)
  411. return rc == 0 ? 0 : -1;
  412. } else {
  413. char *endptr;
  414. long num;
  415. errno = 0;
  416. num = strtol(value, &endptr, 0);
  417. if ((num == 0 && errno == EINVAL)
  418. || (*endptr != '\0')) {
  419. if (strcasecmp(value, "UNLIMITED") == 0
  420. || strcasecmp(value, "INFINITE") == 0) {
  421. num = (long) INFINITE;
  422. } else {
  423. error("\"%s\" is not a valid number", value);
  424. return -1;
  425. }
  426. } else if (errno == ERANGE) {
  427. error("\"%s\" is out of range", value);
  428. return -1;
  429. }
  430. v->data = xmalloc(sizeof(long));
  431. *(long *)v->data = num;
  432. }
  433. v->data_count = 1;
  434. return 1;
  435. }
  436. static int _handle_uint16(s_p_values_t *v,
  437. const char *value, const char *line, char **leftover)
  438. {
  439. if (v->data_count != 0) {
  440. error("%s specified more than once, latest value used",
  441. v->key);
  442. xfree(v->data);
  443. v->data_count = 0;
  444. }
  445. if (v->handler != NULL) {
  446. /* call the handler function */
  447. int rc;
  448. rc = v->handler(&v->data, v->type, v->key, value,
  449. line, leftover);
  450. if (rc != 1)
  451. return rc == 0 ? 0 : -1;
  452. } else {
  453. char *endptr;
  454. unsigned long num;
  455. errno = 0;
  456. num = strtoul(value, &endptr, 0);
  457. if ((num == 0 && errno == EINVAL)
  458. || (*endptr != '\0')) {
  459. if (strcasecmp(value, "UNLIMITED") == 0
  460. || strcasecmp(value, "INFINITE") == 0) {
  461. num = (uint16_t) INFINITE;
  462. } else {
  463. error("%s value \"%s\" is not a valid number",
  464. v->key, value);
  465. return -1;
  466. }
  467. } else if (errno == ERANGE) {
  468. error("%s value (%s) is out of range", v->key, value);
  469. return -1;
  470. } else if (value[0] == '-') {
  471. error("%s value (%s) is less than zero", v->key,
  472. value);
  473. return -1;
  474. } else if (num > 0xffff) {
  475. error("%s value (%s) is greater than 65535", v->key,
  476. value);
  477. return -1;
  478. }
  479. v->data = xmalloc(sizeof(uint16_t));
  480. *(uint16_t *)v->data = (uint16_t)num;
  481. }
  482. v->data_count = 1;
  483. return 1;
  484. }
  485. static int _handle_uint32(s_p_values_t *v,
  486. const char *value, const char *line, char **leftover)
  487. {
  488. if (v->data_count != 0) {
  489. error("%s specified more than once, latest value used",
  490. v->key);
  491. xfree(v->data);
  492. v->data_count = 0;
  493. }
  494. if (v->handler != NULL) {
  495. /* call the handler function */
  496. int rc;
  497. rc = v->handler(&v->data, v->type, v->key, value,
  498. line, leftover);
  499. if (rc != 1)
  500. return rc == 0 ? 0 : -1;
  501. } else {
  502. char *endptr;
  503. unsigned long num;
  504. errno = 0;
  505. num = strtoul(value, &endptr, 0);
  506. if ((endptr[0] == 'k') || (endptr[0] == 'K')) {
  507. num *= 1024;
  508. endptr++;
  509. }
  510. if ((num == 0 && errno == EINVAL)
  511. || (*endptr != '\0')) {
  512. if ((strcasecmp(value, "UNLIMITED") == 0) ||
  513. (strcasecmp(value, "INFINITE") == 0)) {
  514. num = (uint32_t) INFINITE;
  515. } else {
  516. error("%s value (%s) is not a valid number",
  517. v->key, value);
  518. return -1;
  519. }
  520. } else if (errno == ERANGE) {
  521. error("%s value (%s) is out of range", v->key, value);
  522. return -1;
  523. } else if (value[0] == '-') {
  524. error("%s value (%s) is less than zero", v->key,
  525. value);
  526. return -1;
  527. } else if (num > 0xffffffff) {
  528. error("%s value (%s) is greater than 4294967295",
  529. v->key, value);
  530. return -1;
  531. }
  532. v->data = xmalloc(sizeof(uint32_t));
  533. *(uint32_t *)v->data = (uint32_t)num;
  534. }
  535. v->data_count = 1;
  536. return 1;
  537. }
  538. static int _handle_pointer(s_p_values_t *v,
  539. const char *value, const char *line,
  540. char **leftover)
  541. {
  542. if (v->handler != NULL) {
  543. /* call the handler function */
  544. int rc;
  545. rc = v->handler(&v->data, v->type, v->key, value,
  546. line, leftover);
  547. if (rc != 1)
  548. return rc == 0 ? 0 : -1;
  549. } else {
  550. if (v->data_count != 0) {
  551. error("%s specified more than once, "
  552. "latest value used", v->key);
  553. xfree(v->data);
  554. v->data_count = 0;
  555. }
  556. v->data = xstrdup(value);
  557. }
  558. v->data_count = 1;
  559. return 1;
  560. }
  561. static int _handle_array(s_p_values_t *v,
  562. const char *value, const char *line, char **leftover)
  563. {
  564. void *new_ptr;
  565. void **data;
  566. if (v->handler != NULL) {
  567. /* call the handler function */
  568. int rc;
  569. rc = v->handler(&new_ptr, v->type, v->key, value,
  570. line, leftover);
  571. if (rc != 1)
  572. return rc == 0 ? 0 : -1;
  573. } else {
  574. new_ptr = xstrdup(value);
  575. }
  576. v->data_count += 1;
  577. v->data = xrealloc(v->data, (v->data_count)*sizeof(void *));
  578. data = &((void**)v->data)[v->data_count-1];
  579. *data = new_ptr;
  580. return 1;
  581. }
  582. static int _handle_boolean(s_p_values_t *v,
  583. const char *value, const char *line,
  584. char **leftover)
  585. {
  586. if (v->data_count != 0) {
  587. error("%s specified more than once, latest value used",
  588. v->key);
  589. xfree(v->data);
  590. v->data_count = 0;
  591. }
  592. if (v->handler != NULL) {
  593. /* call the handler function */
  594. int rc;
  595. rc = v->handler(&v->data, v->type, v->key, value,
  596. line, leftover);
  597. if (rc != 1)
  598. return rc == 0 ? 0 : -1;
  599. } else {
  600. bool flag;
  601. if (!strcasecmp(value, "yes")
  602. || !strcasecmp(value, "up")
  603. || !strcasecmp(value, "1")) {
  604. flag = true;
  605. } else if (!strcasecmp(value, "no")
  606. || !strcasecmp(value, "down")
  607. || !strcasecmp(value, "0")) {
  608. flag = false;
  609. } else {
  610. error("\"%s\" is not a valid option for \"%s\"",
  611. value, v->key);
  612. return -1;
  613. }
  614. v->data = xmalloc(sizeof(bool));
  615. *(bool *)v->data = flag;
  616. }
  617. v->data_count = 1;
  618. return 1;
  619. }
  620. /*
  621. * IN line: the entire line that currently being parsed
  622. * IN/OUT leftover: leftover is a pointer into the "line" string.
  623. * The incoming leftover point is a pointer to the
  624. * character just after the already parsed key/value pair.
  625. * If the handler for that key parses more of the line,
  626. * it will move the leftover pointer to point to the character
  627. * after it has finished parsing in the line.
  628. */
  629. static void _handle_keyvalue_match(s_p_values_t *v,
  630. const char *value, const char *line,
  631. char **leftover)
  632. {
  633. /* debug3("key = %s, value = %s, line = \"%s\"", */
  634. /* v->key, value, line); */
  635. switch (v->type) {
  636. case S_P_IGNORE:
  637. /* do nothing */
  638. break;
  639. case S_P_STRING:
  640. _handle_string(v, value, line, leftover);
  641. break;
  642. case S_P_LONG:
  643. _handle_long(v, value, line, leftover);
  644. break;
  645. case S_P_UINT16:
  646. _handle_uint16(v, value, line, leftover);
  647. break;
  648. case S_P_UINT32:
  649. _handle_uint32(v, value, line, leftover);
  650. break;
  651. case S_P_POINTER:
  652. _handle_pointer(v, value, line, leftover);
  653. break;
  654. case S_P_ARRAY:
  655. _handle_array(v, value, line, leftover);
  656. break;
  657. case S_P_BOOLEAN:
  658. _handle_boolean(v, value, line, leftover);
  659. break;
  660. }
  661. }
  662. /*
  663. * Return 1 if all characters in "line" are white-space characters,
  664. * otherwise return 0.
  665. */
  666. static int _line_is_space(const char *line)
  667. {
  668. int len;
  669. int i;
  670. if (line == NULL) {
  671. return 1;
  672. }
  673. len = strlen(line);
  674. for (i = 0; i < len; i++) {
  675. if (!isspace((int)line[i]))
  676. return 0;
  677. }
  678. return 1;
  679. }
  680. /*
  681. * Returns 1 if the line is parsed cleanly, and 0 otherwise.
  682. */
  683. int s_p_parse_line(s_p_hashtbl_t *hashtbl, const char *line, char **leftover)
  684. {
  685. char *key, *value;
  686. char *ptr = (char *)line;
  687. s_p_values_t *p;
  688. char *new_leftover;
  689. _keyvalue_regex_init();
  690. while (_keyvalue_regex(ptr, &key, &value, &new_leftover) == 0) {
  691. if ((p = _conf_hashtbl_lookup(hashtbl, key))) {
  692. _handle_keyvalue_match(p, value,
  693. new_leftover, &new_leftover);
  694. *leftover = ptr = new_leftover;
  695. } else {
  696. error("Parsing error at unrecognized key: %s", key);
  697. xfree(key);
  698. xfree(value);
  699. return 0;
  700. }
  701. xfree(key);
  702. xfree(value);
  703. }
  704. return 1;
  705. }
  706. /*
  707. * Returns 1 if the line is parsed cleanly, and 0 otherwise.
  708. * IN ingore_new - if set do not treat unrecongized input as a fatal error
  709. */
  710. static int _parse_next_key(s_p_hashtbl_t *hashtbl,
  711. const char *line, char **leftover, bool ignore_new)
  712. {
  713. char *key, *value;
  714. s_p_values_t *p;
  715. char *new_leftover;
  716. _keyvalue_regex_init();
  717. if (_keyvalue_regex(line, &key, &value, &new_leftover) == 0) {
  718. if ((p = _conf_hashtbl_lookup(hashtbl, key))) {
  719. _handle_keyvalue_match(p, value,
  720. new_leftover, &new_leftover);
  721. *leftover = new_leftover;
  722. } else if (ignore_new) {
  723. debug("Parsing error at unrecognized key: %s", key);
  724. *leftover = (char *)line;
  725. } else {
  726. error("Parsing error at unrecognized key: %s", key);
  727. xfree(key);
  728. xfree(value);
  729. *leftover = (char *)line;
  730. return 0;
  731. }
  732. xfree(key);
  733. xfree(value);
  734. } else {
  735. *leftover = (char *)line;
  736. }
  737. return 1;
  738. }
  739. /*
  740. * Returns 1 if the line contained an include directive and the included
  741. * file was parsed without error. Returns -1 if the line was an include
  742. * directive but the included file contained errors. Returns 0 if
  743. * no include directive is found.
  744. */
  745. static int _parse_include_directive(s_p_hashtbl_t *hashtbl, uint32_t *hash_val,
  746. const char *line, char **leftover,
  747. bool ignore_new)
  748. {
  749. char *ptr;
  750. char *fn_start, *fn_stop;
  751. char *filename;
  752. *leftover = NULL;
  753. if (strncasecmp("include", line, strlen("include")) == 0) {
  754. ptr = (char *)line + strlen("include");
  755. if (!isspace((int)*ptr))
  756. return 0;
  757. while (isspace((int)*ptr))
  758. ptr++;
  759. fn_start = ptr;
  760. while (!isspace((int)*ptr))
  761. ptr++;
  762. fn_stop = *leftover = ptr;
  763. filename = xstrndup(fn_start, fn_stop-fn_start);
  764. if (s_p_parse_file(hashtbl, hash_val, filename, ignore_new)
  765. == SLURM_SUCCESS) {
  766. xfree(filename);
  767. return 1;
  768. } else {
  769. xfree(filename);
  770. return -1;
  771. }
  772. } else {
  773. return 0;
  774. }
  775. }
  776. int s_p_parse_file(s_p_hashtbl_t *hashtbl, uint32_t *hash_val, char *filename,
  777. bool ignore_new)
  778. {
  779. FILE *f;
  780. char line[BUFFER_SIZE];
  781. char *leftover = NULL;
  782. int rc = SLURM_SUCCESS;
  783. int line_number;
  784. int merged_lines;
  785. int inc_rc;
  786. struct stat stat_buf;
  787. if (!filename) {
  788. error("s_p_parse_file: No filename given.");
  789. return SLURM_ERROR;
  790. }
  791. _keyvalue_regex_init();
  792. if (stat(filename, &stat_buf) < 0) {
  793. info("s_p_parse_file: unable to status file \"%s\"", filename);
  794. return SLURM_ERROR;
  795. }
  796. if (stat_buf.st_size == 0) {
  797. info("s_p_parse_file: file \"%s\" is empty", filename);
  798. return SLURM_SUCCESS;
  799. }
  800. f = fopen(filename, "r");
  801. if (f == NULL) {
  802. error("s_p_parse_file: unable to read \"%s\": %m",
  803. filename);
  804. return SLURM_ERROR;
  805. }
  806. line_number = 1;
  807. while ((merged_lines = _get_next_line(
  808. line, BUFFER_SIZE, hash_val, f)) > 0) {
  809. /* skip empty lines */
  810. if (line[0] == '\0') {
  811. line_number += merged_lines;
  812. continue;
  813. }
  814. inc_rc = _parse_include_directive(hashtbl, hash_val,
  815. line, &leftover, ignore_new);
  816. if (inc_rc == 0) {
  817. _parse_next_key(hashtbl, line, &leftover, ignore_new);
  818. } else if (inc_rc < 0) {
  819. error("\"Include\" failed in file %s line %d",
  820. filename, line_number);
  821. rc = SLURM_ERROR;
  822. line_number += merged_lines;
  823. continue;
  824. }
  825. /* Make sure that after parsing only whitespace is left over */
  826. if (!_line_is_space(leftover)) {
  827. char *ptr = xstrdup(leftover);
  828. _strip_cr_nl(ptr);
  829. if (ignore_new) {
  830. debug("Parse error in file %s line %d: \"%s\"",
  831. filename, line_number, ptr);
  832. } else {
  833. error("Parse error in file %s line %d: \"%s\"",
  834. filename, line_number, ptr);
  835. rc = SLURM_ERROR;
  836. }
  837. xfree(ptr);
  838. }
  839. line_number += merged_lines;
  840. }
  841. fclose(f);
  842. return rc;
  843. }
  844. /*
  845. * s_p_hashtbl_merge
  846. *
  847. * Merge the contents of two s_p_hashtbl_t data structures. Anything in
  848. * from_hashtbl that does not also appear in to_hashtbl is transfered to it.
  849. * This is intended primary to support multiple lines of DEFAULT configuration
  850. * information and preserve the default values while adding new defaults.
  851. *
  852. * IN from_hashtbl - Source of old data
  853. * IN to_hashtbl - Destination for old data
  854. */
  855. void s_p_hashtbl_merge(s_p_hashtbl_t *to_hashtbl, s_p_hashtbl_t *from_hashtbl)
  856. {
  857. int i;
  858. s_p_values_t **val_pptr, *val_ptr, *match_ptr;
  859. if (!to_hashtbl || !from_hashtbl)
  860. return;
  861. for (i = 0; i < CONF_HASH_LEN; i++) {
  862. val_pptr = &from_hashtbl[i];
  863. val_ptr = from_hashtbl[i];
  864. while (val_ptr) {
  865. if (val_ptr->data_count == 0) {
  866. /* No data in from_hashtbl record to move.
  867. * Skip record */
  868. val_pptr = &val_ptr->next;
  869. val_ptr = val_ptr->next;
  870. continue;
  871. }
  872. match_ptr = _conf_hashtbl_lookup(to_hashtbl,
  873. val_ptr->key);
  874. if (match_ptr) { /* Found matching key */
  875. if (match_ptr->data_count == 0) {
  876. _conf_hashtbl_swap_data(val_ptr,
  877. match_ptr);
  878. }
  879. val_pptr = &val_ptr->next;
  880. val_ptr = val_ptr->next;
  881. } else { /* No match, move record */
  882. *val_pptr = val_ptr->next;
  883. val_ptr->next = NULL;
  884. _conf_hashtbl_insert(to_hashtbl, val_ptr);
  885. val_ptr = *val_pptr;
  886. }
  887. }
  888. }
  889. }
  890. /*
  891. * Returns 1 if the line is parsed cleanly, and 0 otherwise.
  892. */
  893. int s_p_parse_pair(s_p_hashtbl_t *hashtbl, const char *key, const char *value)
  894. {
  895. s_p_values_t *p;
  896. char *leftover, *v;
  897. if ((p = _conf_hashtbl_lookup(hashtbl, key)) == NULL) {
  898. error("Parsing error at unrecognized key: %s", key);
  899. return 0;
  900. }
  901. /* we have value separated from key here so parse it different way */
  902. while (*value != '\0' && isspace(*value))
  903. value++; /* skip spaces at start if any */
  904. if (*value == '"') { /* quoted value */
  905. v = (char *)value + 1;
  906. leftover = strchr(v, '"');
  907. if (leftover == NULL) {
  908. error("Parse error in data for key %s: %s", key, value);
  909. return 0;
  910. }
  911. } else { /* unqouted value */
  912. leftover = v = (char *)value;
  913. while (*leftover != '\0' && !isspace(*leftover))
  914. leftover++;
  915. }
  916. value = xstrndup(v, leftover - v);
  917. if (*leftover != '\0')
  918. leftover++;
  919. while (*leftover != '\0' && isspace(*leftover))
  920. leftover++; /* skip trailing spaces */
  921. _handle_keyvalue_match(p, value, leftover, &leftover);
  922. xfree(value);
  923. return 1;
  924. }
  925. /*
  926. * s_p_get_string
  927. *
  928. * Search for a key in a s_p_hashtbl_t with value of type
  929. * string. If the key is found and has a set value, the
  930. * value is retuned in "str".
  931. *
  932. * OUT str - pointer to a copy of the string value
  933. * (caller is resonsible for freeing str with xfree())
  934. * IN key - hash table key.
  935. * IN hashtbl - hash table created by s_p_hashtbl_create()
  936. *
  937. * Returns 1 when a value was set for "key" during parsing and "str"
  938. * was successfully set, otherwise returns 0;
  939. *
  940. * NOTE: Caller is responsible for freeing the returned string with xfree!
  941. */
  942. int s_p_get_string(char **str, const char *key, const s_p_hashtbl_t *hashtbl)
  943. {
  944. s_p_values_t *p;
  945. if (!hashtbl)
  946. return 0;
  947. p = _conf_hashtbl_lookup(hashtbl, key);
  948. if (p == NULL) {
  949. error("Invalid key \"%s\"", key);
  950. return 0;
  951. }
  952. if (p->type != S_P_STRING) {
  953. error("Key \"%s\" is not a string", key);
  954. return 0;
  955. }
  956. if (p->data_count == 0) {
  957. return 0;
  958. }
  959. *str = xstrdup((char *)p->data);
  960. return 1;
  961. }
  962. /*
  963. * s_p_get_long
  964. *
  965. * Search for a key in a s_p_hashtbl_t with value of type
  966. * long. If the key is found and has a set value, the
  967. * value is retuned in "num".
  968. *
  969. * OUT num - pointer to a long where the value is returned
  970. * IN key - hash table key
  971. * IN hashtbl - hash table created by s_p_hashtbl_create()
  972. *
  973. * Returns 1 when a value was set for "key" during parsing and "num"
  974. * was successfully set, otherwise returns 0;
  975. */
  976. int s_p_get_long(long *num, const char *key, const s_p_hashtbl_t *hashtbl)
  977. {
  978. s_p_values_t *p;
  979. if (!hashtbl)
  980. return 0;
  981. p = _conf_hashtbl_lookup(hashtbl, key);
  982. if (p == NULL) {
  983. error("Invalid key \"%s\"", key);
  984. return 0;
  985. }
  986. if (p->type != S_P_LONG) {
  987. error("Key \"%s\" is not a long", key);
  988. return 0;
  989. }
  990. if (p->data_count == 0) {
  991. return 0;
  992. }
  993. *num = *(long *)p->data;
  994. return 1;
  995. }
  996. /*
  997. * s_p_get_uint16
  998. *
  999. * Search for a key in a s_p_hashtbl_t with value of type
  1000. * uint16. If the key is found and has a set value, the
  1001. * value is retuned in "num".
  1002. *
  1003. * OUT num - pointer to a uint16_t where the value is returned
  1004. * IN key - hash table key
  1005. * IN hashtbl - hash table created by s_p_hashtbl_create()
  1006. *
  1007. * Returns 1 when a value was set for "key" during parsing and "num"
  1008. * was successfully set, otherwise returns 0;
  1009. */
  1010. int s_p_get_uint16(uint16_t *num, const char *key,
  1011. const s_p_hashtbl_t *hashtbl)
  1012. {
  1013. s_p_values_t *p;
  1014. if (!hashtbl)
  1015. return 0;
  1016. p = _conf_hashtbl_lookup(hashtbl, key);
  1017. if (p == NULL) {
  1018. error("Invalid key \"%s\"", key);
  1019. return 0;
  1020. }
  1021. if (p->type != S_P_UINT16) {
  1022. error("Key \"%s\" is not a uint16_t", key);
  1023. return 0;
  1024. }
  1025. if (p->data_count == 0) {
  1026. return 0;
  1027. }
  1028. *num = *(uint16_t *)p->data;
  1029. return 1;
  1030. }
  1031. /*
  1032. * s_p_get_uint32
  1033. *
  1034. * Search for a key in a s_p_hashtbl_t with value of type
  1035. * uint32. If the key is found and has a set value, the
  1036. * value is retuned in "num".
  1037. *
  1038. * OUT num - pointer to a uint32_t where the value is returned
  1039. * IN key - hash table key
  1040. * IN hashtbl - hash table created by s_p_hashtbl_create()
  1041. *
  1042. * Returns 1 when a value was set for "key" during parsing and "num"
  1043. * was successfully set, otherwise returns 0;
  1044. */
  1045. int s_p_get_uint32(uint32_t *num, const char *key,
  1046. const s_p_hashtbl_t *hashtbl)
  1047. {
  1048. s_p_values_t *p;
  1049. if (!hashtbl)
  1050. return 0;
  1051. p = _conf_hashtbl_lookup(hashtbl, key);
  1052. if (p == NULL) {
  1053. error("Invalid key \"%s\"", key);
  1054. return 0;
  1055. }
  1056. if (p->type != S_P_UINT32) {
  1057. error("Key \"%s\" is not a uint32_t", key);
  1058. return 0;
  1059. }
  1060. if (p->data_count == 0) {
  1061. return 0;
  1062. }
  1063. *num = *(uint32_t *)p->data;
  1064. return 1;
  1065. }
  1066. /*
  1067. * s_p_get_pointer
  1068. *
  1069. * Search for a key in a s_p_hashtbl_t with value of type
  1070. * pointer. If the key is found and has a set value, the
  1071. * value is retuned in "ptr".
  1072. *
  1073. * OUT ptr - pointer to a void pointer where the value is returned
  1074. * IN key - hash table key
  1075. * IN hashtbl - hash table created by s_p_hashtbl_create()
  1076. *
  1077. * Returns 1 when a value was set for "key" during parsing and "ptr"
  1078. * was successfully set, otherwise returns 0;
  1079. */
  1080. int s_p_get_pointer(void **ptr, const char *key, const s_p_hashtbl_t *hashtbl)
  1081. {
  1082. s_p_values_t *p;
  1083. if (!hashtbl)
  1084. return 0;
  1085. p = _conf_hashtbl_lookup(hashtbl, key);
  1086. if (p == NULL) {
  1087. error("Invalid key \"%s\"", key);
  1088. return 0;
  1089. }
  1090. if (p->type != S_P_POINTER) {
  1091. error("Key \"%s\" is not a pointer", key);
  1092. return 0;
  1093. }
  1094. if (p->data_count == 0) {
  1095. return 0;
  1096. }
  1097. *ptr = p->data;
  1098. return 1;
  1099. }
  1100. /*
  1101. * s_p_get_array
  1102. *
  1103. * Most s_p_ data types allow a key to appear only once in a file
  1104. * (s_p_parse_file) or line (s_p_parse_line). S_P_ARRAY is the exception.
  1105. *
  1106. * S_P_ARRAY allows a key to appear any number of times. Each time
  1107. * a particular key is found the value array grows by one element, and
  1108. * that element contains a pointer to the newly parsed value. You can
  1109. * think of this as being an array of S_P_POINTER types.
  1110. *
  1111. * OUT ptr_array - pointer to void pointer-pointer where the value is returned
  1112. * OUT count - length of ptr_array
  1113. * IN key - hash table key
  1114. * IN hashtbl - hash table created by s_p_hashtbl_create()
  1115. *
  1116. * Returns 1 when a value was set for "key" during parsing and both
  1117. * "ptr_array" and "count" were successfully set, otherwise returns 0.
  1118. */
  1119. int s_p_get_array(void **ptr_array[], int *count,
  1120. const char *key, const s_p_hashtbl_t *hashtbl)
  1121. {
  1122. s_p_values_t *p;
  1123. if (!hashtbl)
  1124. return 0;
  1125. p = _conf_hashtbl_lookup(hashtbl, key);
  1126. if (p == NULL) {
  1127. error("Invalid key \"%s\"", key);
  1128. return 0;
  1129. }
  1130. if (p->type != S_P_ARRAY) {
  1131. error("Key \"%s\" is not an array", key);
  1132. return 0;
  1133. }
  1134. if (p->data_count == 0) {
  1135. return 0;
  1136. }
  1137. *ptr_array = (void **)p->data;
  1138. *count = p->data_count;
  1139. return 1;
  1140. }
  1141. /*
  1142. * s_p_get_boolean
  1143. *
  1144. * Search for a key in a s_p_hashtbl_t with value of type
  1145. * boolean. If the key is found and has a set value, the
  1146. * value is retuned in "flag".
  1147. *
  1148. * OUT flag - pointer to a bool where the value is returned
  1149. * IN key - hash table key
  1150. * IN hashtbl - hash table created by s_p_hashtbl_create()
  1151. *
  1152. * Returns 1 when a value was set for "key" during parsing and "num"
  1153. * was successfully set, otherwise returns 0;
  1154. */
  1155. int s_p_get_boolean(bool *flag, const char *key, const s_p_hashtbl_t *hashtbl)
  1156. {
  1157. s_p_values_t *p;
  1158. if (!hashtbl)
  1159. return 0;
  1160. p = _conf_hashtbl_lookup(hashtbl, key);
  1161. if (p == NULL) {
  1162. error("Invalid key \"%s\"", key);
  1163. return 0;
  1164. }
  1165. if (p->type != S_P_BOOLEAN) {
  1166. error("Key \"%s\" is not a boolean", key);
  1167. return 0;
  1168. }
  1169. if (p->data_count == 0) {
  1170. return 0;
  1171. }
  1172. *flag = *(bool *)p->data;
  1173. return 1;
  1174. }
  1175. /*
  1176. * Given an "options" array, print the current values of all
  1177. * options in supplied hash table "hashtbl".
  1178. *
  1179. * Primarily for debugging purposes.
  1180. */
  1181. void s_p_dump_values(const s_p_hashtbl_t *hashtbl,
  1182. const s_p_options_t options[])
  1183. {
  1184. const s_p_options_t *op = NULL;
  1185. long num;
  1186. uint16_t num16;
  1187. uint32_t num32;
  1188. char *str;
  1189. void *ptr;
  1190. void **ptr_array;
  1191. int count;
  1192. bool flag;
  1193. for (op = options; op->key != NULL; op++) {
  1194. switch(op->type) {
  1195. case S_P_STRING:
  1196. if (s_p_get_string(&str, op->key, hashtbl)) {
  1197. verbose("%s = %s", op->key, str);
  1198. xfree(str);
  1199. } else {
  1200. verbose("%s", op->key);
  1201. }
  1202. break;
  1203. case S_P_LONG:
  1204. if (s_p_get_long(&num, op->key, hashtbl))
  1205. verbose("%s = %ld", op->key, num);
  1206. else
  1207. verbose("%s", op->key);
  1208. break;
  1209. case S_P_UINT16:
  1210. if (s_p_get_uint16(&num16, op->key, hashtbl))
  1211. verbose("%s = %hu", op->key, num16);
  1212. else
  1213. verbose("%s", op->key);
  1214. break;
  1215. case S_P_UINT32:
  1216. if (s_p_get_uint32(&num32, op->key, hashtbl))
  1217. verbose("%s = %u", op->key, num32);
  1218. else
  1219. verbose("%s", op->key);
  1220. break;
  1221. case S_P_POINTER:
  1222. if (s_p_get_pointer(&ptr, op->key, hashtbl))
  1223. verbose("%s = %zx", op->key, (size_t)ptr);
  1224. else
  1225. verbose("%s", op->key);
  1226. break;
  1227. case S_P_ARRAY:
  1228. if (s_p_get_array(&ptr_array, &count,
  1229. op->key, hashtbl)) {
  1230. verbose("%s, count = %d", op->key, count);
  1231. } else {
  1232. verbose("%s", op->key);
  1233. }
  1234. break;
  1235. case S_P_BOOLEAN:
  1236. if (s_p_get_boolean(&flag, op->key, hashtbl)) {
  1237. verbose("%s = %s", op->key,
  1238. flag ? "TRUE" : "FALSE");
  1239. } else {
  1240. verbose("%s", op->key);
  1241. }
  1242. break;
  1243. case S_P_IGNORE:
  1244. break;
  1245. }
  1246. }
  1247. }