Commit 5454ed79 5454ed7909380a8fa934b1e1a89d59e62174ab64 by Sergey Poznyakoff

Introduce a better dbm dump format.

* include/mailutils/dbm.h (mu_dbm_get_name): New prototype.
* libmu_dbm/name.c: New file.
* libmu_dbm/Makefile.am (libmu_dbm_la_SOURCES): Add name.c
* mu/dbm.c: New dump format.
1 parent d96764ba
...@@ -73,6 +73,7 @@ int mu_dbm_safety_set_flags (mu_dbm_file_t db, int flags); ...@@ -73,6 +73,7 @@ int mu_dbm_safety_set_flags (mu_dbm_file_t db, int flags);
73 int mu_dbm_safety_check (mu_dbm_file_t db); 73 int mu_dbm_safety_check (mu_dbm_file_t db);
74 char const *mu_dbm_strerror (mu_dbm_file_t db); 74 char const *mu_dbm_strerror (mu_dbm_file_t db);
75 int mu_dbm_get_fd (mu_dbm_file_t db, int *pag, int *dir); 75 int mu_dbm_get_fd (mu_dbm_file_t db, int *pag, int *dir);
76 int mu_dbm_get_name (mu_dbm_file_t db, const char **pname);
76 77
77 int mu_dbm_impl_iterator (mu_iterator_t *itr); 78 int mu_dbm_impl_iterator (mu_iterator_t *itr);
78 79
......
...@@ -29,6 +29,7 @@ libmu_dbm_la_SOURCES = \ ...@@ -29,6 +29,7 @@ libmu_dbm_la_SOURCES = \
29 fetch.c\ 29 fetch.c\
30 firstkey.c\ 30 firstkey.c\
31 getfd.c\ 31 getfd.c\
32 name.c\
32 nextkey.c\ 33 nextkey.c\
33 open.c\ 34 open.c\
34 safety.c\ 35 safety.c\
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2011 2 Copyright (C) 2011 Free Software Foundation, Inc.
3 Free Software Foundation, Inc.
4 3
5 This library is free software; you can redistribute it and/or 4 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public 5 modify it under the terms of the GNU Lesser General Public
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2011 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General
15 Public License along with this library. If not, see
16 <http://www.gnu.org/licenses/>. */
17
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21 #include <unistd.h>
22 #include <stdlib.h>
23 #include <mailutils/types.h>
24 #include <mailutils/list.h>
25 #include <mailutils/url.h>
26 #include <mailutils/dbm.h>
27 #include <mailutils/errno.h>
28 #include <mailutils/util.h>
29 #include "mudbm.h"
30
31 int
32 mu_dbm_get_name (mu_dbm_file_t db, const char **pname)
33 {
34 if (!db)
35 return EINVAL;
36 if (!pname)
37 return MU_ERR_OUT_PTR_NULL;
38 *pname = db->db_name;
39 return 0;
40 }
...@@ -51,19 +51,34 @@ enum key_type ...@@ -51,19 +51,34 @@ enum key_type
51 key_regex 51 key_regex
52 }; 52 };
53 53
54 enum mode mode; 54 static enum mode mode;
55 char *db_name; 55 static char *db_name;
56 char *input_file; 56 static char *input_file;
57 int permissions = 0600; 57 static int file_mode = 0600;
58 struct mu_auth_data *auth; 58 static struct mu_auth_data *auth;
59 uid_t owner_uid = -1; 59 static uid_t owner_uid;
60 gid_t owner_gid = -1; 60 static gid_t owner_gid;
61 int copy_permissions; 61 static char *owner_user;
62 enum key_type key_type = key_literal; 62 static char *owner_group;
63 int case_sensitive = 1; 63 static int copy_permissions;
64 int include_zero = -1; 64
65 #define META_FILE_MODE 0x0001
66 #define META_UID 0x0002
67 #define META_GID 0x0004
68 #define META_USER 0x0008
69 #define META_GROUP 0x0010
70 #define META_AUTH 0x0020
71
72 static int known_meta_data;
73
74 static enum key_type key_type = key_literal;
75 static int case_sensitive = 1;
76 static int include_zero = -1;
77
78 static int suppress_header;
79
65 80
66 void 81 static void
67 init_datum (struct mu_dbm_datum *key, char *str) 82 init_datum (struct mu_dbm_datum *key, char *str)
68 { 83 {
69 memset (key, 0, sizeof *key); 84 memset (key, 0, sizeof *key);
...@@ -71,11 +86,17 @@ init_datum (struct mu_dbm_datum *key, char *str) ...@@ -71,11 +86,17 @@ init_datum (struct mu_dbm_datum *key, char *str)
71 key->mu_dsize = strlen (str) + !!include_zero; 86 key->mu_dsize = strlen (str) + !!include_zero;
72 } 87 }
73 88
74 mu_dbm_file_t 89 static mu_dbm_file_t
75 open_db_file (int mode) 90 open_db_file (int mode)
76 { 91 {
77 int rc; 92 int rc;
78 mu_dbm_file_t db; 93 mu_dbm_file_t db;
94
95 if (!db_name)
96 {
97 mu_error (_("database name not given"));
98 exit (EX_USAGE);
99 }
79 100
80 rc = mu_dbm_create (db_name, &db); 101 rc = mu_dbm_create (db_name, &db);
81 if (rc) 102 if (rc)
...@@ -85,56 +106,477 @@ open_db_file (int mode) ...@@ -85,56 +106,477 @@ open_db_file (int mode)
85 exit (EX_SOFTWARE); 106 exit (EX_SOFTWARE);
86 } 107 }
87 108
88 rc = mu_dbm_open (db, mode, permissions); 109 rc = mu_dbm_open (db, mode, file_mode);
89 if (rc) 110 if (rc)
90 { 111 {
91 mu_diag_funcall (MU_DIAG_ERROR, "mu_dbm_open", db_name, rc); 112 mu_diag_funcall (MU_DIAG_ERROR, "mu_dbm_open", db_name, rc);
92 exit (EX_SOFTWARE); 113 exit (EX_SOFTWARE);
93 } 114 }
94 115
95 if (mode == MU_STREAM_CREAT && (owner_uid != -1 || owner_gid != -1)) 116 return db;
117 }
118
119 static void
120 set_db_ownership (mu_dbm_file_t db)
121 {
122 int rc, dirfd, pagfd;
123 struct stat st;
124
125 rc = mu_dbm_get_fd (db, &pagfd, &dirfd);
126 if (rc)
127 {
128 mu_diag_funcall (MU_DIAG_ERROR, "mu_dbm_get_fd", db_name, rc);
129 exit (EX_SOFTWARE);
130 }
131
132 if (known_meta_data & META_USER)
96 { 133 {
97 int dirfd, pagfd; 134 struct mu_auth_data *ap;
98 135
99 rc = mu_dbm_get_fd (db, &pagfd, &dirfd); 136 ap = mu_get_auth_by_name (owner_user);
100 if (rc) 137 if (!ap)
101 { 138 {
102 mu_diag_funcall (MU_DIAG_ERROR, "mu_dbm_get_fd", db_name, rc); 139 if (!(known_meta_data & META_UID))
103 exit (EX_SOFTWARE); 140 {
141 mu_error (_("no such user: %s"), owner_user);
142 exit (EX_DATAERR);
143 }
104 } 144 }
105 if (owner_uid == -1 || owner_gid == -1) 145 else
106 { 146 {
107 struct stat st; 147 owner_uid = ap->uid;
108 148 known_meta_data |= META_UID;
109 if (fstat (dirfd, &st)) 149 mu_auth_data_free (ap);
150 }
151 }
152
153 if (known_meta_data & META_GROUP)
154 {
155 struct group *gr = getgrnam (owner_group);
156 if (!gr)
157 {
158 if (!(known_meta_data & META_GID))
110 { 159 {
111 mu_diag_funcall (MU_DIAG_ERROR, "fstat", db_name, errno); 160 mu_error (_("no such group: %s"), owner_group);
112 exit (EX_SOFTWARE); 161 exit (EX_DATAERR);
113 } 162 }
114 if (owner_uid == -1)
115 owner_uid = st.st_uid;
116 if (owner_gid == -1)
117 owner_gid = st.st_gid;
118 } 163 }
119 if (fchown (pagfd, owner_uid, owner_gid)) 164 else
120 { 165 {
121 mu_diag_funcall (MU_DIAG_ERROR, "fchown", db_name, errno); 166 owner_gid = gr->gr_gid;
167 known_meta_data |= META_GID;
168 }
169 }
170
171 if (fstat (dirfd, &st))
172 {
173 mu_diag_funcall (MU_DIAG_ERROR, "fstat", db_name, errno);
174 exit (EX_SOFTWARE);
175 }
176
177 if (known_meta_data & META_FILE_MODE)
178 {
179 if (fchmod (pagfd, file_mode) ||
180 (pagfd != dirfd && fchmod (dirfd, file_mode)))
181 {
182 mu_diag_funcall (MU_DIAG_ERROR, "fchmod", db_name, errno);
122 exit (EX_SOFTWARE); 183 exit (EX_SOFTWARE);
123 } 184 }
124 if (pagfd != dirfd && 185 }
125 fchown (dirfd, owner_uid, owner_gid)) 186
187 if (known_meta_data & (META_UID|META_GID))
188 {
189 if (!(known_meta_data & META_UID))
190 owner_uid = st.st_uid;
191 else if (!(known_meta_data & META_GID))
192 owner_gid = st.st_gid;
193
194 if (fchown (pagfd, owner_uid, owner_gid) ||
195 (pagfd != dirfd && fchown (dirfd, owner_uid, owner_gid)))
126 { 196 {
127 mu_diag_funcall (MU_DIAG_ERROR, "fchown", db_name, errno); 197 mu_diag_funcall (MU_DIAG_ERROR, "fchown", db_name, errno);
128 exit (EX_SOFTWARE); 198 exit (EX_SOFTWARE);
129 } 199 }
130 } 200 }
131 return db;
132 } 201 }
202
203
204 struct iobuf
205 {
206 mu_stream_t stream;
207 char *buffer;
208 size_t bufsize;
209 size_t length;
210 int read;
211 };
212
213 static int is_dbm_directive (struct iobuf *input);
214 static int is_len_directive (struct iobuf *input);
215 static int is_ignored_directive (const char *name);
216 static int set_directive (char *val);
217 static void print_header (const char *name, mu_stream_t str);
218
219 static int
220 input_getline (struct iobuf *inp)
221 {
222 int rc;
223 size_t len;
224
225 if (inp->read)
226 {
227 inp->read = 0;
228 return 0;
229 }
230
231 while (1)
232 {
233 rc = mu_stream_getline (inp->stream, &inp->buffer, &inp->bufsize, &len);
234 if (rc)
235 return rc;
236 if (len == 0)
237 {
238 inp->length = 0;
239 break;
240 }
241 mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM,
242 MU_IOCTL_LOGSTREAM_ADVANCE_LOCUS_LINE, NULL);
243 inp->length = mu_rtrim_class (inp->buffer, MU_CTYPE_ENDLN);
244 if (inp->buffer[0] == '#' && !is_dbm_directive (inp))
245 {
246 struct mu_locus loc;
247 mu_stream_ioctl (mu_strerr,
248 MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_GET_LOCUS,
249 &loc);
250 loc.mu_line = strtoul (inp->buffer + 1, NULL, 10);
251 mu_stream_ioctl (mu_strerr,
252 MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_SET_LOCUS,
253 &loc);
254 free (loc.mu_file);
255 continue;
256 }
257 break;
258 }
259 return 0;
260 }
261
262 static void
263 input_ungetline (struct iobuf *inp)
264 {
265 inp->read = 1;
266 }
267
268 static size_t
269 input_length (struct iobuf *inp)
270 {
271 return inp->length;
272 }
273
274 struct xfer_format
275 {
276 const char *name;
277 void (*init) (struct xfer_format *fmt, const char *version,
278 struct iobuf *iop, int wr);
279 int (*reader) (struct iobuf *, void *data, struct mu_dbm_datum *key,
280 struct mu_dbm_datum *content);
281 int (*writer) (struct iobuf *, void *data, struct mu_dbm_datum const *key,
282 struct mu_dbm_datum const *content);
283 void *data;
284 };
285
286 static int ascii_reader (struct iobuf *, void *data,
287 struct mu_dbm_datum *key,
288 struct mu_dbm_datum *content);
289 static int ascii_writer (struct iobuf *, void *data,
290 struct mu_dbm_datum const *key,
291 struct mu_dbm_datum const *content);
292
293 static void newfmt_init (struct xfer_format *fmt,
294 const char *version, struct iobuf *iop, int wr);
295
296 static int newfmt_reader (struct iobuf *, void *data,
297 struct mu_dbm_datum *key,
298 struct mu_dbm_datum *content);
299 static int newfmt_writer (struct iobuf *, void *data,
300 struct mu_dbm_datum const *key,
301 struct mu_dbm_datum const *content);
302
303 static struct xfer_format format_tab[] = {
304 { "0.0", NULL, ascii_reader, ascii_writer, NULL },
305 { "1.0", newfmt_init, newfmt_reader, newfmt_writer, NULL },
306 { NULL }
307 };
308 static int format_count = MU_ARRAY_SIZE (format_tab) - 1;
309
310 static struct xfer_format *format = format_tab;
311 static const char *dump_format_version;
312
313 static int
314 read_data (struct iobuf *inp, struct mu_dbm_datum *key,
315 struct mu_dbm_datum *content)
316 {
317 return format->reader (inp, format->data, key, content);
318 }
319
320 static int
321 write_data (struct iobuf *iop, struct mu_dbm_datum const *key,
322 struct mu_dbm_datum const *content)
323 {
324 return format->writer (iop, format->data, key, content);
325 }
326
327 static int
328 select_format (const char *version)
329 {
330 struct xfer_format *fmt;
331 char *p;
332 unsigned long n;
333
334 dump_format_version = version;
335 for (fmt = format_tab; fmt->name; fmt++)
336 if (strcmp (fmt->name, version) == 0)
337 {
338 format = fmt;
339 return 0;
340 }
341
342 /* Try version number */
343 errno = 0;
344 n = strtoul (version, &p, 10);
345 if ((*p == 0 || *p == '.') && errno == 0 && n < format_count)
346 {
347 format = format_tab + n;
348 return 0;
349 }
350 mu_error (_("unsupported format version: %s"), version);
351 return 1;
352 }
353
354 static void
355 init_format (int wr, struct iobuf *iop)
356 {
357 if (format->init)
358 format->init (format,
359 dump_format_version ? dump_format_version : format->name,
360 iop, wr);
361 }
362
363
364 static int
365 ascii_writer (struct iobuf *iop, void *data,
366 struct mu_dbm_datum const *key,
367 struct mu_dbm_datum const *content)
368 {
369 size_t len;
370
371 if (!data)
372 {
373 if (!suppress_header && include_zero == 1 &&
374 !is_ignored_directive ("null"))
375 mu_stream_printf (iop->stream, "#:null\n");
376 data = ascii_writer;
377 }
378
379 len = key->mu_dsize;
380 if (key->mu_dptr[len - 1] == 0)
381 len--;
382 mu_stream_write (iop->stream, key->mu_dptr, len, NULL);
383 mu_stream_write (iop->stream, "\t", 1, NULL);
384
385 len = content->mu_dsize;
386 if (content->mu_dptr[len - 1] == 0)
387 len--;
388 mu_stream_write (iop->stream, content->mu_dptr, len, NULL);
389 mu_stream_write (iop->stream, "\n", 1, NULL);
390 return 0;
391 }
392
393 static int
394 ascii_reader (struct iobuf *inp, void *data MU_ARG_UNUSED,
395 struct mu_dbm_datum *key,
396 struct mu_dbm_datum *content)
397 {
398 char *kstr, *val;
399 int rc;
400
401 rc = input_getline (inp);
402 if (rc)
403 {
404 mu_error ("%s", mu_strerror (rc));
405 return -1;
406 }
407 if (input_length (inp) == 0)
408 return 1;
409 kstr = mu_str_stripws (inp->buffer);
410 val = mu_str_skip_class_comp (kstr, MU_CTYPE_SPACE);
411 *val++ = 0;
412 val = mu_str_skip_class (val, MU_CTYPE_SPACE);
413 if (*val == 0)
414 {
415 mu_error (_("malformed line"));
416 key->mu_dsize = 0;
417 }
418 else
419 {
420 init_datum (key, kstr);
421 init_datum (content, val);
422 }
423 return 0;
424 }
425
426 static void
427 newfmt_init (struct xfer_format *fmt, const char *version,
428 struct iobuf *iop, int wr)
429 {
430 int rc;
431
432 if (!wr)
433 {
434 mu_stream_t flt;
435
436 rc = mu_linelen_filter_create (&flt, iop->stream, 76, MU_STREAM_WRITE);
437 if (rc)
438 {
439 mu_diag_funcall (MU_DIAG_ERROR, "mu_linelen_filter_create",
440 NULL, rc);
441 exit (EX_SOFTWARE);
442 }
443 iop->stream = flt;
444 }
445 else
446 {
447 mu_opool_t pool;
448 rc = mu_opool_create (&pool, 0);
449 if (rc)
450 {
451 mu_diag_funcall (MU_DIAG_ERROR, "mu_opool_create",
452 NULL, rc);
453 exit (EX_SOFTWARE);
454 }
455 fmt->data = pool;
456 }
457 }
458
459 static int
460 newfmt_read_datum (struct iobuf *iop, mu_opool_t pool,
461 struct mu_dbm_datum *datum)
462 {
463 int rc;
464 unsigned char *ptr, *out;
465 size_t len;
466
467 mu_dbm_datum_free (datum);
468
469 rc = input_getline (iop);
470 if (rc)
471 {
472 mu_error ("%s", mu_strerror (rc));
473 exit (EX_UNAVAILABLE);
474 }
475 if (iop->length == 0)
476 return 1;
477
478 if (!is_len_directive (iop))
479 {
480 mu_error (_("unrecognized input line"));
481 exit (EX_DATAERR);
482 }
483 else
484 {
485 char *p;
486 unsigned long n;
487
488 errno = 0;
489 n = strtoul (iop->buffer + 6, &p, 10);
490 if (*p || errno)
491 {
492 mu_error (_("invalid length"));
493 exit (EX_DATAERR);
494 }
495 datum->mu_dsize = n;
496 }
497
498 mu_opool_clear (pool);
499 while (1)
500 {
501 rc = input_getline (iop);
502 if (rc)
503 {
504 mu_error ("%s", mu_strerror (rc));
505 exit (EX_UNAVAILABLE);
506 }
507 if (iop->length == 0)
508 break;
509 if (is_len_directive (iop))
510 {
511 input_ungetline (iop);
512 break;
513 }
514 mu_opool_append (pool, iop->buffer, iop->length);
515 }
516
517 ptr = mu_opool_finish (pool, &len);
518
519 rc = mu_base64_decode (ptr, len, &out, &len);
520 if (rc)
521 {
522 mu_diag_funcall (MU_DIAG_ERROR, "mu_base64_decode", NULL, rc);
523 exit (EX_SOFTWARE);
524 }
525
526 mu_dbm_datum_free (datum);
527
528 datum->mu_dptr = (void*) out;
529 return 0;
530 }
531
532 static int
533 newfmt_reader (struct iobuf *input, void *data,
534 struct mu_dbm_datum *key,
535 struct mu_dbm_datum *content)
536 {
537 mu_opool_t pool = data;
538 if (newfmt_read_datum (input, pool, key))
539 return 1;
540 if (newfmt_read_datum (input, pool, content))
541 return 1;
542 return 0;
543 }
544
545 static void
546 newfmt_write_datum (struct iobuf *iop, struct mu_dbm_datum const *datum)
547 {
548 int rc;
549
550 mu_stream_printf (iop->stream, "#:len=%lu\n",
551 (unsigned long) datum->mu_dsize);
552
553 rc = mu_base64_encode ((unsigned char*)datum->mu_dptr, datum->mu_dsize,
554 (unsigned char **)&iop->buffer, &iop->bufsize);
555 if (rc)
556 {
557 mu_diag_funcall (MU_DIAG_ERROR, "mu_base64_encode", NULL, rc);
558 exit (EX_SOFTWARE);
559 }
560 mu_stream_write (iop->stream, iop->buffer, iop->bufsize, NULL);
561 free (iop->buffer); // FIXME
562 mu_stream_write (iop->stream, "\n", 1, NULL);
563 }
564
565 static int
566 newfmt_writer (struct iobuf *iop, void *data,
567 struct mu_dbm_datum const *key,
568 struct mu_dbm_datum const *content)
569 {
570 newfmt_write_datum (iop, key);
571 newfmt_write_datum (iop, content);
572 return 0;
573 }
574
133 575
134 struct print_data 576 struct print_data
135 { 577 {
136 mu_dbm_file_t db; 578 mu_dbm_file_t db;
137 mu_stream_t stream; 579 struct iobuf iob;
138 }; 580 };
139 581
140 static int 582 static int
...@@ -143,7 +585,69 @@ print_action (struct mu_dbm_datum const *key, void *data) ...@@ -143,7 +585,69 @@ print_action (struct mu_dbm_datum const *key, void *data)
143 int rc; 585 int rc;
144 struct mu_dbm_datum contents; 586 struct mu_dbm_datum contents;
145 struct print_data *pd = data; 587 struct print_data *pd = data;
146 size_t len; 588
589 if (!suppress_header)
590 {
591 int fd;
592 struct stat st;
593 const char *name, *p;
594 rc = mu_dbm_get_fd (pd->db, &fd, NULL);
595 if (rc)
596 {
597 mu_diag_funcall (MU_DIAG_ERROR, "mu_dbm_get_fd", db_name, rc);
598 exit (EX_SOFTWARE);
599 }
600 if (fstat (fd, &st))
601 {
602 mu_diag_funcall (MU_DIAG_ERROR, "fstat", db_name, errno);
603 exit (EX_UNAVAILABLE);
604 }
605
606 if (!(known_meta_data & META_UID))
607 {
608 known_meta_data |= META_UID;
609 owner_uid = st.st_uid;
610 }
611 if (!(known_meta_data & META_GID))
612 {
613 known_meta_data |= META_GID;
614 owner_gid = st.st_gid;
615 }
616 if (!(known_meta_data & META_FILE_MODE))
617 {
618 known_meta_data |= META_FILE_MODE;
619 file_mode = st.st_mode & 0777;
620 }
621
622 if (!(known_meta_data & META_USER))
623 {
624 struct mu_auth_data *ap = mu_get_auth_by_uid (owner_uid);
625 if (ap)
626 {
627 owner_user = xstrdup (ap->name);
628 known_meta_data |= META_USER;
629 mu_auth_data_free (ap);
630 }
631 }
632
633 if (!(known_meta_data & META_GROUP))
634 {
635 struct group *gr = getgrgid (owner_gid);
636 if (gr)
637 {
638 owner_group = xstrdup (gr->gr_name);
639 known_meta_data |= META_GROUP;
640 }
641 }
642
643 mu_dbm_get_name (pd->db, &name);
644 p = strrchr (name, '/');
645 if (p)
646 p++;
647 else
648 p = name;
649 print_header (p, mu_strout);
650 }
147 651
148 memset (&contents, 0, sizeof contents); 652 memset (&contents, 0, sizeof contents);
149 rc = mu_dbm_fetch (pd->db, key, &contents); 653 rc = mu_dbm_fetch (pd->db, key, &contents);
...@@ -152,20 +656,10 @@ print_action (struct mu_dbm_datum const *key, void *data) ...@@ -152,20 +656,10 @@ print_action (struct mu_dbm_datum const *key, void *data)
152 mu_error (_("database fetch error: %s"), mu_dbm_strerror (pd->db)); 656 mu_error (_("database fetch error: %s"), mu_dbm_strerror (pd->db));
153 exit (EX_UNAVAILABLE); 657 exit (EX_UNAVAILABLE);
154 } 658 }
155 659 rc = write_data (&pd->iob, key, &contents);
156 len = key->mu_dsize;
157 if (key->mu_dptr[len - 1] == 0)
158 len--;
159 mu_stream_write (pd->stream, key->mu_dptr, len, NULL);
160 mu_stream_write (pd->stream, "\t", 1, NULL);
161
162 len = contents.mu_dsize;
163 if (contents.mu_dptr[len - 1] == 0)
164 len--;
165 mu_stream_write (pd->stream, contents.mu_dptr, len, NULL);
166 mu_stream_write (pd->stream, "\n", 1, NULL);
167 mu_dbm_datum_free (&contents); 660 mu_dbm_datum_free (&contents);
168 return 0; 661 suppress_header = 1;
662 return rc;
169 } 663 }
170 664
171 static void 665 static void
...@@ -254,7 +748,7 @@ match_regex (const char *str, void *data) ...@@ -254,7 +748,7 @@ match_regex (const char *str, void *data)
254 return 0; 748 return 0;
255 } 749 }
256 750
257 void 751 static void
258 compile_regexes (int argc, char **argv, struct regmatch *match) 752 compile_regexes (int argc, char **argv, struct regmatch *match)
259 { 753 {
260 regex_t *regs = xcalloc (argc, sizeof (regs[0])); 754 regex_t *regs = xcalloc (argc, sizeof (regs[0]));
...@@ -293,10 +787,13 @@ list_database (int argc, char **argv) ...@@ -293,10 +787,13 @@ list_database (int argc, char **argv)
293 { 787 {
294 mu_dbm_file_t db = open_db_file (MU_STREAM_READ); 788 mu_dbm_file_t db = open_db_file (MU_STREAM_READ);
295 struct print_data pdata; 789 struct print_data pdata;
296 790
791 memset (&pdata, 0, sizeof pdata);
297 pdata.db = db; 792 pdata.db = db;
298 pdata.stream = mu_strout; 793 pdata.iob.stream = mu_strout;
299 794
795 init_format (0, &pdata.iob);
796
300 if (argc == 0) 797 if (argc == 0)
301 iterate_database (db, NULL, NULL, print_action, &pdata); 798 iterate_database (db, NULL, NULL, print_action, &pdata);
302 else 799 else
...@@ -321,23 +818,359 @@ list_database (int argc, char **argv) ...@@ -321,23 +818,359 @@ list_database (int argc, char **argv)
321 } 818 }
322 } 819 }
323 mu_dbm_destroy (&db); 820 mu_dbm_destroy (&db);
821 mu_stream_close (pdata.iob.stream);
822 }
823
824 static int
825 is_dbm_directive (struct iobuf *input)
826 {
827 return input->length > 2 &&
828 input->buffer[0] == '#' &&
829 input->buffer[1] == ':';
830 }
831
832 static int
833 is_len_directive (struct iobuf *input)
834 {
835 return input->length > 6 && memcmp (input->buffer, "#:len=", 6) == 0;
836 }
837
838 /*
839 #:version=1.0 # Version number
840 #:filename=S # Original database name (basename)
841 #:uid=N,user=S,gid=N,group=S,mode=N # File meta info
842 #:null[=0|1] # Null termination (v.0.0 only)
843 #:len=N # record length (v.1.0)
844 */
845
846 static int
847 _set_version (const char *val)
848 {
849 if (select_format (val))
850 exit (EX_DATAERR);
851 return 0;
852 }
853
854 static int
855 _set_file (const char *val)
856 {
857 if (!db_name)
858 db_name = xstrdup (val);
859 return 0;
860 }
861
862 static int
863 _set_null (const char *val)
864 {
865 if (!val)
866 include_zero = 1;
867 else if (val[0] == '0' && val[1] == 0)
868 include_zero = 0;
869 else if (val[0] == '1' && val[1] == 0)
870 include_zero = 1;
871 else
872 {
873 mu_error (_("bad value for `null' directive: %s"), val);
874 exit (EX_DATAERR);
875 }
876 return 0;
877 }
878
879 static int
880 _set_uid (const char *val)
881 {
882 char *p;
883 unsigned long n;
884
885 if (known_meta_data & META_UID)
886 return 0;
887 errno = 0;
888 n = strtoul (val, &p, 8);
889 if (*p || errno)
890 {
891 mu_error (_("invalid UID"));
892 exit (EX_DATAERR);
893 }
894 owner_uid = n;
895 known_meta_data |= META_UID;
896 return 0;
897 }
898
899 static int
900 _set_gid (const char *val)
901 {
902 char *p;
903 unsigned long n;
904
905 if (known_meta_data & META_GID)
906 return 0;
907 errno = 0;
908 n = strtoul (val, &p, 8);
909 if (*p || errno)
910 {
911 mu_error (_("invalid GID"));
912 exit (EX_DATAERR);
913 }
914 owner_gid = n;
915 known_meta_data |= META_GID;
916 return 0;
917 }
918
919 static int
920 _set_user (const char *val)
921 {
922 if (known_meta_data & META_USER)
923 return 0;
924 free (owner_user);
925 owner_user = xstrdup (val);
926 known_meta_data |= META_USER;
927 return 0;
928 }
929
930 static int
931 _set_group (const char *val)
932 {
933 if (known_meta_data & META_GROUP)
934 return 0;
935 free (owner_group);
936 owner_group = xstrdup (val);
937 known_meta_data |= META_GROUP;
938 return 0;
939 }
940
941 static int
942 _set_mode (const char *val)
943 {
944 char *p;
945 unsigned long n;
946
947 if (known_meta_data & META_FILE_MODE)
948 return 0;
949 errno = 0;
950 n = strtoul (val, &p, 8);
951 if (*p || errno || n > 0777)
952 {
953 mu_error (_("invalid file mode"));
954 exit (EX_DATAERR);
955 }
956 file_mode = n;
957 known_meta_data |= META_FILE_MODE;
958 return 0;
959 }
960
961 struct dbm_directive
962 {
963 const char *name;
964 size_t len;
965 int (*set) (const char *val);
966 int flags;
967 };
968
969 #define DF_VALUE 0x01 /* directive requires a value */
970 #define DF_HEADER 0x02 /* can appear only in file header */
971 #define DF_PROTECT 0x04 /* directive cannot be ignored */
972 #define DF_META 0x08 /* directive keeps file meta-information */
973 #define DF_SEEN 0x10 /* directive was already seen */
974 #define DF_IGNORE 0x20 /* ignore this directive */
975
976 static struct dbm_directive dbm_directive_table[] = {
977 #define S(s) #s, sizeof #s - 1
978 { S(version), _set_version, DF_HEADER|DF_VALUE|DF_PROTECT },
979 { S(file), _set_file, DF_HEADER|DF_VALUE },
980 { S(uid), _set_uid, DF_HEADER|DF_META|DF_VALUE },
981 { S(user), _set_user, DF_HEADER|DF_META|DF_VALUE },
982 { S(gid), _set_gid, DF_HEADER|DF_META|DF_VALUE },
983 { S(group), _set_group, DF_HEADER|DF_META|DF_VALUE },
984 { S(mode), _set_mode, DF_HEADER|DF_META|DF_VALUE },
985 { S(null), _set_null, DF_HEADER|DF_VALUE },
986 { S(null), _set_null, DF_HEADER },
987 #undef S
988 { NULL }
989 };
990
991 static void
992 ignore_directives (const char *arg)
993 {
994 struct mu_wordsplit ws;
995 size_t i;
996
997 ws.ws_delim = ",";
998 if (mu_wordsplit (arg, &ws,
999 MU_WRDSF_NOVAR | MU_WRDSF_NOCMD | MU_WRDSF_DELIM))
1000 {
1001 mu_error (_("cannot split input line: %s"), mu_wordsplit_strerror (&ws));
1002 exit (EX_SOFTWARE);
1003 }
1004
1005 for (i = 0; i < ws.ws_wordc; i++)
1006 {
1007 char *arg = ws.ws_wordv[i];
1008 size_t len = strlen (arg);
1009 struct dbm_directive *p;
1010 int found = 0;
1011
1012 for (p = dbm_directive_table; p->name; p++)
1013 {
1014 if (p->len == len && memcmp (p->name, arg, len) == 0)
1015 {
1016 if (p->flags & DF_PROTECT)
1017 mu_error (_("directive %s cannot be ignored"), p->name);
1018 else
1019 p->flags |= DF_IGNORE;
1020 found = 1;
1021 }
1022 }
1023 if (!found)
1024 mu_error (_("unknown directive: %s"), arg);
1025 }
1026 mu_wordsplit_free (&ws);
1027 }
1028
1029 static int
1030 is_ignored_directive (const char *arg)
1031 {
1032 size_t len = strlen (arg);
1033 struct dbm_directive *p;
1034
1035 for (p = dbm_directive_table; p->name; p++)
1036 {
1037 if (p->len == len && memcmp (p->name, arg, len) == 0)
1038 return p->flags & DF_IGNORE;
1039 }
1040 return 0;
324 } 1041 }
1042
1043 static void
1044 ignore_flagged_directives (int flag)
1045 {
1046 struct dbm_directive *p;
1047
1048 for (p = dbm_directive_table; p->name; p++)
1049 if (!(p->flags & DF_PROTECT) && (p->flags & flag))
1050 p->flags |= DF_IGNORE;
1051 }
1052
1053 static int
1054 set_directive (char *val)
1055 {
1056 size_t len;
1057 struct dbm_directive *p, *match = NULL;
1058
1059 mu_ltrim_class (val, MU_CTYPE_BLANK);
1060 mu_rtrim_class (val, MU_CTYPE_BLANK);
1061 len = strcspn (val, "=");
1062 for (p = dbm_directive_table; p->name; p++)
1063 {
1064 if (p->len == len && memcmp (p->name, val, len) == 0)
1065 {
1066 int rc;
1067
1068 match = p;
1069 if (val[len] == '=')
1070 {
1071 if (!(p->flags & DF_VALUE))
1072 continue;
1073 }
1074 else if (p->flags & DF_VALUE)
1075 continue;
1076
1077 if (p->flags & DF_IGNORE)
1078 return 0;
1079
1080 if (p->flags & DF_SEEN)
1081 {
1082 mu_error (_("directive %s appeared twice"), val);
1083 return 1;
1084 }
1085 rc = p->set ((p->flags & DF_VALUE) ? val + len + 1 : NULL);
1086 if (p->flags & DF_HEADER)
1087 p->flags |= DF_SEEN;
1088 return rc;
1089 }
1090 }
1091 if (match)
1092 {
1093 if (match->flags & DF_VALUE)
1094 mu_error (_("directive requires argument: %s"), val);
1095 else
1096 mu_error (_("directive does not take argument: %s"), val);
1097 }
1098 else
1099 mu_error (_("unknown or unsupported directive %s"), val);
1100 return 1;
1101 }
1102
1103 static void
1104 print_header (const char *name, mu_stream_t str)
1105 {
1106 char *delim;
1107 time_t t;
1108
1109 time (&t);
1110 mu_stream_printf (str, "# ");
1111 mu_stream_printf (str, _("Database dump file created by %s on %s"),
1112 PACKAGE_STRING,
1113 ctime (&t));
1114 mu_stream_printf (str, "#:version=%s\n", format->name);
1115 if (!is_ignored_directive ("file"))
1116 mu_stream_printf (str, "#:file=%s\n", name);
1117
1118 delim = "#:";
1119 if ((known_meta_data & META_UID) && !is_ignored_directive ("uid"))
1120 {
1121 mu_stream_printf (str, "%suid=%lu", delim, (unsigned long) owner_uid);
1122 delim = ",";
1123 }
1124 if ((known_meta_data & META_USER) && !is_ignored_directive ("user"))
1125 {
1126 mu_stream_printf (str, "%suser=%s", delim, owner_user);
1127 delim = ",";
1128 }
1129
1130 if ((known_meta_data & META_GID) && !is_ignored_directive ("gid"))
1131 {
1132 mu_stream_printf (str, "%sgid=%lu", delim, (unsigned long) owner_gid);
1133 delim = ",";
1134 }
1135
1136 if ((known_meta_data & META_GROUP) && !is_ignored_directive ("group"))
1137 {
1138 mu_stream_printf (str, "%sgroup=%s", delim, owner_group);
1139 delim = ",";
1140 }
1141
1142 if ((known_meta_data & META_FILE_MODE) && !is_ignored_directive ("mode"))
1143 mu_stream_printf (str, "%smode=%03o", delim, file_mode);
1144
1145 if (delim[0] == ',')
1146 mu_stream_printf (str, "\n");
1147 }
1148
325 1149
326 void 1150 static void
327 add_records (int mode, int replace) 1151 add_records (int mode, int replace)
328 { 1152 {
329 mu_dbm_file_t db; 1153 mu_dbm_file_t db;
330 mu_stream_t input, flt; 1154 mu_stream_t instream, flt;
331 const char *flt_argv[] = { "inline-comment", "#", "-S", "-i", "#", NULL }; 1155 const char *flt_argv[] = { "inline-comment", "#", "-S", "-i", "#", NULL };
332 char *buf = NULL;
333 size_t size = 0;
334 size_t len;
335 unsigned long line;
336 int rc; 1156 int rc;
1157 int save_log_mode = 0, log_mode;
1158 struct mu_locus save_locus = { NULL, }, locus;
1159 struct mu_dbm_datum key, contents;
1160 struct iobuf input;
1161 struct mu_wordsplit ws;
1162 int wsflags = MU_WRDSF_NOVAR | MU_WRDSF_NOCMD | MU_WRDSF_DELIM;
1163
1164 if (mode != MU_STREAM_CREAT)
1165 {
1166 ignore_flagged_directives (DF_META);
1167 known_meta_data = 0;
1168 }
337 1169
1170 /* Prepare input data */
338 if (input_file) 1171 if (input_file)
339 { 1172 {
340 rc = mu_file_stream_create (&input, input_file, MU_STREAM_READ); 1173 rc = mu_file_stream_create (&instream, input_file, MU_STREAM_READ);
341 if (rc) 1174 if (rc)
342 { 1175 {
343 mu_error (_("cannot open input file %s: %s"), input_file, 1176 mu_error (_("cannot open input file %s: %s"), input_file,
...@@ -346,9 +1179,9 @@ add_records (int mode, int replace) ...@@ -346,9 +1179,9 @@ add_records (int mode, int replace)
346 } 1179 }
347 } 1180 }
348 else 1181 else
349 input = mu_strin; 1182 instream = mu_strin;
350 1183
351 rc = mu_filter_create_args (&flt, input, "inline-comment", 1184 rc = mu_filter_create_args (&flt, instream, "inline-comment",
352 MU_ARRAY_SIZE (flt_argv) - 1, flt_argv, 1185 MU_ARRAY_SIZE (flt_argv) - 1, flt_argv,
353 MU_FILTER_DECODE, MU_STREAM_READ); 1186 MU_FILTER_DECODE, MU_STREAM_READ);
354 if (rc) 1187 if (rc)
...@@ -356,56 +1189,103 @@ add_records (int mode, int replace) ...@@ -356,56 +1189,103 @@ add_records (int mode, int replace)
356 mu_diag_funcall (MU_DIAG_ERROR, "mu_filter_create_args", input_file, rc); 1189 mu_diag_funcall (MU_DIAG_ERROR, "mu_filter_create_args", input_file, rc);
357 exit (EX_UNAVAILABLE); 1190 exit (EX_UNAVAILABLE);
358 } 1191 }
359 mu_stream_unref (input); 1192 mu_stream_unref (instream);
360 input = flt; 1193 instream = flt;
361 1194
362 db = open_db_file (mode); 1195 /* Configure error stream to output input file location before each error
1196 message */
1197 locus.mu_file = input_file ? input_file : "<stdin>";
1198 locus.mu_line = 0;
1199 locus.mu_col = 0;
1200
1201 mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_GET_MODE,
1202 &save_log_mode);
1203 mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_GET_LOCUS,
1204 &save_locus);
1205 log_mode = save_log_mode | MU_LOGMODE_LOCUS;
1206 mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_SET_MODE,
1207 &log_mode);
1208 mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_SET_LOCUS,
1209 &locus);
363 1210
364 line = 1; 1211 /* Initialize I/O data */
365 if (!input_file) 1212 memset (&key, 0, sizeof key);
366 input_file = "<stdin>"; 1213 memset (&contents, 0, sizeof contents);
367 while ((rc = mu_stream_getline (input, &buf, &size, &len)) == 0 1214
368 && len > 0) 1215 /* Initialize input buffer */
1216 input.buffer = NULL;
1217 input.bufsize = 0;
1218 input.length = 0;
1219 input.read = 0;
1220 input.stream = instream;
1221
1222 /* Read directive header */
1223 ws.ws_delim = ",";
1224 while ((rc = input_getline (&input)) == 0 &&
1225 is_dbm_directive (&input) &&
1226 !is_len_directive (&input))
369 { 1227 {
370 struct mu_dbm_datum key, contents; 1228 size_t i;
371 char *kstr, *val; 1229
372 1230 if (mu_wordsplit (input.buffer + 2, &ws, wsflags))
373 mu_rtrim_class (buf, MU_CTYPE_ENDLN);
374 if (buf[0] == '#')
375 { 1231 {
376 line = strtoul (buf + 1, NULL, 10); 1232 mu_error (_("cannot split input line: %s"),
377 continue; 1233 mu_wordsplit_strerror (&ws));
1234 exit (EX_SOFTWARE);
378 } 1235 }
379 kstr = mu_str_stripws (buf); 1236 for (i = 0; i < ws.ws_wordc; i++)
380 val = mu_str_skip_class_comp (kstr, MU_CTYPE_SPACE);
381 *val++ = 0;
382 val = mu_str_skip_class (val, MU_CTYPE_SPACE);
383 if (*val == 0)
384 { 1237 {
385 mu_error (_("%s:%lu: malformed line"), input_file, line); 1238 set_directive (ws.ws_wordv[i]);
386 line++;
387 continue;
388 } 1239 }
1240 wsflags |= MU_WRDSF_REUSE;
1241 }
1242 if (wsflags & MU_WRDSF_REUSE)
1243 mu_wordsplit_free (&ws);
389 1244
390 init_datum (&key, kstr); 1245 init_format (1, &input);
391 init_datum (&contents, val); 1246
1247 /* Open the database */
1248 db = open_db_file (mode);
1249 if (known_meta_data)
1250 set_db_ownership (db);
1251
1252 /* Read and store the actual data */
1253 if (rc == 0 && input_length (&input) > 0)
1254 {
1255 ignore_flagged_directives (DF_HEADER);
1256 input_ungetline (&input);
392 1257
393 rc = mu_dbm_store (db, &key, &contents, replace); 1258 memset (&key, 0, sizeof key);
394 if (rc) 1259 memset (&contents, 0, sizeof contents);
395 mu_error (_("%s:%lu: cannot store datum: %s"), 1260
396 input_file, line, 1261 while ((rc = read_data (&input, &key, &contents)) == 0)
397 rc == MU_ERR_FAILURE ? 1262 {
398 mu_dbm_strerror (db) : mu_strerror (rc)); 1263 if (key.mu_dsize)
399 line++; 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 }
400 } 1272 }
1273
1274 mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_SET_MODE,
1275 &save_log_mode);
1276 mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM, MU_IOCTL_LOGSTREAM_SET_LOCUS,
1277 &save_locus);
1278
401 mu_dbm_destroy (&db); 1279 mu_dbm_destroy (&db);
402 1280 mu_stream_unref (instream);
403 mu_stream_unref (input);
404 } 1281 }
405 1282
406 static void 1283 static void
407 create_database () 1284 create_database ()
408 { 1285 {
1286 if (getuid() != 0)
1287 ignore_flagged_directives (DF_META);
1288
409 if (copy_permissions) 1289 if (copy_permissions)
410 { 1290 {
411 struct stat st; 1291 struct stat st;
...@@ -422,14 +1302,21 @@ create_database () ...@@ -422,14 +1302,21 @@ create_database ()
422 } 1302 }
423 owner_uid = st.st_uid; 1303 owner_uid = st.st_uid;
424 owner_gid = st.st_gid; 1304 owner_gid = st.st_gid;
425 permissions = st.st_mode & 0777; 1305 file_mode = st.st_mode & 0777;
1306 known_meta_data |= META_UID | META_GID | META_FILE_MODE;
426 } 1307 }
427 else if (auth) 1308 else if (auth)
428 { 1309 {
429 if (owner_uid == -1) 1310 if (!(known_meta_data & META_UID))
430 owner_uid = auth->uid; 1311 {
431 if (owner_gid == -1) 1312 owner_uid = auth->uid;
432 owner_gid = auth->gid; 1313 known_meta_data |= META_UID;
1314 }
1315 if (!(known_meta_data & META_GID))
1316 {
1317 owner_gid = auth->gid;
1318 known_meta_data |= META_GID;
1319 }
433 } 1320 }
434 add_records (MU_STREAM_CREAT, 0); 1321 add_records (MU_STREAM_CREAT, 0);
435 } 1322 }
...@@ -558,6 +1445,15 @@ static struct argp_option dbm_options[] = { ...@@ -558,6 +1445,15 @@ static struct argp_option dbm_options[] = {
558 N_("set database owner group") }, 1445 N_("set database owner group") },
559 { "copy-permissions", 'P', NULL, 0, 1446 { "copy-permissions", 'P', NULL, 0,
560 N_("copy database permissions and ownership from the input file") }, 1447 N_("copy database permissions and ownership from the input file") },
1448 { "ignore-meta", 'm', NULL, 0,
1449 N_("ignore meta-information from input file headers") },
1450 { "ignore-directives", 'I', N_("NAMES"), 0,
1451 N_("ignore the listed directives") },
1452 { NULL, 0, NULL, 0, N_("List modifiers"), 0},
1453 { "format", 'H', N_("TYPE"), 0,
1454 N_("select output format") },
1455 { "no-header", 'q', NULL, 0,
1456 N_("suppress format header") },
561 { NULL, 0, NULL, 0, N_("List and Delete modifiers"), 0}, 1457 { NULL, 0, NULL, 0, N_("List and Delete modifiers"), 0},
562 { "glob", 'G', NULL, 0, 1458 { "glob", 'G', NULL, 0,
563 N_("treat keys as globbing patterns") }, 1459 N_("treat keys as globbing patterns") },
...@@ -602,13 +1498,18 @@ dbm_parse_opt (int key, char *arg, struct argp_state *state) ...@@ -602,13 +1498,18 @@ dbm_parse_opt (int key, char *arg, struct argp_state *state)
602 input_file = arg; 1498 input_file = arg;
603 break; 1499 break;
604 1500
1501 case 'H':
1502 select_format (arg);
1503 break;
1504
605 case 'p': 1505 case 'p':
606 { 1506 {
607 char *p; 1507 char *p;
608 unsigned long d = strtoul (arg, &p, 8); 1508 unsigned long d = strtoul (arg, &p, 8);
609 if (*p || (d & ~0777)) 1509 if (*p || (d & ~0777))
610 argp_error (state, _("invalid file mode: %s"), arg); 1510 argp_error (state, _("invalid file mode: %s"), arg);
611 permissions = d; 1511 file_mode = d;
1512 known_meta_data |= META_FILE_MODE;
612 } 1513 }
613 break; 1514 break;
614 1515
...@@ -616,17 +1517,27 @@ dbm_parse_opt (int key, char *arg, struct argp_state *state) ...@@ -616,17 +1517,27 @@ dbm_parse_opt (int key, char *arg, struct argp_state *state)
616 copy_permissions = 1; 1517 copy_permissions = 1;
617 break; 1518 break;
618 1519
1520 case 'q':
1521 suppress_header = 1;
1522 break;
1523
619 case 'u': 1524 case 'u':
620 auth = mu_get_auth_by_name (arg); 1525 auth = mu_get_auth_by_name (arg);
621 if (!auth) 1526 if (auth)
1527 known_meta_data |= META_AUTH;
1528 else
622 { 1529 {
623 char *p; 1530 char *p;
624 unsigned long n = strtoul (arg, &p, 0); 1531 unsigned long n = strtoul (arg, &p, 0);
625 if (*p == 0) 1532 if (*p == 0)
626 owner_uid = n; 1533 {
1534 owner_uid = n;
1535 known_meta_data |= META_UID;
1536 }
627 else 1537 else
628 argp_error (state, _("no such user: %s"), arg); 1538 argp_error (state, _("no such user: %s"), arg);
629 } 1539 }
1540 ignore_directives ("user,uid");
630 break; 1541 break;
631 1542
632 case 'g': 1543 case 'g':
...@@ -643,6 +1554,8 @@ dbm_parse_opt (int key, char *arg, struct argp_state *state) ...@@ -643,6 +1554,8 @@ dbm_parse_opt (int key, char *arg, struct argp_state *state)
643 } 1554 }
644 else 1555 else
645 owner_gid = gr->gr_gid; 1556 owner_gid = gr->gr_gid;
1557 known_meta_data |= META_GID;
1558 ignore_directives ("group,gid");
646 } 1559 }
647 break; 1560 break;
648 1561
...@@ -654,6 +1567,14 @@ dbm_parse_opt (int key, char *arg, struct argp_state *state) ...@@ -654,6 +1567,14 @@ dbm_parse_opt (int key, char *arg, struct argp_state *state)
654 key_type = key_regex; 1567 key_type = key_regex;
655 break; 1568 break;
656 1569
1570 case 'm':/* FIXME: Why m? */
1571 ignore_flagged_directives (DF_META);
1572 break;
1573
1574 case 'I':
1575 ignore_directives (arg);
1576 break;
1577
657 case 'i': 1578 case 'i':
658 case_sensitive = 0; 1579 case_sensitive = 0;
659 break; 1580 break;
...@@ -686,8 +1607,8 @@ int ...@@ -686,8 +1607,8 @@ int
686 mutool_dbm (int argc, char **argv) 1607 mutool_dbm (int argc, char **argv)
687 { 1608 {
688 int index; 1609 int index;
689 1610
690 if (argp_parse (&dbm_argp, argc, argv, ARGP_IN_ORDER, &index, NULL)) 1611 if (argp_parse (&dbm_argp, argc, argv, 0, &index, NULL))
691 return 1; 1612 return 1;
692 1613
693 argc -= index; 1614 argc -= index;
...@@ -695,12 +1616,18 @@ mutool_dbm (int argc, char **argv) ...@@ -695,12 +1616,18 @@ mutool_dbm (int argc, char **argv)
695 1616
696 if (argc == 0) 1617 if (argc == 0)
697 { 1618 {
698 mu_error (_("database name not given")); 1619 if (mode != mode_create)
699 exit (EX_USAGE); 1620 {
1621 mu_error (_("database name not given"));
1622 exit (EX_USAGE);
1623 }
700 } 1624 }
701 db_name = *argv++; 1625 else
702 --argc; 1626 {
703 1627 db_name = *argv++;
1628 --argc;
1629 }
1630
704 switch (mode) 1631 switch (mode)
705 { 1632 {
706 case mode_list: 1633 case mode_list:
......