PageRenderTime 61ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/src/rec-int.c

#
C | 1269 lines | 988 code | 148 blank | 133 comment | 144 complexity | 34082ea47b4b20d13724d4a13a4838e9 MD5 | raw file
Possible License(s): GPL-3.0
  1. /* -*- mode: C -*-
  2. *
  3. * File: rec-int.c
  4. * Date: Thu Jul 15 18:23:26 2010
  5. *
  6. * GNU recutils - Data integrity.
  7. *
  8. */
  9. /* Copyright (C) 2010-2014 Jose E. Marchesi */
  10. /* This program is free software: you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation, either version 3 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  22. */
  23. #include <config.h>
  24. #include <stdio.h>
  25. #include <string.h>
  26. #include <stdlib.h>
  27. #include <regex.h>
  28. #include <gettext.h>
  29. #define _(str) dgettext (PACKAGE, str)
  30. #include <tempname.h>
  31. #if defined REMOTE_DESCRIPTORS
  32. # include <curl/curl.h>
  33. #endif
  34. #include <rec.h>
  35. #include <rec-utils.h>
  36. /*
  37. * Forward references.
  38. */
  39. static int rec_int_check_descriptor (rec_rset_t rset, rec_buf_t errors);
  40. static int rec_int_check_record_key (rec_rset_t rset,
  41. rec_record_t orig_record, rec_record_t record,
  42. rec_buf_t errors);
  43. static int rec_int_check_record_types (rec_db_t db,
  44. rec_rset_t rset,
  45. rec_record_t record,
  46. rec_buf_t errors);
  47. static int rec_int_check_record_mandatory (rec_rset_t rset, rec_record_t record,
  48. rec_buf_t errors);
  49. static int rec_int_check_record_unique (rec_rset_t rset, rec_record_t record,
  50. rec_buf_t errors);
  51. static int rec_int_check_record_prohibit (rec_rset_t rset, rec_record_t record,
  52. rec_buf_t errors);
  53. static int rec_int_check_record_sex_constraints (rec_rset_t rset, rec_record_t record,
  54. rec_buf_t errors);
  55. static int rec_int_check_record_allowed (rec_rset_t rset, rec_record_t record,
  56. rec_buf_t errors);
  57. #if defined REC_CRYPT_SUPPORT
  58. static int rec_int_check_record_secrets (rec_rset_t rset, rec_record_t record,
  59. rec_buf_t errors);
  60. #endif
  61. static int rec_int_merge_remote (rec_rset_t rset, rec_buf_t errors);
  62. static bool rec_int_rec_type_p (const char *str);
  63. /* The following macros are used by some functions in this file to
  64. reduce verbosity. */
  65. #define FNAME(id) rec_std_field_name ((id))
  66. #define ADD_ERROR(buf,str,...) \
  67. do \
  68. { \
  69. char *tmp = NULL; \
  70. if (asprintf (&tmp, (str), __VA_ARGS__) != -1) \
  71. { \
  72. rec_buf_puts (tmp, (buf)); \
  73. free (tmp); \
  74. } \
  75. } \
  76. while (0)
  77. /*
  78. * Public functions.
  79. */
  80. int
  81. rec_int_check_db (rec_db_t db,
  82. bool check_descriptors_p,
  83. bool remote_descriptors_p,
  84. rec_buf_t errors)
  85. {
  86. int ret;
  87. size_t db_size;
  88. size_t n_rset;
  89. rec_rset_t rset;
  90. ret = 0;
  91. db_size = rec_db_size (db);
  92. for (n_rset = 0; n_rset < db_size; n_rset++)
  93. {
  94. rset = rec_db_get_rset (db, n_rset);
  95. ret = ret + rec_int_check_rset (db,
  96. rset,
  97. check_descriptors_p,
  98. remote_descriptors_p,
  99. errors);
  100. }
  101. return ret;
  102. }
  103. int
  104. rec_int_check_rset (rec_db_t db,
  105. rec_rset_t rset,
  106. bool check_descriptor_p,
  107. bool remote_descriptor_p,
  108. rec_buf_t errors)
  109. {
  110. int res;
  111. rec_mset_iterator_t iter;
  112. rec_record_t record;
  113. rec_record_t descriptor;
  114. size_t num_records, min_records, max_records;
  115. res = 0;
  116. if (remote_descriptor_p
  117. && (descriptor = rec_rset_descriptor (rset)))
  118. {
  119. /* Make a backup of the record descriptor to restore it
  120. later. */
  121. descriptor = rec_record_dup (descriptor);
  122. /* Fetch the remote descriptor, if any, and merge it with the
  123. local descriptor. If there is any error, stop and report
  124. it. */
  125. res = rec_int_merge_remote (rset, errors);
  126. if (res > 0)
  127. {
  128. return res;
  129. }
  130. }
  131. if (check_descriptor_p)
  132. {
  133. res += rec_int_check_descriptor (rset, errors);
  134. }
  135. if (res > 0)
  136. {
  137. /* Stop here, since a lot of errors in the records will be
  138. generated due to errors in the record descriptor. */
  139. return res;
  140. }
  141. /* Verify rset size restrictions. */
  142. num_records = rec_rset_num_records (rset);
  143. min_records = rec_rset_min_records (rset);
  144. max_records = rec_rset_max_records (rset);
  145. if (min_records == max_records)
  146. {
  147. if (num_records != min_records)
  148. {
  149. ADD_ERROR (errors,
  150. _("%s: error: the number of records of type %s should be %zd.\n"),
  151. rec_rset_source (rset), rec_rset_type (rset), min_records);
  152. res++;
  153. }
  154. }
  155. else
  156. {
  157. if (num_records > rec_rset_max_records (rset))
  158. {
  159. ADD_ERROR (errors,
  160. _("%s: error: too many records of type %s. Maximum allowed are %zd.\n"),
  161. rec_rset_source (rset), rec_rset_type (rset), rec_rset_max_records (rset));
  162. res++;
  163. }
  164. if (num_records < rec_rset_min_records (rset))
  165. {
  166. ADD_ERROR (errors,
  167. _("%s: error: too few records of type %s. Minimum allowed are %zd.\n"),
  168. rec_rset_source (rset), rec_rset_type (rset), rec_rset_min_records (rset));
  169. res++;
  170. }
  171. }
  172. iter = rec_mset_iterator (rec_rset_mset (rset));
  173. while (rec_mset_iterator_next (&iter, MSET_RECORD, (const void **) &record, NULL))
  174. {
  175. res += rec_int_check_record (db,
  176. rset,
  177. record, record,
  178. errors);
  179. }
  180. rec_mset_iterator_free (&iter);
  181. if (remote_descriptor_p)
  182. {
  183. /* Restore the original descriptor in the record set. */
  184. rec_rset_set_descriptor (rset, descriptor);
  185. }
  186. return res;
  187. }
  188. int
  189. rec_int_check_record (rec_db_t db,
  190. rec_rset_t rset,
  191. rec_record_t orig_record,
  192. rec_record_t record,
  193. rec_buf_t errors)
  194. {
  195. int res;
  196. res =
  197. rec_int_check_record_key (rset, orig_record, record, errors)
  198. + rec_int_check_record_types (db, rset, record, errors)
  199. + rec_int_check_record_mandatory (rset, record, errors)
  200. + rec_int_check_record_unique (rset, record, errors)
  201. #if defined REC_CRYPT_SUPPORT
  202. + rec_int_check_record_secrets (rset, record, errors)
  203. #endif
  204. + rec_int_check_record_prohibit (rset, record, errors)
  205. + rec_int_check_record_sex_constraints (rset, record, errors)
  206. + rec_int_check_record_allowed (rset, record, errors);
  207. return res;
  208. }
  209. bool
  210. rec_int_check_field_type (rec_db_t db,
  211. rec_rset_t rset,
  212. rec_field_t field,
  213. rec_buf_t errors)
  214. {
  215. bool res = true;
  216. rec_type_t type;
  217. char *errors_str;
  218. res = true;
  219. /* Get the proper type to check 'field' with, checking with the type
  220. from the type registry of 'rset', if any. */
  221. type = rec_rset_get_field_type (rset, rec_field_name (field));
  222. /* Check the field with the type. This is done by simply invoking
  223. rec_type_check on the field value. An exception to this is the
  224. 'rec' type. The 'rec' type is used to implement foreign keys,
  225. and its effect on the type integrity system is that the value of
  226. the field must be considered to be of whatever type the primary
  227. key of the referred record set is. */
  228. if (type)
  229. {
  230. if (rec_type_kind (type) == REC_TYPE_REC)
  231. {
  232. /* Get the name of the referred record set. Check the type
  233. if and only if:
  234. - The referred rset exists in DB and
  235. - The referred rset has a primary key.
  236. - The primary key of the referred rset has a type.
  237. */
  238. const char *rset_type = rec_type_rec (type);
  239. rec_rset_t rset = rec_db_get_rset_by_type (db, rset_type);
  240. if (rset)
  241. {
  242. const char *key = rec_rset_key (rset);
  243. rec_type_t key_type = rec_rset_get_field_type (rset, key);
  244. if (key_type)
  245. {
  246. if (!rec_type_check (key_type, rec_field_value (field), &errors_str))
  247. {
  248. if (errors)
  249. {
  250. ADD_ERROR (errors,
  251. "%s:%s: error: %s\n",
  252. rec_field_source (field), rec_field_location_str (field),
  253. errors_str);
  254. }
  255. free (errors_str);
  256. res = false;
  257. }
  258. }
  259. }
  260. }
  261. else
  262. {
  263. if (!rec_type_check (type, rec_field_value (field), &errors_str))
  264. {
  265. if (errors)
  266. {
  267. ADD_ERROR (errors,
  268. "%s:%s: error: %s\n",
  269. rec_field_source (field), rec_field_location_str (field),
  270. errors_str);
  271. }
  272. free (errors_str);
  273. res = false;
  274. }
  275. }
  276. }
  277. return res;
  278. }
  279. /*
  280. * Private functions
  281. */
  282. static rec_fex_t
  283. rec_int_collect_field_list (rec_record_t record,
  284. const char *fname)
  285. {
  286. size_t i, j = 0;
  287. size_t num_fields = rec_record_get_num_fields_by_name (record, fname);
  288. rec_fex_t res = rec_fex_new (NULL, REC_FEX_SIMPLE);
  289. if (!res)
  290. return NULL; /* Out of memory. */
  291. for (i = 0; i < num_fields; i++)
  292. {
  293. rec_field_t field = rec_record_get_field_by_name (record, fname, i);
  294. rec_fex_t fex = rec_fex_new (rec_field_value (field), REC_FEX_SIMPLE);
  295. if (!fex)
  296. /* Invalid value in the field. Ignore it. */
  297. continue;
  298. for (j = 0; j < rec_fex_size (fex); j++)
  299. {
  300. rec_fex_elem_t elem = rec_fex_get (fex, j);
  301. char *field_name = strdup (rec_fex_elem_field_name (elem));
  302. if (!field_name
  303. || !rec_fex_append (res,
  304. field_name,
  305. rec_fex_elem_min (elem),
  306. rec_fex_elem_max (elem)))
  307. /* Not enough memory: panic and retreat! */
  308. return NULL;
  309. }
  310. rec_fex_destroy (fex);
  311. }
  312. return res;
  313. }
  314. static int
  315. rec_int_check_record_types (rec_db_t db,
  316. rec_rset_t rset,
  317. rec_record_t record,
  318. rec_buf_t errors)
  319. {
  320. int res;
  321. rec_field_t field;
  322. rec_mset_iterator_t iter;
  323. res = 0;
  324. iter = rec_mset_iterator (rec_record_mset (record));
  325. while (rec_mset_iterator_next (&iter, MSET_FIELD, (const void **) &field, NULL))
  326. {
  327. /* Check for the type. */
  328. if (!rec_int_check_field_type (db, rset, field, errors))
  329. {
  330. res++;
  331. }
  332. }
  333. rec_mset_iterator_free (&iter);
  334. return res;
  335. }
  336. static int
  337. rec_int_check_record_mandatory (rec_rset_t rset,
  338. rec_record_t record,
  339. rec_buf_t errors)
  340. {
  341. rec_fex_t fex_mandatory = NULL;
  342. int res = 0;
  343. size_t i;
  344. rec_record_t descriptor = rec_rset_descriptor (rset);
  345. if (descriptor)
  346. {
  347. fex_mandatory = rec_int_collect_field_list (descriptor, FNAME(REC_FIELD_MANDATORY));
  348. if (!fex_mandatory)
  349. {
  350. ADD_ERROR (errors, _("out of memory\n"), "");
  351. res = 1;
  352. goto cleanup;
  353. }
  354. /* Make sure that all fields in the mandatory fields list are in
  355. this record. */
  356. for (i = 0; i < rec_fex_size (fex_mandatory); i++)
  357. {
  358. const char *fname = rec_fex_elem_field_name (rec_fex_get (fex_mandatory, i));
  359. if (rec_record_get_num_fields_by_name (record, fname)
  360. == 0)
  361. {
  362. ADD_ERROR (errors,
  363. _("%s:%s: error: mandatory field '%s' not found in record\n"),
  364. rec_record_source (record),
  365. rec_record_location_str (record),
  366. fname);
  367. res++;
  368. }
  369. }
  370. }
  371. cleanup:
  372. rec_fex_destroy (fex_mandatory);
  373. return res;
  374. }
  375. static int
  376. rec_int_check_record_allowed (rec_rset_t rset,
  377. rec_record_t record,
  378. rec_buf_t errors)
  379. {
  380. /* If %allowed is specified then fields with names not in the union
  381. of %allowed + %mandatory + %key are not allowed in records, and
  382. thus that situation is an integrity error. */
  383. rec_fex_t fex_allowed = NULL;
  384. rec_fex_t fex_mandatory = NULL;
  385. rec_fex_t fex_key = NULL;
  386. int res = 0;
  387. rec_record_t descriptor = rec_rset_descriptor (rset);
  388. if (descriptor)
  389. {
  390. fex_allowed = rec_int_collect_field_list (descriptor, FNAME(REC_FIELD_ALLOWED));
  391. fex_mandatory = rec_int_collect_field_list (descriptor, FNAME(REC_FIELD_MANDATORY));
  392. fex_key = rec_int_collect_field_list (descriptor, FNAME(REC_FIELD_KEY));
  393. if (!fex_allowed || !fex_mandatory || !fex_key)
  394. {
  395. ADD_ERROR (errors, _("out of memory\n"), "");
  396. res = 1;
  397. goto cleanup;
  398. }
  399. if (rec_fex_size (fex_allowed) == 0)
  400. /* Nothing to do. */
  401. goto cleanup;
  402. /* Make sure that all the fields in RECORD are in either
  403. %allowed, %mandatory or %key. */
  404. rec_field_t field = NULL;
  405. rec_mset_iterator_t iter = rec_mset_iterator (rec_record_mset (record));
  406. while (rec_mset_iterator_next (&iter, MSET_FIELD, (const void **) &field, NULL))
  407. {
  408. const char *field_name = rec_field_name (field);
  409. if (!(rec_fex_member_p (fex_allowed, field_name, -1, -1)
  410. || rec_fex_member_p (fex_mandatory, field_name, -1, -1)
  411. || rec_fex_member_p (fex_key, field_name, -1, -1)))
  412. {
  413. /* This field is not allowed. */
  414. ADD_ERROR (errors,
  415. _("%s:%s: error: field '%s' not allowed in this record set\n"),
  416. rec_record_source (record),
  417. rec_record_location_str (record),
  418. field_name);
  419. res++;
  420. }
  421. }
  422. rec_mset_iterator_free (&iter);
  423. }
  424. cleanup:
  425. rec_fex_destroy (fex_allowed);
  426. rec_fex_destroy (fex_mandatory);
  427. rec_fex_destroy (fex_key);
  428. return res;
  429. }
  430. static int
  431. rec_int_check_record_unique (rec_rset_t rset,
  432. rec_record_t record,
  433. rec_buf_t errors)
  434. {
  435. rec_fex_t fex_unique = NULL;
  436. int res = 0;
  437. size_t i;
  438. rec_record_t descriptor = rec_rset_descriptor (rset);
  439. if (descriptor)
  440. {
  441. fex_unique = rec_int_collect_field_list (descriptor, FNAME(REC_FIELD_UNIQUE));
  442. if (!fex_unique)
  443. {
  444. ADD_ERROR (errors, _("out of memory\n"), "");
  445. res = 1;
  446. goto cleanup;
  447. }
  448. /* Make sure that all fields in the unique fields list are
  449. unique in this record. */
  450. for (i = 0; i < rec_fex_size (fex_unique); i++)
  451. {
  452. const char *fname = rec_fex_elem_field_name (rec_fex_get (fex_unique, i));
  453. if (rec_record_get_num_fields_by_name (record, fname) > 1)
  454. {
  455. ADD_ERROR (errors,
  456. _("%s:%s: error: field '%s' should be unique in this record\n"),
  457. rec_record_source (record),
  458. rec_record_location_str (record),
  459. fname);
  460. res++;
  461. }
  462. }
  463. }
  464. cleanup:
  465. rec_fex_destroy (fex_unique);
  466. return res;
  467. }
  468. static int
  469. rec_int_check_record_prohibit (rec_rset_t rset,
  470. rec_record_t record,
  471. rec_buf_t errors)
  472. {
  473. rec_fex_t fex_prohibit = NULL;
  474. int res = 0;
  475. size_t i;
  476. rec_record_t descriptor = rec_rset_descriptor (rset);
  477. if (descriptor)
  478. {
  479. fex_prohibit = rec_int_collect_field_list (descriptor, FNAME(REC_FIELD_PROHIBIT));
  480. if (!fex_prohibit)
  481. {
  482. ADD_ERROR (errors, _("out of memory\n"), "");
  483. res = 1;
  484. goto cleanup;
  485. }
  486. /* Make sure that no field in the prohibit fields list is
  487. present in the record. */
  488. for (i = 0; i < rec_fex_size (fex_prohibit); i++)
  489. {
  490. const char *fname = rec_fex_elem_field_name (rec_fex_get (fex_prohibit, i));
  491. if (rec_record_get_num_fields_by_name (record, fname) > 0)
  492. {
  493. ADD_ERROR (errors,
  494. _("%s:%s: error: prohibited field '%s' found in record\n"),
  495. rec_record_source (record),
  496. rec_record_location_str (record),
  497. fname);
  498. res++;
  499. }
  500. }
  501. }
  502. cleanup:
  503. rec_fex_destroy (fex_prohibit);
  504. return res;
  505. }
  506. static int
  507. rec_int_check_record_sex_constraints (rec_rset_t rset,
  508. rec_record_t record,
  509. rec_buf_t errors)
  510. {
  511. int res = 0;
  512. size_t i = 0;
  513. size_t num_constraints = rec_rset_num_sex_constraints (rset);
  514. for (i = 0; i < num_constraints; i++)
  515. {
  516. bool status = false;
  517. rec_sex_t sex = rec_rset_sex_constraint (rset, i);
  518. if (!rec_sex_eval (sex, record, &status))
  519. {
  520. ADD_ERROR (errors,
  521. _("%s:%s: error: %%constraint[%d] violated in record\n"),
  522. rec_record_source (record),
  523. rec_record_location_str (record),
  524. i);
  525. res++;
  526. }
  527. }
  528. return res;
  529. }
  530. #if defined REC_CRYPT_SUPPORT
  531. static int
  532. rec_int_check_record_secrets (rec_rset_t rset,
  533. rec_record_t record,
  534. rec_buf_t errors)
  535. {
  536. int res;
  537. rec_field_t field;
  538. rec_mset_iterator_t iter;
  539. res = 0;
  540. iter = rec_mset_iterator (rec_record_mset (record));
  541. while (rec_mset_iterator_next (&iter, MSET_FIELD, (const void**) &field, NULL))
  542. {
  543. /* If the field is confidential it must be encrypted. Encrypted
  544. field values can be recognized by the "encrypted-"
  545. prefix. */
  546. #define REC_ENCRYPTED_PREFIX "encrypted-"
  547. if (rec_rset_field_confidential_p (rset, rec_field_name (field))
  548. && (strncmp (rec_field_value (field),
  549. REC_ENCRYPTED_PREFIX,
  550. strlen (REC_ENCRYPTED_PREFIX)) != 0))
  551. {
  552. ADD_ERROR (errors,
  553. _("%s:%s: error: confidential field is not encrypted\n"),
  554. rec_record_source (record),
  555. rec_record_location_str (record));
  556. res++;
  557. }
  558. }
  559. rec_mset_iterator_free (&iter);
  560. return res;
  561. }
  562. #endif /* REC_CRYPT_SUPPORT */
  563. static int
  564. rec_int_check_record_key (rec_rset_t rset,
  565. rec_record_t orig_record,
  566. rec_record_t record,
  567. rec_buf_t errors)
  568. {
  569. int res;
  570. rec_record_t descriptor;
  571. rec_record_t other_record;
  572. rec_mset_iterator_t iter;
  573. char *key_field_name;
  574. rec_field_t field;
  575. rec_field_t key;
  576. rec_field_t other_key;
  577. bool duplicated_key;
  578. size_t i;
  579. size_t num_fields;
  580. res = 0;
  581. descriptor = rec_rset_descriptor (rset);
  582. if (descriptor)
  583. {
  584. for (i = 0; i < rec_record_get_num_fields_by_name (descriptor,
  585. FNAME(REC_FIELD_KEY));
  586. i++)
  587. {
  588. field = rec_record_get_field_by_name (descriptor, FNAME(REC_FIELD_KEY), i);
  589. /* Parse the field name from the value of %key: */
  590. key_field_name = rec_parse_field_name_str (rec_field_value (field));
  591. if (key_field_name)
  592. {
  593. num_fields = rec_record_get_num_fields_by_name (record, key_field_name);
  594. if (num_fields == 0)
  595. {
  596. ADD_ERROR (errors,
  597. _("%s:%s: error: key field '%s' not found in record\n"),
  598. rec_record_source (record),
  599. rec_record_location_str (record),
  600. rec_field_value (field));
  601. res++;
  602. }
  603. else if (num_fields > 1)
  604. {
  605. ADD_ERROR (errors,
  606. _("%s:%s: error: multiple key fields '%s' in record\n"),
  607. rec_record_source (record),
  608. rec_record_location_str (record),
  609. rec_field_value (field));
  610. res++;
  611. }
  612. else /* num_fields == 1 */
  613. {
  614. /* Check that the value specified as the key is
  615. unique in the whole record set. */
  616. key = rec_record_get_field_by_name (record,
  617. key_field_name,
  618. 0);
  619. duplicated_key = false;
  620. iter = rec_mset_iterator (rec_rset_mset (rset));
  621. while (rec_mset_iterator_next (&iter, MSET_RECORD, (const void**) &other_record, NULL))
  622. {
  623. if (other_record != orig_record)
  624. {
  625. /* XXX: Only the first key field is considered. */
  626. other_key = rec_record_get_field_by_name (other_record,
  627. key_field_name,
  628. 0);
  629. if (other_key)
  630. {
  631. if (strcmp (rec_field_value (other_key),
  632. rec_field_value (key)) == 0)
  633. {
  634. /* Found a key field with the same
  635. value in other record. */
  636. duplicated_key = true;
  637. break;
  638. }
  639. }
  640. }
  641. }
  642. rec_mset_iterator_free (&iter);
  643. if (duplicated_key)
  644. {
  645. ADD_ERROR (errors,
  646. _("%s:%s: error: duplicated key value in field '%s' in record\n"),
  647. rec_record_source (orig_record),
  648. rec_record_location_str (orig_record),
  649. rec_field_name (key));
  650. res++;
  651. break;
  652. }
  653. }
  654. free (key_field_name);
  655. }
  656. }
  657. }
  658. return res;
  659. }
  660. static int
  661. rec_int_check_descriptor (rec_rset_t rset,
  662. rec_buf_t errors)
  663. {
  664. int res;
  665. rec_record_t descriptor;
  666. rec_mset_iterator_t iter;
  667. rec_field_t field;
  668. const char *field_name;
  669. const char *field_value;
  670. rec_fex_t fex;
  671. const char *auto_field_name;
  672. size_t i;
  673. rec_type_t type;
  674. char *type_name = NULL;
  675. const char *p, *q = NULL;
  676. res = 0;
  677. descriptor = rec_rset_descriptor (rset);
  678. if (descriptor)
  679. {
  680. /* Check the type of the record set:
  681. 1. There should be one (and only one) %rec: field in the
  682. record.
  683. 2. The value of the %rec: field shall be well-formed.
  684. */
  685. if (rec_record_get_num_fields_by_name (descriptor, FNAME(REC_FIELD_REC)) == 0)
  686. {
  687. ADD_ERROR (errors,
  688. _("%s:%s: error: missing %%rec field in record descriptor\n"),
  689. rec_record_source (descriptor),
  690. rec_record_location_str (descriptor));
  691. res++;
  692. }
  693. else if (rec_record_get_num_fields_by_name (descriptor, FNAME(REC_FIELD_REC)) > 1)
  694. {
  695. ADD_ERROR (errors,
  696. _("%s:%s: error: too many %%rec fields in record descriptor\n"),
  697. rec_record_source (descriptor),
  698. rec_record_location_str (descriptor));
  699. res++;
  700. }
  701. field = rec_record_get_field_by_name (descriptor, FNAME(REC_FIELD_REC), 0);
  702. if (!rec_int_rec_type_p (rec_field_value (field)))
  703. {
  704. ADD_ERROR (errors,
  705. _("%s:%s: error: invalid record type %s\n"),
  706. rec_field_source (field),
  707. rec_field_location_str (field),
  708. rec_field_value (field));
  709. res++;
  710. }
  711. /* Only one 'key:' entry is allowed, if any. */
  712. if (rec_record_get_num_fields_by_name (descriptor, FNAME(REC_FIELD_KEY)) > 1)
  713. {
  714. ADD_ERROR (errors,
  715. _("%s:%s: error: only one %%key field is allowed in a record descriptor\n"),
  716. rec_record_source (descriptor),
  717. rec_record_location_str (descriptor));
  718. res++;
  719. }
  720. /* Only one 'size:' entry is allowed, if any. */
  721. if (rec_record_get_num_fields_by_name (descriptor, FNAME(REC_FIELD_SIZE)) > 1)
  722. {
  723. ADD_ERROR (errors,
  724. _("%s:%s: error: only one %%size field is allowed in a record descriptor\n"),
  725. rec_record_source (descriptor),
  726. rec_record_location_str (descriptor));
  727. res++;
  728. }
  729. /* Only one 'sort:' entry is allowed, if any. */
  730. if (rec_record_get_num_fields_by_name (descriptor, FNAME(REC_FIELD_SORT)) > 1)
  731. {
  732. ADD_ERROR (errors,
  733. _("%s:%s: error: only one %%sort field is allowed in a record descriptor\n"),
  734. rec_record_source (descriptor),
  735. rec_record_location_str (descriptor));
  736. res++;
  737. }
  738. /* Iterate on fields. */
  739. iter = rec_mset_iterator (rec_record_mset (descriptor));
  740. while (rec_mset_iterator_next (&iter, MSET_FIELD, (const void**) &field, NULL))
  741. {
  742. field_name = rec_field_name (field);
  743. field_value = rec_field_value (field);
  744. if (rec_field_name_equal_p (field_name, FNAME(REC_FIELD_TYPE)))
  745. {
  746. /* Check for the list of fields. */
  747. p = field_value;
  748. rec_skip_blanks (&p);
  749. if (!rec_parse_regexp (&p, "^" REC_FNAME_RE "(," REC_FNAME_RE ")*",
  750. NULL))
  751. {
  752. ADD_ERROR (errors,
  753. _("%s:%s: error: expected a comma-separated list of fields \
  754. before the type specification\n"),
  755. rec_field_source (field),
  756. rec_field_location_str (field));
  757. res++;
  758. }
  759. /* Check the type descriptor. Note that it can be
  760. either a type specification or a type name. */
  761. rec_skip_blanks (&p);
  762. if (!rec_type_descr_p (p))
  763. {
  764. q = p;
  765. if (rec_parse_regexp (&q, "^" REC_TYPE_NAME_RE "[ \t\n]*$",
  766. NULL))
  767. {
  768. /* The named type shall exist in the record set
  769. type registry.
  770. XXX: but this is probably a warning rather
  771. than an error. */
  772. rec_parse_regexp (&p, "^" REC_TYPE_NAME_RE, &type_name);
  773. if (!rec_type_reg_get (rec_rset_get_type_reg (rset), type_name))
  774. {
  775. ADD_ERROR (errors,
  776. _("%s:%s: error: the referred type %s \
  777. does not exist\n"),
  778. rec_field_source (field),
  779. rec_field_location_str (field),
  780. type_name);
  781. res++;
  782. }
  783. }
  784. else
  785. {
  786. /* XXX: make rec_type_descr_p to report more details. */
  787. ADD_ERROR (errors,
  788. _("%s:%s: error: invalid type specification\n"),
  789. rec_field_source (field),
  790. rec_field_location_str (field));
  791. res++;
  792. }
  793. }
  794. }
  795. else if (rec_field_name_equal_p (field_name, FNAME(REC_FIELD_TYPEDEF)))
  796. {
  797. /* Check for the type name. */
  798. p = field_value;
  799. rec_skip_blanks (&p);
  800. if (!rec_parse_regexp (&p, "^" REC_TYPE_NAME_RE, NULL))
  801. {
  802. ADD_ERROR (errors,
  803. _("%s:%s: error: expected a type name before the type \
  804. specification\n"),
  805. rec_field_source (field),
  806. rec_field_location_str (field));
  807. res++;
  808. }
  809. /* Check the type descriptor. Note that it can be
  810. either a type specification or a type name. */
  811. rec_skip_blanks (&p);
  812. if (!rec_type_descr_p (p))
  813. {
  814. q = p;
  815. if (rec_parse_regexp (&q, "^" REC_TYPE_NAME_RE "[ \t\n]*$",
  816. NULL))
  817. {
  818. /* The named type shall exist in the record set
  819. type registry.
  820. XXX: but this is probably a warning rather
  821. than an error. */
  822. rec_parse_regexp (&p, "^" REC_TYPE_NAME_RE, &type_name);
  823. if (!rec_type_reg_get (rec_rset_get_type_reg (rset), type_name))
  824. {
  825. ADD_ERROR (errors,
  826. _("%s:%s: error: the referred type %s \
  827. does not exist\n"),
  828. rec_field_source (field),
  829. rec_field_location_str (field),
  830. type_name);
  831. res++;
  832. }
  833. }
  834. else
  835. {
  836. /* XXX: make rec_type_descr_p to report more details. */
  837. ADD_ERROR (errors,
  838. _("%s:%s: error: invalid typedef specification\n"),
  839. rec_field_source (field),
  840. rec_field_location_str (field));
  841. res++;
  842. }
  843. }
  844. }
  845. else if (rec_field_name_equal_p (field_name, FNAME(REC_FIELD_CONSTRAINT)))
  846. {
  847. /* Check that the value of this field is a valid
  848. selection expression. */
  849. rec_sex_t sex = rec_sex_new (false);
  850. if (sex)
  851. {
  852. if (rec_sex_compile (sex, field_value))
  853. {
  854. rec_sex_destroy (sex);
  855. }
  856. else
  857. {
  858. ADD_ERROR (errors,
  859. _("%s:%s: error: value for %s[%zd] is not a valid selection expression\n"),
  860. rec_record_source (descriptor),
  861. rec_record_location_str (descriptor),
  862. rec_field_name (field),
  863. rec_record_get_field_index_by_name (descriptor, field));
  864. res++;
  865. }
  866. }
  867. else
  868. {
  869. /* Out of memory. */
  870. res++;
  871. }
  872. }
  873. else if (rec_field_name_equal_p (field_name, FNAME(REC_FIELD_MANDATORY))
  874. || rec_field_name_equal_p (field_name, FNAME(REC_FIELD_UNIQUE))
  875. || rec_field_name_equal_p (field_name, FNAME(REC_FIELD_PROHIBIT))
  876. || rec_field_name_equal_p (field_name, FNAME(REC_FIELD_AUTO))
  877. || rec_field_name_equal_p (field_name, FNAME(REC_FIELD_SORT))
  878. || rec_field_name_equal_p (field_name, FNAME(REC_FIELD_ALLOWED)))
  879. {
  880. /* Check that the value of this field is a parseable
  881. list of field names. */
  882. fex = rec_fex_new (field_value, REC_FEX_SIMPLE);
  883. if (fex)
  884. {
  885. rec_fex_destroy (fex);
  886. }
  887. else
  888. {
  889. ADD_ERROR (errors,
  890. _("%s:%s: error: value for %s[%zd] is not a list of field names\n"),
  891. rec_record_source (descriptor),
  892. rec_record_location_str (descriptor),
  893. rec_field_name (field),
  894. rec_record_get_field_index_by_name (descriptor, field));
  895. res++;
  896. }
  897. }
  898. else if (rec_field_name_equal_p (field_name, FNAME(REC_FIELD_SIZE)))
  899. {
  900. if (!rec_match (field_value, REC_INT_SIZE_RE))
  901. {
  902. ADD_ERROR (errors,
  903. _("%s:%s: error: value for %s should be a number optionally preceded by >, <, >= or <=.\n"),
  904. rec_field_source (field),
  905. rec_field_location_str (field),
  906. field_name);
  907. res++;
  908. }
  909. }
  910. #if defined REC_CRYPT_SUPPORT
  911. else if (rec_field_name_equal_p (field_name, FNAME(REC_FIELD_CONFIDENTIAL)))
  912. {
  913. if (!rec_match (field_value,
  914. "^"
  915. "[ \n\t]*" REC_FNAME_RE "([ \n\t]+" REC_FNAME_RE ")*"
  916. "[ \n\t]*$"))
  917. {
  918. ADD_ERROR (errors,
  919. _("%s:%s: error: value for %s should be a list of field names.\n"),
  920. rec_field_source (field),
  921. rec_field_location_str (field),
  922. field_name);
  923. res++;
  924. }
  925. }
  926. #endif /* REC_CRYPT_SUPPORT */
  927. if ((rec_field_name_equal_p (field_name, FNAME(REC_FIELD_AUTO)))
  928. && (fex = rec_fex_new (field_value, REC_FEX_SIMPLE)))
  929. {
  930. /* Check that the auto incremented fields have not been
  931. declared with a type other than 'int'. */
  932. for (i = 0; i < rec_fex_size (fex); i++)
  933. {
  934. auto_field_name = rec_fex_elem_field_name (rec_fex_get (fex, i));
  935. type = rec_rset_get_field_type (rset, auto_field_name);
  936. if ((!type) ||
  937. ! ((rec_type_kind (type) == REC_TYPE_INT)
  938. || (rec_type_kind (type) == REC_TYPE_RANGE)
  939. #if defined UUID_TYPE
  940. || (rec_type_kind (type) == REC_TYPE_UUID)
  941. #endif
  942. || (rec_type_kind (type) == REC_TYPE_DATE)))
  943. {
  944. ADD_ERROR (errors,
  945. #if defined UUID_TYPE
  946. _("%s:%s: error: auto-incremented field %s should be of type int, range, uuid or date\n"),
  947. #else
  948. _("%s:%s: error: auto-incremented field %s should be of type int, range or date\n"),
  949. #endif
  950. rec_record_source (descriptor),
  951. rec_record_location_str (descriptor),
  952. auto_field_name);
  953. res++;
  954. }
  955. }
  956. }
  957. }
  958. rec_mset_iterator_free (&iter);
  959. }
  960. return res;
  961. }
  962. int
  963. rec_int_merge_remote (rec_rset_t rset,
  964. rec_buf_t errors)
  965. {
  966. int res;
  967. rec_parser_t parser;
  968. rec_record_t descriptor;
  969. rec_db_t remote_db;
  970. rec_rset_t remote_rset;
  971. rec_field_t remote_field;
  972. rec_mset_iterator_t iter;
  973. rec_record_t remote_descriptor;
  974. rec_field_t rec_field;
  975. char *rec_type;
  976. char *rec_url = NULL;
  977. char *rec_file = NULL;
  978. char *rec_source = NULL;
  979. FILE *external_file;
  980. char tmpfile_name[14];
  981. res = 0;
  982. tmpfile_name[0] = '\0';
  983. /* If a remote descriptor is defined in the record descriptor of
  984. RSET, fetch it and merge it with the local descriptor. */
  985. descriptor = rec_rset_descriptor (rset);
  986. if (descriptor)
  987. {
  988. /* Check if there is an URL in the %rec: field. */
  989. rec_field = rec_record_get_field_by_name (descriptor, FNAME(REC_FIELD_REC), 0);
  990. if (!rec_int_rec_type_p (rec_field_value (rec_field)))
  991. {
  992. return 0;
  993. }
  994. rec_type = rec_extract_type (rec_field_value (rec_field));
  995. rec_file = rec_extract_file (rec_field_value (rec_field));
  996. rec_url = rec_extract_url (rec_field_value (rec_field));
  997. if (rec_file || rec_url)
  998. {
  999. if (rec_url)
  1000. {
  1001. #if defined REMOTE_DESCRIPTORS
  1002. CURL *curl;
  1003. int tmpfile_des;
  1004. /* Fetch the remote descriptor. */
  1005. curl = curl_easy_init ();
  1006. /* Create a temporary file. */
  1007. memcpy (tmpfile_name, "recint-XXXXXX", 13);
  1008. tmpfile_name[13] = '\0';
  1009. tmpfile_des = gen_tempname (tmpfile_name, 0, 0, GT_FILE);
  1010. external_file = fdopen (tmpfile_des, "r+");
  1011. /* Fetch the remote file. */
  1012. curl_easy_setopt (curl, CURLOPT_URL, rec_url);
  1013. curl_easy_setopt (curl, CURLOPT_WRITEDATA, external_file);
  1014. curl_easy_setopt (curl, CURLOPT_FAILONERROR, 1);
  1015. if (curl_easy_perform (curl) != 0)
  1016. {
  1017. ADD_ERROR (errors,
  1018. _("%s:%s: error: could not fetch remote descriptor from url %s.\n"),
  1019. rec_field_source (rec_field), rec_field_location_str (rec_field),
  1020. rec_url);
  1021. res++;
  1022. goto exit;
  1023. }
  1024. curl_easy_cleanup (curl);
  1025. rec_source = rec_url;
  1026. #else
  1027. goto exit;
  1028. #endif /* REMOTE_DESCRIPTORS */
  1029. }
  1030. else
  1031. {
  1032. /* Try to open the file. */
  1033. external_file = fopen (rec_file, "r");
  1034. if (!external_file)
  1035. {
  1036. ADD_ERROR (errors,
  1037. _("%s:%s: error: could not read external descriptor from file %s.\n"),
  1038. rec_field_source (rec_field), rec_field_location_str (rec_field),
  1039. rec_file);
  1040. res++;
  1041. goto exit;
  1042. }
  1043. rec_source = rec_file;
  1044. }
  1045. /* Parse the contents of the external file. */
  1046. fseek (external_file, 0, SEEK_SET);
  1047. parser = rec_parser_new (external_file, rec_source);
  1048. if (!rec_parse_db (parser, &remote_db))
  1049. {
  1050. ADD_ERROR (errors,
  1051. _("%s:%s: error: %s does not contain valid rec data.\n"),
  1052. rec_field_source (rec_field), rec_field_location_str (rec_field),
  1053. rec_source);
  1054. res++;
  1055. goto exit;
  1056. }
  1057. rec_parser_destroy (parser);
  1058. /* Get the proper external descriptor and merge it with
  1059. the local one. */
  1060. remote_rset = rec_db_get_rset_by_type (remote_db, rec_type);
  1061. if (!remote_rset)
  1062. {
  1063. ADD_ERROR (errors,
  1064. _("%s:%s: error: %s does not contain information for type %s.\n"),
  1065. rec_field_source (rec_field), rec_field_location_str (rec_field),
  1066. rec_source, rec_type);
  1067. res++;
  1068. goto exit;
  1069. }
  1070. remote_descriptor = rec_rset_descriptor (remote_rset);
  1071. if (!remote_descriptor)
  1072. {
  1073. /* Do nothing. */
  1074. goto exit;
  1075. }
  1076. iter = rec_mset_iterator (rec_record_mset (remote_descriptor));
  1077. while (rec_mset_iterator_next (&iter, MSET_FIELD, (const void**) &remote_field, NULL))
  1078. {
  1079. /* Merge the descriptors, but take care to not add a new
  1080. %rec: field. */
  1081. if (!rec_field_name_equal_p (rec_field_name (remote_field), FNAME(REC_FIELD_REC)))
  1082. {
  1083. rec_mset_append (rec_record_mset (descriptor), MSET_FIELD, (void *) rec_field_dup (remote_field), MSET_ANY);
  1084. }
  1085. }
  1086. rec_mset_iterator_free (&iter);
  1087. /* Update the record descriptor (triggering the creation
  1088. of a new type registry). */
  1089. rec_rset_set_descriptor (rset, rec_record_dup (descriptor));
  1090. rec_db_destroy (remote_db);
  1091. fclose (external_file);
  1092. }
  1093. }
  1094. exit:
  1095. if (rec_url && (tmpfile_name[0] != '\0'))
  1096. {
  1097. remove (tmpfile_name);
  1098. }
  1099. free (rec_url);
  1100. free (rec_file);
  1101. return res;
  1102. }
  1103. static bool
  1104. rec_int_rec_type_p (const char *str)
  1105. {
  1106. return rec_match (str,
  1107. "^[ \t]*"
  1108. REC_RECORD_TYPE_RE
  1109. "[ \n\t]*"
  1110. "("
  1111. "(" REC_URL_REGEXP ")"
  1112. "|"
  1113. "(" REC_FILE_REGEXP ")"
  1114. "[ \t]*)?"
  1115. "$");
  1116. }
  1117. /* End of rec-int.c */