PageRenderTime 784ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/mu/dbm.c

#
C | 1868 lines | 1799 code | 54 blank | 15 comment | 70 complexity | 77b547bebc4012f2daa0aff4e403f483 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-3.0, CC-BY-SA-3.0
  1. /* GNU Mailutils -- a suite of utilities for electronic mail
  2. Copyright (C) 2010-2012, 2014 Free Software Foundation, Inc.
  3. GNU Mailutils is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 3, or (at your option)
  6. any later version.
  7. GNU Mailutils is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
  13. #if defined(HAVE_CONFIG_H)
  14. # include <config.h>
  15. #endif
  16. #include <sys/types.h>
  17. #include <sys/stat.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <grp.h>
  21. #include <sysexits.h>
  22. #include <fnmatch.h>
  23. #include <regex.h>
  24. #include <mailutils/mailutils.h>
  25. #include <mailutils/dbm.h>
  26. #include "argp.h"
  27. #include "mu.h"
  28. static char dbm_doc[] = N_("mu dbm - DBM management tool\n"
  29. "Valid COMMANDs are:\n"
  30. "\n"
  31. " create or load - create the database\n"
  32. " dump - dump the database\n"
  33. " list - list contents of the database\n"
  34. " delete - delete specified keys from the database\n"
  35. " add - add records to the database\n"
  36. " replace - add records replacing ones with matching keys\n");
  37. char dbm_docstring[] = N_("DBM management tool");
  38. static char dbm_args_doc[] = N_("COMMAND FILE [KEY...]");
  39. enum mode
  40. {
  41. mode_list,
  42. mode_dump,
  43. mode_create,
  44. mode_delete,
  45. mode_add,
  46. mode_replace,
  47. };
  48. enum key_type
  49. {
  50. key_literal,
  51. key_glob,
  52. key_regex
  53. };
  54. static enum mode mode;
  55. static char *db_name;
  56. static char *input_file;
  57. static int file_mode = 0600;
  58. static struct mu_auth_data *auth;
  59. static uid_t owner_uid;
  60. static gid_t owner_gid;
  61. static char *owner_user;
  62. static char *owner_group;
  63. static int copy_permissions;
  64. #define META_FILE_MODE 0x0001
  65. #define META_UID 0x0002
  66. #define META_GID 0x0004
  67. #define META_USER 0x0008
  68. #define META_GROUP 0x0010
  69. #define META_AUTH 0x0020
  70. static int known_meta_data;
  71. static enum key_type key_type = key_literal;
  72. static int case_sensitive = 1;
  73. static int include_zero = -1;
  74. static int suppress_header = -1;
  75. static void
  76. init_datum (struct mu_dbm_datum *key, char *str)
  77. {
  78. memset (key, 0, sizeof *key);
  79. key->mu_dptr = str;
  80. key->mu_dsize = strlen (str) + !!include_zero;
  81. }
  82. static mu_dbm_file_t
  83. open_db_file (int mode)
  84. {
  85. int rc;
  86. mu_dbm_file_t db;
  87. if (!db_name)
  88. {
  89. mu_error (_("database name not given"));
  90. exit (EX_USAGE);
  91. }
  92. rc = mu_dbm_create (db_name, &db, 0);
  93. if (rc)
  94. {
  95. mu_diag_output (MU_DIAG_ERROR, _("unable to create database %s: %s"),
  96. db_name, mu_strerror (rc));
  97. exit (EX_SOFTWARE);
  98. }
  99. rc = mu_dbm_open (db, mode, file_mode);
  100. if (rc)
  101. {
  102. mu_diag_funcall (MU_DIAG_ERROR, "mu_dbm_open", db_name, rc);
  103. exit (EX_SOFTWARE);
  104. }
  105. return db;
  106. }
  107. static void
  108. set_db_ownership (mu_dbm_file_t db)
  109. {
  110. int rc, dirfd, pagfd;
  111. struct stat st;
  112. rc = mu_dbm_get_fd (db, &pagfd, &dirfd);
  113. if (rc)
  114. {
  115. mu_diag_funcall (MU_DIAG_ERROR, "mu_dbm_get_fd", db_name, rc);
  116. exit (EX_SOFTWARE);
  117. }
  118. if (known_meta_data & META_USER)
  119. {
  120. struct mu_auth_data *ap;
  121. ap = mu_get_auth_by_name (owner_user);
  122. if (!ap)
  123. {
  124. if (!(known_meta_data & META_UID))
  125. {
  126. mu_error (_("no such user: %s"), owner_user);
  127. exit (EX_NOUSER);
  128. }
  129. }
  130. else
  131. {
  132. owner_uid = ap->uid;
  133. known_meta_data |= META_UID;
  134. mu_auth_data_free (ap);
  135. }
  136. }
  137. if (known_meta_data & META_GROUP)
  138. {
  139. struct group *gr = getgrnam (owner_group);
  140. if (!gr)
  141. {
  142. if (!(known_meta_data & META_GID))
  143. {
  144. mu_error (_("no such group: %s"), owner_group);
  145. exit (EX_DATAERR);
  146. }
  147. }
  148. else
  149. {
  150. owner_gid = gr->gr_gid;
  151. known_meta_data |= META_GID;
  152. }
  153. }
  154. if (fstat (dirfd, &st))
  155. {
  156. mu_diag_funcall (MU_DIAG_ERROR, "fstat", db_name, errno);
  157. exit (EX_SOFTWARE);
  158. }
  159. if (known_meta_data & META_FILE_MODE)
  160. {
  161. if (fchmod (pagfd, file_mode) ||
  162. (pagfd != dirfd && fchmod (dirfd, file_mode)))
  163. {
  164. mu_diag_funcall (MU_DIAG_ERROR, "fchmod", db_name, errno);
  165. exit (EX_SOFTWARE);
  166. }
  167. }
  168. if (known_meta_data & (META_UID|META_GID))
  169. {
  170. if (!(known_meta_data & META_UID))
  171. owner_uid = st.st_uid;
  172. else if (!(known_meta_data & META_GID))
  173. owner_gid = st.st_gid;
  174. if (fchown (pagfd, owner_uid, owner_gid) ||
  175. (pagfd != dirfd && fchown (dirfd, owner_uid, owner_gid)))
  176. {
  177. mu_diag_funcall (MU_DIAG_ERROR, "fchown", db_name, errno);
  178. exit (EX_SOFTWARE);
  179. }
  180. }
  181. }
  182. #define IOBUF_REREAD 1
  183. #define IOBUF_EOF 2
  184. struct iobuf
  185. {
  186. mu_stream_t stream;
  187. char *buffer;
  188. size_t bufsize;
  189. size_t length;
  190. int flag; /* 0 or one of the IOBUF_ constants above. */
  191. };
  192. static int is_dbm_directive (struct iobuf *input);
  193. static int is_len_directive (struct iobuf *input);
  194. static int is_ignored_directive (const char *name);
  195. static int set_directive (char *val);
  196. static void print_header (const char *name, mu_stream_t str);
  197. #define input_eof(iob) ((iob)->flag == IOBUF_EOF)
  198. static int
  199. input_getline (struct iobuf *inp)
  200. {
  201. int rc;
  202. size_t len;
  203. switch (inp->flag)
  204. {
  205. case 0:
  206. break;
  207. case IOBUF_REREAD:
  208. inp->flag = 0;
  209. return 0;
  210. case IOBUF_EOF:
  211. inp->length = 0;
  212. return 0;
  213. }
  214. while (1)
  215. {
  216. rc = mu_stream_getline (inp->stream, &inp->buffer, &inp->bufsize, &len);
  217. if (rc)
  218. return rc;
  219. if (len == 0)
  220. {
  221. inp->flag = IOBUF_EOF;
  222. inp->length = 0;
  223. break;
  224. }
  225. mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM,
  226. MU_IOCTL_LOGSTREAM_ADVANCE_LOCUS_LINE, NULL);
  227. inp->length = mu_rtrim_class (inp->buffer, MU_CTYPE_ENDLN);
  228. if (inp->buffer[0] == '#' && !is_dbm_directive (inp))
  229. {
  230. struct mu_locus loc;
  231. mu_stream_ioctl (mu_strerr,
  232. MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_GET_LOCUS,
  233. &loc);
  234. loc.mu_line = strtoul (inp->buffer + 1, NULL, 10);
  235. mu_stream_ioctl (mu_strerr,
  236. MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_SET_LOCUS,
  237. &loc);
  238. free (loc.mu_file);
  239. continue;
  240. }
  241. break;
  242. }
  243. return 0;
  244. }
  245. static void
  246. input_ungetline (struct iobuf *inp)
  247. {
  248. if (inp->flag == 0)
  249. inp->flag = IOBUF_REREAD;
  250. }
  251. static size_t
  252. input_length (struct iobuf *inp)
  253. {
  254. return inp->length;
  255. }
  256. struct xfer_format
  257. {
  258. const char *name;
  259. void (*init) (struct xfer_format *fmt, const char *version,
  260. struct iobuf *iop, int wr);
  261. int (*reader) (struct iobuf *, void *data, struct mu_dbm_datum *key,
  262. struct mu_dbm_datum *content);
  263. int (*writer) (struct iobuf *, void *data, struct mu_dbm_datum const *key,
  264. struct mu_dbm_datum const *content);
  265. void *data;
  266. };
  267. static int ascii_reader (struct iobuf *, void *data,
  268. struct mu_dbm_datum *key,
  269. struct mu_dbm_datum *content);
  270. static int ascii_writer (struct iobuf *, void *data,
  271. struct mu_dbm_datum const *key,
  272. struct mu_dbm_datum const *content);
  273. static int C_reader (struct iobuf *, void *data,
  274. struct mu_dbm_datum *key,
  275. struct mu_dbm_datum *content);
  276. static int C_writer (struct iobuf *, void *data,
  277. struct mu_dbm_datum const *key,
  278. struct mu_dbm_datum const *content);
  279. static void newfmt_init (struct xfer_format *fmt,
  280. const char *version, struct iobuf *iop, int wr);
  281. static int newfmt_reader (struct iobuf *, void *data,
  282. struct mu_dbm_datum *key,
  283. struct mu_dbm_datum *content);
  284. static int newfmt_writer (struct iobuf *, void *data,
  285. struct mu_dbm_datum const *key,
  286. struct mu_dbm_datum const *content);
  287. static struct xfer_format format_tab[] = {
  288. { "C", NULL, C_reader, C_writer, NULL },
  289. { "0.0", NULL, ascii_reader, ascii_writer, NULL },
  290. { "1.0", newfmt_init, newfmt_reader, newfmt_writer, NULL },
  291. { NULL }
  292. };
  293. #define DEFAULT_LIST_FORMAT (&format_tab[1])
  294. #define DEFAULT_DUMP_FORMAT (&format_tab[2])
  295. #define DEFAULT_LOAD_FORMAT (&format_tab[1])
  296. static struct xfer_format *format;
  297. static const char *dump_format_version;
  298. static int
  299. read_data (struct iobuf *inp, struct mu_dbm_datum *key,
  300. struct mu_dbm_datum *content)
  301. {
  302. return format->reader (inp, format->data, key, content);
  303. }
  304. static int
  305. write_data (struct iobuf *iop, struct mu_dbm_datum const *key,
  306. struct mu_dbm_datum const *content)
  307. {
  308. return format->writer (iop, format->data, key, content);
  309. }
  310. static int
  311. select_format (const char *version)
  312. {
  313. struct xfer_format *fmt;
  314. dump_format_version = version;
  315. for (fmt = format_tab; fmt->name; fmt++)
  316. if (strcmp (fmt->name, version) == 0)
  317. {
  318. format = fmt;
  319. return 0;
  320. }
  321. mu_error (_("unsupported format version: %s"), version);
  322. return 1;
  323. }
  324. static void
  325. init_format (int wr, struct iobuf *iop)
  326. {
  327. if (format->init)
  328. format->init (format,
  329. dump_format_version ? dump_format_version : format->name,
  330. iop, wr);
  331. }
  332. static int
  333. ascii_writer (struct iobuf *iop, void *data,
  334. struct mu_dbm_datum const *key,
  335. struct mu_dbm_datum const *content)
  336. {
  337. size_t len;
  338. if (!data)
  339. {
  340. if (!suppress_header && include_zero == 1 &&
  341. !is_ignored_directive ("null"))
  342. mu_stream_printf (iop->stream, "#:null\n");
  343. data = ascii_writer;
  344. }
  345. len = key->mu_dsize;
  346. if (key->mu_dptr[len - 1] == 0)
  347. len--;
  348. mu_stream_write (iop->stream, key->mu_dptr, len, NULL);
  349. mu_stream_write (iop->stream, "\t", 1, NULL);
  350. len = content->mu_dsize;
  351. if (content->mu_dptr[len - 1] == 0)
  352. len--;
  353. mu_stream_write (iop->stream, content->mu_dptr, len, NULL);
  354. mu_stream_write (iop->stream, "\n", 1, NULL);
  355. return 0;
  356. }
  357. static int
  358. ascii_reader (struct iobuf *inp, void *data MU_ARG_UNUSED,
  359. struct mu_dbm_datum *key,
  360. struct mu_dbm_datum *content)
  361. {
  362. char *kstr, *val;
  363. int rc;
  364. rc = input_getline (inp);
  365. if (rc)
  366. {
  367. mu_error ("%s", mu_strerror (rc));
  368. return -1;
  369. }
  370. if (input_eof (inp))
  371. return 1;
  372. if (input_length (inp) == 0)
  373. {
  374. key->mu_dsize = 0;
  375. return 0;
  376. }
  377. kstr = mu_str_stripws (inp->buffer);
  378. val = mu_str_skip_class_comp (kstr, MU_CTYPE_SPACE);
  379. *val++ = 0;
  380. val = mu_str_skip_class (val, MU_CTYPE_SPACE);
  381. if (*val == 0)
  382. {
  383. mu_error (_("malformed line"));
  384. key->mu_dsize = 0;
  385. }
  386. else
  387. {
  388. init_datum (key, kstr);
  389. init_datum (content, val);
  390. }
  391. return 0;
  392. }
  393. void
  394. write_quoted_string (mu_stream_t stream, char *str, size_t len)
  395. {
  396. for (; len; str++, len--)
  397. {
  398. if (*str == '"')
  399. {
  400. mu_stream_write (stream, "\\", 1, NULL);
  401. mu_stream_write (stream, str, 1, NULL);
  402. }
  403. else if (*str != '\t' && *str != '\\' && mu_isprint (*str))
  404. mu_stream_write (stream, str, 1, NULL);
  405. else
  406. {
  407. int c = mu_wordsplit_c_quote_char (*str);
  408. mu_stream_write (stream, "\\", 1, NULL);
  409. if (c != -1)
  410. mu_stream_write (stream, str, 1, NULL);
  411. else
  412. mu_stream_printf (stream, "%03o", *(unsigned char *) str);
  413. }
  414. }
  415. }
  416. static int
  417. C_writer (struct iobuf *iop, void *data MU_ARG_UNUSED,
  418. struct mu_dbm_datum const *key,
  419. struct mu_dbm_datum const *content)
  420. {
  421. write_quoted_string (iop->stream, key->mu_dptr, key->mu_dsize);
  422. mu_stream_write (iop->stream, "\n", 1, NULL);
  423. write_quoted_string (iop->stream, content->mu_dptr, content->mu_dsize);
  424. mu_stream_write (iop->stream, "\n\n", 2, NULL);
  425. return 0;
  426. }
  427. #define ISODIGIT(c) ((c) >= '0' && c < '8')
  428. #define OCTVAL(c) ((c) - '0')
  429. static int
  430. C_read_datum (struct iobuf *inp, struct mu_dbm_datum *datum)
  431. {
  432. size_t i = 0;
  433. char *base, *ptr;
  434. size_t length;
  435. int rc;
  436. free (datum->mu_dptr);
  437. memset (datum, 0, sizeof (*datum));
  438. rc = input_getline (inp);
  439. if (rc)
  440. {
  441. mu_error ("%s", mu_strerror (rc));
  442. return -1;
  443. }
  444. if (input_eof (inp))
  445. return 1;
  446. if ((length = input_length (inp)) == 0)
  447. {
  448. mu_error (_("empty line"));
  449. return -1;
  450. }
  451. memset (datum, 0, sizeof (*datum));
  452. datum->mu_dptr = ptr = mu_alloc (length);
  453. base = inp->buffer;
  454. for (i = 0; i < length; ptr++)
  455. {
  456. if (base[i] == '\\')
  457. {
  458. if (++i >= length)
  459. {
  460. mu_error (_("unfinished string"));
  461. return -1;
  462. }
  463. else if (ISODIGIT (base[i]))
  464. {
  465. unsigned c;
  466. if (i + 3 > length)
  467. {
  468. mu_error (_("unfinished string"));
  469. return -1;
  470. }
  471. c = OCTVAL (base[i]);
  472. c <<= 3;
  473. c |= OCTVAL (base[i + 1]);
  474. c <<= 3;
  475. c |= OCTVAL (base[i + 2]);
  476. *ptr = c;
  477. i += 3;
  478. }
  479. else
  480. {
  481. int c = mu_wordsplit_c_unquote_char (base[i]);
  482. if (c == -1)
  483. {
  484. mu_error (_("invalid escape sequence (\\%c)"), base[i]);
  485. return -1;
  486. }
  487. *ptr = c;
  488. }
  489. }
  490. else
  491. *ptr = base[i++];
  492. }
  493. datum->mu_dsize = ptr - datum->mu_dptr;
  494. return 0;
  495. }
  496. static int
  497. C_reader (struct iobuf *inp, void *data MU_ARG_UNUSED,
  498. struct mu_dbm_datum *key,
  499. struct mu_dbm_datum *content)
  500. {
  501. int rc;
  502. rc = C_read_datum (inp, key);
  503. if (rc < 0)
  504. exit (EX_DATAERR);
  505. else if (rc == 1)
  506. return 1;
  507. if (C_read_datum (inp, content))
  508. exit (EX_DATAERR);
  509. rc = input_getline (inp);
  510. if (rc)
  511. {
  512. mu_error ("%s", mu_strerror (rc));
  513. return -1;
  514. }
  515. if (input_length (inp) != 0)
  516. {
  517. mu_error (_("unrecognized line"));
  518. return -1;
  519. }
  520. return 0;
  521. }
  522. static void
  523. newfmt_init (struct xfer_format *fmt, const char *version,
  524. struct iobuf *iop, int wr)
  525. {
  526. int rc;
  527. if (!wr)
  528. {
  529. mu_stream_t flt;
  530. rc = mu_linelen_filter_create (&flt, iop->stream, 76, MU_STREAM_WRITE);
  531. if (rc)
  532. {
  533. mu_diag_funcall (MU_DIAG_ERROR, "mu_linelen_filter_create",
  534. NULL, rc);
  535. exit (EX_SOFTWARE);
  536. }
  537. iop->stream = flt;
  538. }
  539. else
  540. {
  541. mu_opool_t pool;
  542. rc = mu_opool_create (&pool, 0);
  543. if (rc)
  544. {
  545. mu_diag_funcall (MU_DIAG_ERROR, "mu_opool_create",
  546. NULL, rc);
  547. exit (EX_SOFTWARE);
  548. }
  549. fmt->data = pool;
  550. }
  551. }
  552. static int
  553. newfmt_read_datum (struct iobuf *iop, mu_opool_t pool,
  554. struct mu_dbm_datum *datum)
  555. {
  556. int rc;
  557. unsigned char *ptr, *out;
  558. size_t len;
  559. free (datum->mu_dptr);
  560. memset (datum, 0, sizeof (*datum));
  561. rc = input_getline (iop);
  562. if (rc)
  563. {
  564. mu_error ("%s", mu_strerror (rc));
  565. exit (EX_IOERR);
  566. }
  567. if (input_eof (iop))
  568. return 1;
  569. if (!is_len_directive (iop))
  570. {
  571. mu_error (_("unrecognized input line"));
  572. exit (EX_DATAERR);
  573. }
  574. else
  575. {
  576. char *p;
  577. unsigned long n;
  578. errno = 0;
  579. n = strtoul (iop->buffer + 6, &p, 10);
  580. if (*p || errno)
  581. {
  582. mu_error (_("invalid length"));
  583. exit (EX_DATAERR);
  584. }
  585. datum->mu_dsize = n;
  586. }
  587. mu_opool_clear (pool);
  588. while (1)
  589. {
  590. rc = input_getline (iop);
  591. if (rc)
  592. {
  593. mu_error ("%s", mu_strerror (rc));
  594. exit (EX_IOERR);
  595. }
  596. if (input_eof (iop))
  597. break;
  598. if (is_len_directive (iop))
  599. {
  600. input_ungetline (iop);
  601. break;
  602. }
  603. mu_opool_append (pool, iop->buffer, iop->length);
  604. }
  605. ptr = mu_opool_finish (pool, &len);
  606. rc = mu_base64_decode (ptr, len, &out, &len);
  607. if (rc)
  608. {
  609. mu_diag_funcall (MU_DIAG_ERROR, "mu_base64_decode", NULL, rc);
  610. exit (EX_SOFTWARE);
  611. }
  612. datum->mu_dptr = (void*) out;
  613. return 0;
  614. }
  615. static int
  616. newfmt_reader (struct iobuf *input, void *data,
  617. struct mu_dbm_datum *key,
  618. struct mu_dbm_datum *content)
  619. {
  620. mu_opool_t pool = data;
  621. if (newfmt_read_datum (input, pool, key))
  622. return 1;
  623. if (newfmt_read_datum (input, pool, content))
  624. return 1;
  625. return 0;
  626. }
  627. static void
  628. newfmt_write_datum (struct iobuf *iop, struct mu_dbm_datum const *datum)
  629. {
  630. int rc;
  631. mu_stream_printf (iop->stream, "#:len=%lu\n",
  632. (unsigned long) datum->mu_dsize);
  633. rc = mu_base64_encode ((unsigned char*)datum->mu_dptr, datum->mu_dsize,
  634. (unsigned char **)&iop->buffer, &iop->bufsize);
  635. if (rc)
  636. {
  637. mu_diag_funcall (MU_DIAG_ERROR, "mu_base64_encode", NULL, rc);
  638. exit (EX_SOFTWARE);
  639. }
  640. mu_stream_write (iop->stream, iop->buffer, iop->bufsize, NULL);
  641. free (iop->buffer); /* FIXME */
  642. mu_stream_write (iop->stream, "\n", 1, NULL);
  643. }
  644. static int
  645. newfmt_writer (struct iobuf *iop, void *data,
  646. struct mu_dbm_datum const *key,
  647. struct mu_dbm_datum const *content)
  648. {
  649. newfmt_write_datum (iop, key);
  650. newfmt_write_datum (iop, content);
  651. return 0;
  652. }
  653. struct print_data
  654. {
  655. mu_dbm_file_t db;
  656. struct iobuf iob;
  657. };
  658. static int
  659. print_action (struct mu_dbm_datum const *key, void *data)
  660. {
  661. int rc;
  662. struct mu_dbm_datum contents;
  663. struct print_data *pd = data;
  664. if (!suppress_header)
  665. {
  666. int fd;
  667. struct stat st;
  668. const char *name, *p;
  669. rc = mu_dbm_get_fd (pd->db, &fd, NULL);
  670. if (rc)
  671. {
  672. mu_diag_funcall (MU_DIAG_ERROR, "mu_dbm_get_fd", db_name, rc);
  673. exit (EX_SOFTWARE);
  674. }
  675. if (fstat (fd, &st))
  676. {
  677. mu_diag_funcall (MU_DIAG_ERROR, "fstat", db_name, errno);
  678. exit (EX_UNAVAILABLE);
  679. }
  680. if (!(known_meta_data & META_UID))
  681. {
  682. known_meta_data |= META_UID;
  683. owner_uid = st.st_uid;
  684. }
  685. if (!(known_meta_data & META_GID))
  686. {
  687. known_meta_data |= META_GID;
  688. owner_gid = st.st_gid;
  689. }
  690. if (!(known_meta_data & META_FILE_MODE))
  691. {
  692. known_meta_data |= META_FILE_MODE;
  693. file_mode = st.st_mode & 0777;
  694. }
  695. if (!(known_meta_data & META_USER))
  696. {
  697. struct mu_auth_data *ap = mu_get_auth_by_uid (owner_uid);
  698. if (ap)
  699. {
  700. owner_user = mu_strdup (ap->name);
  701. known_meta_data |= META_USER;
  702. mu_auth_data_free (ap);
  703. }
  704. }
  705. if (!(known_meta_data & META_GROUP))
  706. {
  707. struct group *gr = getgrgid (owner_gid);
  708. if (gr)
  709. {
  710. owner_group = mu_strdup (gr->gr_name);
  711. known_meta_data |= META_GROUP;
  712. }
  713. }
  714. mu_dbm_get_name (pd->db, &name);
  715. p = strrchr (name, '/');
  716. if (p)
  717. p++;
  718. else
  719. p = name;
  720. print_header (p, mu_strout);
  721. }
  722. memset (&contents, 0, sizeof contents);
  723. rc = mu_dbm_fetch (pd->db, key, &contents);
  724. if (rc)
  725. {
  726. mu_error (_("database fetch error: %s"), mu_dbm_strerror (pd->db));
  727. exit (EX_UNAVAILABLE);
  728. }
  729. rc = write_data (&pd->iob, key, &contents);
  730. mu_dbm_datum_free (&contents);
  731. suppress_header = 1;
  732. return rc;
  733. }
  734. static void
  735. iterate_database (mu_dbm_file_t db,
  736. int (*matcher) (const char *, void *), void *matcher_data,
  737. int (*action) (struct mu_dbm_datum const *, void *),
  738. void *action_data)
  739. {
  740. int rc;
  741. struct mu_dbm_datum key;
  742. char *buf = NULL;
  743. size_t bufsize = 0;
  744. memset (&key, 0, sizeof key);
  745. for (rc = mu_dbm_firstkey (db, &key); rc == 0;
  746. rc = mu_dbm_nextkey (db, &key))
  747. {
  748. if (include_zero == -1)
  749. include_zero = key.mu_dptr[key.mu_dsize-1] == 0;
  750. if (matcher)
  751. {
  752. if (key.mu_dsize + 1 > bufsize)
  753. {
  754. bufsize = key.mu_dsize + 1;
  755. buf = mu_realloc (buf, bufsize);
  756. }
  757. memcpy (buf, key.mu_dptr, key.mu_dsize);
  758. buf[key.mu_dsize] = 0;
  759. if (!matcher (buf, matcher_data))
  760. continue;
  761. }
  762. if (action (&key, action_data))
  763. break;
  764. }
  765. free (buf);
  766. }
  767. static int
  768. match_literal (const char *str, void *data)
  769. {
  770. char **argv = data;
  771. for (; *argv; argv++)
  772. {
  773. if ((case_sensitive ? strcmp : strcasecmp) (str, *argv) == 0)
  774. return 1;
  775. }
  776. return 0;
  777. }
  778. #ifndef FNM_CASEFOLD
  779. # define FNM_CASEFOLD 0
  780. #endif
  781. static int
  782. match_glob (const char *str, void *data)
  783. {
  784. char **argv = data;
  785. for (; *argv; argv++)
  786. {
  787. if (fnmatch (*argv, str, case_sensitive ? FNM_CASEFOLD : 0) == 0)
  788. return 1;
  789. }
  790. return 0;
  791. }
  792. struct regmatch
  793. {
  794. int regc;
  795. regex_t *regs;
  796. };
  797. static int
  798. match_regex (const char *str, void *data)
  799. {
  800. struct regmatch *match = data;
  801. int i;
  802. for (i = 0; i < match->regc; i++)
  803. {
  804. if (regexec (&match->regs[i], str, 0, NULL, 0) == 0)
  805. return 1;
  806. }
  807. return 0;
  808. }
  809. static void
  810. compile_regexes (int argc, char **argv, struct regmatch *match)
  811. {
  812. regex_t *regs = mu_calloc (argc, sizeof (regs[0]));
  813. int i;
  814. int cflags = (case_sensitive ? 0: REG_ICASE) | REG_EXTENDED | REG_NOSUB;
  815. int errors = 0;
  816. for (i = 0; i < argc; i++)
  817. {
  818. int rc = regcomp (&regs[i], argv[i], cflags);
  819. if (rc)
  820. {
  821. char errbuf[512];
  822. regerror (rc, &regs[i], errbuf, sizeof (errbuf));
  823. mu_error (_("error compiling `%s': %s"), argv[i], errbuf);
  824. errors++;
  825. }
  826. }
  827. if (errors)
  828. exit (EX_USAGE);
  829. match->regc = argc;
  830. match->regs = regs;
  831. }
  832. static void
  833. free_regexes (struct regmatch *match)
  834. {
  835. int i;
  836. for (i = 0; i < match->regc; i++)
  837. regfree (&match->regs[i]);
  838. free (match->regs);
  839. }
  840. static void
  841. list_database (int argc, char **argv)
  842. {
  843. mu_dbm_file_t db = open_db_file (MU_STREAM_READ);
  844. struct print_data pdata;
  845. memset (&pdata, 0, sizeof pdata);
  846. pdata.db = db;
  847. pdata.iob.stream = mu_strout;
  848. init_format (0, &pdata.iob);
  849. if (argc == 0)
  850. iterate_database (db, NULL, NULL, print_action, &pdata);
  851. else
  852. {
  853. switch (key_type)
  854. {
  855. case key_literal:
  856. iterate_database (db, match_literal, argv, print_action, &pdata);
  857. break;
  858. case key_glob:
  859. iterate_database (db, match_glob, argv, print_action, &pdata);
  860. break;
  861. case key_regex:
  862. {
  863. struct regmatch m;
  864. compile_regexes (argc, argv, &m);
  865. iterate_database (db, match_regex, &m, print_action, &pdata);
  866. free_regexes (&m);
  867. }
  868. }
  869. }
  870. mu_dbm_destroy (&db);
  871. mu_stream_close (pdata.iob.stream);
  872. }
  873. static int
  874. is_dbm_directive (struct iobuf *input)
  875. {
  876. return input->length > 2 &&
  877. input->buffer[0] == '#' &&
  878. input->buffer[1] == ':';
  879. }
  880. static int
  881. is_len_directive (struct iobuf *input)
  882. {
  883. return input->length > 6 && memcmp (input->buffer, "#:len=", 6) == 0;
  884. }
  885. /*
  886. #:version=1.0 # Version number
  887. #:filename=S # Original database name (basename)
  888. #:uid=N,user=S,gid=N,group=S,mode=N # File meta info
  889. #:null[=0|1] # Null termination (v.0.0 only)
  890. #:len=N # record length (v.1.0)
  891. */
  892. static int
  893. _set_version (const char *val)
  894. {
  895. if (select_format (val))
  896. exit (EX_DATAERR);
  897. return 0;
  898. }
  899. static int
  900. _set_file (const char *val)
  901. {
  902. if (!db_name)
  903. db_name = mu_strdup (val);
  904. return 0;
  905. }
  906. static int
  907. _set_null (const char *val)
  908. {
  909. if (!val)
  910. include_zero = 1;
  911. else if (val[0] == '0' && val[1] == 0)
  912. include_zero = 0;
  913. else if (val[0] == '1' && val[1] == 0)
  914. include_zero = 1;
  915. else
  916. {
  917. mu_error (_("bad value for `null' directive: %s"), val);
  918. exit (EX_DATAERR);
  919. }
  920. return 0;
  921. }
  922. static int
  923. _set_uid (const char *val)
  924. {
  925. char *p;
  926. unsigned long n;
  927. if (known_meta_data & META_UID)
  928. return 0;
  929. errno = 0;
  930. n = strtoul (val, &p, 8);
  931. if (*p || errno)
  932. {
  933. mu_error (_("invalid UID"));
  934. exit (EX_NOUSER);
  935. }
  936. owner_uid = n;
  937. known_meta_data |= META_UID;
  938. return 0;
  939. }
  940. static int
  941. _set_gid (const char *val)
  942. {
  943. char *p;
  944. unsigned long n;
  945. if (known_meta_data & META_GID)
  946. return 0;
  947. errno = 0;
  948. n = strtoul (val, &p, 8);
  949. if (*p || errno)
  950. {
  951. mu_error (_("invalid GID"));
  952. exit (EX_DATAERR);
  953. }
  954. owner_gid = n;
  955. known_meta_data |= META_GID;
  956. return 0;
  957. }
  958. static int
  959. _set_user (const char *val)
  960. {
  961. if (known_meta_data & META_USER)
  962. return 0;
  963. free (owner_user);
  964. owner_user = mu_strdup (val);
  965. known_meta_data |= META_USER;
  966. return 0;
  967. }
  968. static int
  969. _set_group (const char *val)
  970. {
  971. if (known_meta_data & META_GROUP)
  972. return 0;
  973. free (owner_group);
  974. owner_group = mu_strdup (val);
  975. known_meta_data |= META_GROUP;
  976. return 0;
  977. }
  978. static int
  979. _set_mode (const char *val)
  980. {
  981. char *p;
  982. unsigned long n;
  983. if (known_meta_data & META_FILE_MODE)
  984. return 0;
  985. errno = 0;
  986. n = strtoul (val, &p, 8);
  987. if (*p || errno || n > 0777)
  988. {
  989. mu_error (_("invalid file mode"));
  990. exit (EX_DATAERR);
  991. }
  992. file_mode = n;
  993. known_meta_data |= META_FILE_MODE;
  994. return 0;
  995. }
  996. struct dbm_directive
  997. {
  998. const char *name;
  999. size_t len;
  1000. int (*set) (const char *val);
  1001. int flags;
  1002. };
  1003. #define DF_VALUE 0x01 /* directive requires a value */
  1004. #define DF_HEADER 0x02 /* can appear only in file header */
  1005. #define DF_PROTECT 0x04 /* directive cannot be ignored */
  1006. #define DF_META 0x08 /* directive keeps file meta-information */
  1007. #define DF_SEEN 0x10 /* directive was already seen */
  1008. #define DF_IGNORE 0x20 /* ignore this directive */
  1009. static struct dbm_directive dbm_directive_table[] = {
  1010. #define S(s) #s, sizeof #s - 1
  1011. { S(version), _set_version, DF_HEADER|DF_VALUE|DF_PROTECT },
  1012. { S(file), _set_file, DF_HEADER|DF_VALUE },
  1013. { S(uid), _set_uid, DF_HEADER|DF_META|DF_VALUE },
  1014. { S(user), _set_user, DF_HEADER|DF_META|DF_VALUE },
  1015. { S(gid), _set_gid, DF_HEADER|DF_META|DF_VALUE },
  1016. { S(group), _set_group, DF_HEADER|DF_META|DF_VALUE },
  1017. { S(mode), _set_mode, DF_HEADER|DF_META|DF_VALUE },
  1018. { S(null), _set_null, DF_HEADER|DF_VALUE },
  1019. { S(null), _set_null, DF_HEADER },
  1020. #undef S
  1021. { NULL }
  1022. };
  1023. static void
  1024. ignore_directives (const char *arg)
  1025. {
  1026. struct mu_wordsplit ws;
  1027. size_t i;
  1028. ws.ws_delim = ",";
  1029. if (mu_wordsplit (arg, &ws,
  1030. MU_WRDSF_NOVAR | MU_WRDSF_NOCMD | MU_WRDSF_DELIM))
  1031. {
  1032. mu_error (_("cannot split input line: %s"), mu_wordsplit_strerror (&ws));
  1033. exit (EX_SOFTWARE);
  1034. }
  1035. for (i = 0; i < ws.ws_wordc; i++)
  1036. {
  1037. char *arg = ws.ws_wordv[i];
  1038. size_t len = strlen (arg);
  1039. struct dbm_directive *p;
  1040. int found = 0;
  1041. for (p = dbm_directive_table; p->name; p++)
  1042. {
  1043. if (p->len == len && memcmp (p->name, arg, len) == 0)
  1044. {
  1045. if (p->flags & DF_PROTECT)
  1046. mu_error (_("directive %s cannot be ignored"), p->name);
  1047. else
  1048. p->flags |= DF_IGNORE;
  1049. found = 1;
  1050. }
  1051. }
  1052. if (!found)
  1053. mu_error (_("unknown directive: %s"), arg);
  1054. }
  1055. mu_wordsplit_free (&ws);
  1056. }
  1057. static int
  1058. is_ignored_directive (const char *arg)
  1059. {
  1060. size_t len = strlen (arg);
  1061. struct dbm_directive *p;
  1062. for (p = dbm_directive_table; p->name; p++)
  1063. {
  1064. if (p->len == len && memcmp (p->name, arg, len) == 0)
  1065. return p->flags & DF_IGNORE;
  1066. }
  1067. return 0;
  1068. }
  1069. static void
  1070. ignore_flagged_directives (int flag)
  1071. {
  1072. struct dbm_directive *p;
  1073. for (p = dbm_directive_table; p->name; p++)
  1074. if (!(p->flags & DF_PROTECT) && (p->flags & flag))
  1075. p->flags |= DF_IGNORE;
  1076. }
  1077. static int
  1078. set_directive (char *val)
  1079. {
  1080. size_t len;
  1081. struct dbm_directive *p, *match = NULL;
  1082. mu_ltrim_class (val, MU_CTYPE_BLANK);
  1083. mu_rtrim_class (val, MU_CTYPE_BLANK);
  1084. len = strcspn (val, "=");
  1085. for (p = dbm_directive_table; p->name; p++)
  1086. {
  1087. if (p->len == len && memcmp (p->name, val, len) == 0)
  1088. {
  1089. int rc;
  1090. match = p;
  1091. if (val[len] == '=')
  1092. {
  1093. if (!(p->flags & DF_VALUE))
  1094. continue;
  1095. }
  1096. else if (p->flags & DF_VALUE)
  1097. continue;
  1098. if (p->flags & DF_IGNORE)
  1099. return 0;
  1100. if (p->flags & DF_SEEN)
  1101. {
  1102. mu_error (_("directive %s appeared twice"), val);
  1103. return 1;
  1104. }
  1105. rc = p->set ((p->flags & DF_VALUE) ? val + len + 1 : NULL);
  1106. if (p->flags & DF_HEADER)
  1107. p->flags |= DF_SEEN;
  1108. return rc;
  1109. }
  1110. }
  1111. if (match)
  1112. {
  1113. if (match->flags & DF_VALUE)
  1114. mu_error (_("directive requires argument: %s"), val);
  1115. else
  1116. mu_error (_("directive does not take argument: %s"), val);
  1117. }
  1118. else
  1119. mu_error (_("unknown or unsupported directive %s"), val);
  1120. return 1;
  1121. }
  1122. static void
  1123. print_header (const char *name, mu_stream_t str)
  1124. {
  1125. char *delim;
  1126. time_t t;
  1127. time (&t);
  1128. mu_stream_printf (str, "# ");
  1129. mu_stream_printf (str, _("Database dump file created by %s on %s"),
  1130. PACKAGE_STRING,
  1131. ctime (&t));
  1132. mu_stream_printf (str, "#:version=%s\n", format->name);
  1133. if (!is_ignored_directive ("file"))
  1134. mu_stream_printf (str, "#:file=%s\n", name);
  1135. delim = "#:";
  1136. if ((known_meta_data & META_UID) && !is_ignored_directive ("uid"))
  1137. {
  1138. mu_stream_printf (str, "%suid=%lu", delim, (unsigned long) owner_uid);
  1139. delim = ",";
  1140. }
  1141. if ((known_meta_data & META_USER) && !is_ignored_directive ("user"))
  1142. {
  1143. mu_stream_printf (str, "%suser=%s", delim, owner_user);
  1144. delim = ",";
  1145. }
  1146. if ((known_meta_data & META_GID) && !is_ignored_directive ("gid"))
  1147. {
  1148. mu_stream_printf (str, "%sgid=%lu", delim, (unsigned long) owner_gid);
  1149. delim = ",";
  1150. }
  1151. if ((known_meta_data & META_GROUP) && !is_ignored_directive ("group"))
  1152. {
  1153. mu_stream_printf (str, "%sgroup=%s", delim, owner_group);
  1154. delim = ",";
  1155. }
  1156. if ((known_meta_data & META_FILE_MODE) && !is_ignored_directive ("mode"))
  1157. mu_stream_printf (str, "%smode=%03o", delim, file_mode);
  1158. if (delim[0] == ',')
  1159. mu_stream_printf (str, "\n");
  1160. }
  1161. static void
  1162. add_records (int mode, int replace)
  1163. {
  1164. mu_dbm_file_t db;
  1165. mu_stream_t instream, flt;
  1166. const char *flt_argv[] = { "inline-comment", "#", "-S", "-i", "#", NULL };
  1167. int rc;
  1168. int save_log_mode = 0, log_mode;
  1169. struct mu_locus save_locus = { NULL, }, locus;
  1170. struct mu_dbm_datum key, contents;
  1171. struct iobuf input;
  1172. struct mu_wordsplit ws;
  1173. int wsflags = MU_WRDSF_NOVAR | MU_WRDSF_NOCMD | MU_WRDSF_DELIM;
  1174. if (mode != MU_STREAM_CREAT)
  1175. {
  1176. ignore_flagged_directives (DF_META);
  1177. known_meta_data = 0;
  1178. }
  1179. /* Prepare input data */
  1180. if (input_file)
  1181. {
  1182. rc = mu_file_stream_create (&instream, input_file, MU_STREAM_READ);
  1183. if (rc)
  1184. {
  1185. mu_error (_("cannot open input file %s: %s"), input_file,
  1186. mu_strerror (rc));
  1187. exit (EX_NOINPUT);
  1188. }
  1189. }
  1190. else
  1191. {
  1192. instream = mu_strin;
  1193. mu_stream_ref (instream);
  1194. }
  1195. rc = mu_filter_create_args (&flt, instream, "inline-comment",
  1196. MU_ARRAY_SIZE (flt_argv) - 1, flt_argv,
  1197. MU_FILTER_DECODE, MU_STREAM_READ);
  1198. if (rc)
  1199. {
  1200. mu_diag_funcall (MU_DIAG_ERROR, "mu_filter_create_args", input_file, rc);
  1201. exit (EX_UNAVAILABLE);
  1202. }
  1203. mu_stream_unref (instream);
  1204. instream = flt;
  1205. /* Configure error stream to output input file location before each error
  1206. message */
  1207. locus.mu_file = input_file ? input_file : "<stdin>";
  1208. locus.mu_line = 0;
  1209. locus.mu_col = 0;
  1210. mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_GET_MODE,
  1211. &save_log_mode);
  1212. mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_GET_LOCUS,
  1213. &save_locus);
  1214. log_mode = save_log_mode | MU_LOGMODE_LOCUS;
  1215. mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_SET_MODE,
  1216. &log_mode);
  1217. mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_SET_LOCUS,
  1218. &locus);
  1219. /* Initialize I/O data */
  1220. memset (&key, 0, sizeof key);
  1221. memset (&contents, 0, sizeof contents);
  1222. /* Initialize input buffer */
  1223. input.buffer = NULL;
  1224. input.bufsize = 0;
  1225. input.length = 0;
  1226. input.flag = 0;
  1227. input.stream = instream;
  1228. /* Read directive header */
  1229. ws.ws_delim = ",";
  1230. while ((rc = input_getline (&input)) == 0 &&
  1231. is_dbm_directive (&input) &&
  1232. !is_len_directive (&input))
  1233. {
  1234. size_t i;
  1235. if (mu_wordsplit (input.buffer + 2, &ws, wsflags))
  1236. {
  1237. mu_error (_("cannot split input line: %s"),
  1238. mu_wordsplit_strerror (&ws));
  1239. exit (EX_SOFTWARE);
  1240. }
  1241. for (i = 0; i < ws.ws_wordc; i++)
  1242. {
  1243. set_directive (ws.ws_wordv[i]);
  1244. }
  1245. wsflags |= MU_WRDSF_REUSE;
  1246. }
  1247. if (wsflags & MU_WRDSF_REUSE)
  1248. mu_wordsplit_free (&ws);
  1249. if (!format)
  1250. format = DEFAULT_LOAD_FORMAT;
  1251. init_format (1, &input);
  1252. /* Open the database */
  1253. db = open_db_file (mode);
  1254. /* Read and store the actual data */
  1255. if (rc == 0 && input_length (&input) > 0)
  1256. {
  1257. ignore_flagged_directives (DF_HEADER);
  1258. input_ungetline (&input);
  1259. memset (&key, 0, sizeof key);
  1260. memset (&contents, 0, sizeof contents);
  1261. while ((rc = read_data (&input, &key, &contents)) == 0)
  1262. {
  1263. if (key.mu_dsize)
  1264. {
  1265. rc = mu_dbm_store (db, &key, &contents, replace);
  1266. if (rc)
  1267. mu_error (_("cannot store datum: %s"),
  1268. rc == MU_ERR_FAILURE ?
  1269. mu_dbm_strerror (db) : mu_strerror (rc));
  1270. }
  1271. }
  1272. }
  1273. mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_SET_MODE,
  1274. &save_log_mode);
  1275. mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_SET_LOCUS,
  1276. &save_locus);
  1277. if (known_meta_data)
  1278. set_db_ownership (db);
  1279. mu_dbm_destroy (&db);
  1280. mu_stream_unref (instream);
  1281. }
  1282. static void
  1283. create_database ()
  1284. {
  1285. if (getuid() != 0)
  1286. ignore_flagged_directives (DF_META);
  1287. if (copy_permissions)
  1288. {
  1289. struct stat st;
  1290. if (!input_file)
  1291. {
  1292. mu_error (_("--copy-permissions used without --file"));
  1293. exit (EX_USAGE);
  1294. }
  1295. if (stat (input_file, &st))
  1296. {
  1297. mu_diag_funcall (MU_DIAG_ERROR, "stat", input_file, errno);
  1298. exit (EX_UNAVAILABLE);
  1299. }
  1300. owner_uid = st.st_uid;
  1301. owner_gid = st.st_gid;
  1302. file_mode = st.st_mode & 0777;
  1303. known_meta_data |= META_UID | META_GID | META_FILE_MODE;
  1304. }
  1305. else if (auth)
  1306. {
  1307. if (!(known_meta_data & META_UID))
  1308. {
  1309. owner_uid = auth->uid;
  1310. known_meta_data |= META_UID;
  1311. }
  1312. if (!(known_meta_data & META_GID))
  1313. {
  1314. owner_gid = auth->gid;
  1315. known_meta_data |= META_GID;
  1316. }
  1317. }
  1318. add_records (MU_STREAM_CREAT, 0);
  1319. }
  1320. static int
  1321. store_to_list (struct mu_dbm_datum const *key, void *data)
  1322. {
  1323. int rc;
  1324. mu_list_t list = data;
  1325. char *p = mu_alloc (key->mu_dsize + 1);
  1326. memcpy (p, key->mu_dptr, key->mu_dsize);
  1327. p[key->mu_dsize] = 0;
  1328. rc = mu_list_append (list, p);
  1329. if (rc)
  1330. {
  1331. mu_diag_funcall (MU_DIAG_ERROR, "mu_list_append", p, rc);
  1332. exit (EX_SOFTWARE);
  1333. }
  1334. return 0;
  1335. }
  1336. static int
  1337. do_delete (void *item, void *data)
  1338. {
  1339. char *str = item;
  1340. mu_dbm_file_t db = data;
  1341. struct mu_dbm_datum key;
  1342. int rc;
  1343. init_datum (&key, str);
  1344. rc = mu_dbm_delete (db, &key);
  1345. if (rc == MU_ERR_NOENT)
  1346. {
  1347. mu_error (_("cannot remove record for %s: %s"),
  1348. str, mu_strerror (rc));
  1349. }
  1350. else if (rc)
  1351. {
  1352. mu_error (_("cannot remove record for %s: %s"),
  1353. str, mu_dbm_strerror (db));
  1354. if (rc != MU_ERR_NOENT)
  1355. exit (EX_UNAVAILABLE);
  1356. }
  1357. return 0;
  1358. }
  1359. static void
  1360. delete_database (int argc, char **argv)
  1361. {
  1362. mu_dbm_file_t db = open_db_file (MU_STREAM_RDWR);
  1363. mu_list_t templist = NULL;
  1364. int rc, i;
  1365. if (argc == 0)
  1366. {
  1367. mu_error (_("not enough arguments for delete"));
  1368. exit (EX_USAGE);
  1369. }
  1370. /* Collect matching keys */
  1371. rc = mu_list_create (&templist);
  1372. if (rc)
  1373. {
  1374. mu_diag_funcall (MU_DIAG_ERROR, "mu_list_create", NULL, rc);
  1375. exit (EX_SOFTWARE);
  1376. }
  1377. mu_list_set_destroy_item (templist, mu_list_free_item);
  1378. switch (key_type)
  1379. {
  1380. case key_literal:
  1381. for (i = 0; i < argc; i++)
  1382. {
  1383. char *p = mu_strdup (argv[i]);
  1384. rc = mu_list_append (templist, p);
  1385. if (rc)
  1386. {
  1387. mu_diag_funcall (MU_DIAG_ERROR, "mu_list_append", p, rc);
  1388. exit (EX_SOFTWARE);
  1389. }
  1390. }
  1391. break;
  1392. case key_glob:
  1393. iterate_database (db, match_glob, argv,
  1394. store_to_list, templist);
  1395. break;
  1396. case key_regex:
  1397. {
  1398. struct regmatch m;
  1399. compile_regexes (argc, argv, &m);
  1400. iterate_database (db, match_regex, &m, store_to_list, templist);
  1401. free_regexes (&m);
  1402. }
  1403. }
  1404. mu_list_foreach (templist, do_delete, db);
  1405. mu_list_destroy (&templist);
  1406. mu_dbm_destroy (&db);
  1407. }
  1408. /*
  1409. mu dbm --create a.db < input
  1410. mu dbm --list a.db
  1411. mu dbm --delete a.db key [key...]
  1412. mu dbm --add a.db < input
  1413. mu dbm --replace a.db < input
  1414. */
  1415. static struct argp_option dbm_options[] = {
  1416. { NULL, 0, NULL, 0, N_("Create Options"), 0},
  1417. { "file", 'f', N_("FILE"), 0,
  1418. N_("read input from FILE (with create, delete, add and replace)") },
  1419. { "permissions", 'p', N_("NUM"), 0,
  1420. N_("set permissions on the created database") },
  1421. { "user", 'u', N_("USER"), 0,
  1422. N_("set database owner name") },
  1423. { "group", 'g', N_("GROUP"), 0,
  1424. N_("set database owner group") },
  1425. { "copy-permissions", 'P', NULL, 0,
  1426. N_("copy database permissions and ownership from the input file") },
  1427. { "ignore-meta", 'm', NULL, 0,
  1428. N_("ignore meta-information from input file headers") },
  1429. { "ignore-directives", 'I', N_("NAMES"), 0,
  1430. N_("ignore the listed directives") },
  1431. { NULL, 0, NULL, 0, N_("List and Dump Options"), 0},
  1432. { "format", 'H', N_("TYPE"), 0,
  1433. N_("select output format") },
  1434. { "no-header", 'q', NULL, 0,
  1435. N_("suppress format header") },
  1436. { NULL, 0, NULL, 0, N_("List, Dump and Delete Options"), 0},
  1437. { "glob", 'G', NULL, 0,
  1438. N_("treat keys as globbing patterns") },
  1439. { "regex", 'R', NULL, 0,
  1440. N_("treat keys as regular expressions") },
  1441. { "ignore-case", 'i', NULL, 0,
  1442. N_("case-insensitive matches") },
  1443. { NULL, 0, NULL, 0, N_("Options for Use with Format 0.0"), 0 },
  1444. { "count-null", 'N', NULL, 0,
  1445. N_("data length accounts for terminating zero") },
  1446. { "no-count-null", 'n', NULL, 0,
  1447. N_("data length does not account for terminating zero") },
  1448. { NULL }
  1449. };
  1450. static error_t
  1451. dbm_parse_opt (int key, char *arg, struct argp_state *state)
  1452. {
  1453. switch (key)
  1454. {
  1455. case 'f':
  1456. input_file = arg;
  1457. break;
  1458. case 'H':
  1459. select_format (arg);
  1460. break;
  1461. case 'p':
  1462. {
  1463. char *p;
  1464. unsigned long d = strtoul (arg, &p, 8);
  1465. if (*p || (d & ~0777))
  1466. argp_error (state, _("invalid file mode: %s"), arg);
  1467. file_mode = d;
  1468. known_meta_data |= META_FILE_MODE;
  1469. }
  1470. break;
  1471. case 'P':
  1472. copy_permissions = 1;
  1473. break;
  1474. case 'q':
  1475. suppress_header = 1;
  1476. break;
  1477. case 'u':
  1478. auth = mu_get_auth_by_name (arg);
  1479. if (auth)
  1480. known_meta_data |= META_AUTH;
  1481. else
  1482. {
  1483. char *p;
  1484. unsigned long n = strtoul (arg, &p, 0);
  1485. if (*p == 0)
  1486. {
  1487. owner_uid = n;
  1488. known_meta_data |= META_UID;
  1489. }
  1490. else
  1491. argp_error (state, _("no such user: %s"), arg);
  1492. }
  1493. ignore_directives ("user,uid");
  1494. break;
  1495. case 'g':
  1496. {
  1497. struct group *gr = getgrnam (arg);
  1498. if (!gr)
  1499. {
  1500. char *p;
  1501. unsigned long n = strtoul (arg, &p, 0);
  1502. if (*p == 0)
  1503. owner_gid = n;
  1504. else
  1505. argp_error (state, _("no such group: %s"), arg);
  1506. }
  1507. else
  1508. owner_gid = gr->gr_gid;
  1509. known_meta_data |= META_GID;
  1510. ignore_directives ("group,gid");
  1511. }
  1512. break;
  1513. case 'G':
  1514. key_type = key_glob;
  1515. break;
  1516. case 'R':
  1517. key_type = key_regex;
  1518. break;
  1519. case 'm':/* FIXME: Why m? */
  1520. ignore_flagged_directives (DF_META);
  1521. break;
  1522. case 'I':
  1523. ignore_directives (arg);
  1524. break;
  1525. case 'i':
  1526. case_sensitive = 0;
  1527. break;
  1528. case 'N':
  1529. include_zero = 1;
  1530. break;
  1531. case 'n':
  1532. include_zero = 0;
  1533. break;
  1534. default:
  1535. return ARGP_ERR_UNKNOWN;
  1536. }
  1537. return 0;
  1538. }
  1539. static struct argp dbm_argp = {
  1540. dbm_options,
  1541. dbm_parse_opt,
  1542. dbm_args_doc,
  1543. dbm_doc,
  1544. NULL,
  1545. NULL,
  1546. NULL
  1547. };
  1548. struct mu_kwd mode_tab[] =
  1549. {
  1550. { "add", mode_add },
  1551. { "create", mode_create },
  1552. { "load", mode_create },
  1553. { "list", mode_list },
  1554. { "replace", mode_replace },
  1555. { "delete", mode_delete },
  1556. { "dump", mode_dump },
  1557. { NULL }
  1558. };
  1559. int
  1560. mutool_dbm (int argc, char **argv)
  1561. {
  1562. int index;
  1563. if (argp_parse (&dbm_argp, argc, argv, 0, &index, NULL))
  1564. return 1;
  1565. argc -= index;
  1566. argv += index;
  1567. if (argc == 0)
  1568. {
  1569. mu_error (_("subcommand not given"));
  1570. exit (EX_USAGE);
  1571. }
  1572. if (mu_kwd_xlat_name (mode_tab, argv[0], &index))
  1573. {
  1574. mu_error (_("unknown subcommand: %s"), argv[0]);
  1575. exit (EX_USAGE);
  1576. }
  1577. mode = index;
  1578. argc--;
  1579. argv++;
  1580. if (argc == 0)
  1581. {
  1582. if (mode != mode_create)
  1583. {
  1584. mu_error (_("database name not given"));
  1585. exit (EX_USAGE);
  1586. }
  1587. }
  1588. else
  1589. {
  1590. db_name = *argv++;
  1591. --argc;
  1592. }
  1593. switch (mode)
  1594. {
  1595. case mode_list:
  1596. if (!format)
  1597. format = DEFAULT_LIST_FORMAT;
  1598. if (suppress_header == -1)
  1599. suppress_header = 1;
  1600. list_database (argc, argv);
  1601. break;
  1602. case mode_dump:
  1603. if (!format)
  1604. format = DEFAULT_DUMP_FORMAT;
  1605. if (suppress_header == -1)
  1606. suppress_header = 0;
  1607. list_database (argc, argv);
  1608. break;
  1609. case mode_create:
  1610. if (argc)
  1611. {
  1612. mu_error (_("too many arguments for create"));
  1613. exit (EX_USAGE);
  1614. }
  1615. create_database ();
  1616. break;
  1617. case mode_delete:
  1618. delete_database (argc, argv);
  1619. break;
  1620. case mode_add:
  1621. if (argc)
  1622. {
  1623. mu_error (_("too many arguments for add"));
  1624. exit (EX_USAGE);
  1625. }
  1626. add_records (MU_STREAM_RDWR, 0);
  1627. break;
  1628. case mode_replace:
  1629. if (argc)
  1630. {
  1631. mu_error (_("too many arguments for replace"));
  1632. exit (EX_USAGE);
  1633. }
  1634. add_records (MU_STREAM_RDWR, 1);
  1635. break;
  1636. }
  1637. return 0;
  1638. }
  1639. /*
  1640. MU Setup: dbm
  1641. mu-handler: mutool_dbm
  1642. mu-docstring: dbm_docstring
  1643. mu-cond: ENABLE_DBM
  1644. End MU Setup:
  1645. */