1 /* This file is part of GDBM, the GNU data base manager.
2 Copyright (C) 1990-2021 Free Software Foundation, Inc.
3
4 GDBM is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 GDBM 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
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with GDBM. If not, see <http://www.gnu.org/licenses/>. */
16
17 #include "gdbmtool.h"
18 #include "gdbm.h"
19 #include "gram.h"
20
21 #include <errno.h>
22 #include <ctype.h>
23 #include <signal.h>
24 #include <pwd.h>
25 #include <sys/ioctl.h>
26 #include <sys/wait.h>
27 #include <sys/time.h>
28 #include <sys/resource.h>
29 #include <termios.h>
30 #include <stdarg.h>
31 #ifdef HAVE_LOCALE_H
32 # include <locale.h>
33 #endif
34
35 static GDBM_FILE gdbm_file = NULL; /* Database to operate upon */
36 static datum key_data; /* Current key */
37 static datum return_data; /* Current data */
38
39 /* Return values for hanlders: */
40 enum
41 {
42 GDBMSHELL_OK, /* Success */
43 GDBMSHELL_GDBM_ERR, /* GDBM error */
44 GDBMSHELL_SYNTAX, /* Syntax error (invalid argument etc) */
45 GDBMSHELL_ERR, /* Other error */
46 GDBMSHELL_CANCEL /* Operation canceled */
47 };
48
49 static void
datum_free(datum * dp)50 datum_free (datum *dp)
51 {
52 free (dp->dptr);
53 dp->dptr = NULL;
54 }
55
56
57 int
gdbmshell_setopt(char * name,int opt,int val)58 gdbmshell_setopt (char *name, int opt, int val)
59 {
60 if (gdbm_file)
61 {
62 if (gdbm_setopt (gdbm_file, opt, &val, sizeof (val)) == -1)
63 {
64 dberror (_("%s failed"), name);
65 return 1;
66 }
67 }
68 return 0;
69 }
70
71 static void
closedb(void)72 closedb (void)
73 {
74 if (gdbm_file)
75 {
76 gdbm_close (gdbm_file);
77 gdbm_file = NULL;
78 variable_unset ("fd");
79 }
80
81 datum_free (&key_data);
82 datum_free (&return_data);
83 }
84
85 static int
opendb(char * dbname,int fd)86 opendb (char *dbname, int fd)
87 {
88 int cache_size = 0;
89 int block_size = 0;
90 int flags;
91 int filemode;
92 GDBM_FILE db;
93 int n;
94
95 switch (variable_get ("cachesize", VART_INT, (void**) &cache_size))
96 {
97 case VAR_OK:
98 case VAR_ERR_NOTSET:
99 break;
100 default:
101 abort ();
102 }
103 switch (variable_get ("blocksize", VART_INT, (void**) &block_size))
104 {
105 case VAR_OK:
106 case VAR_ERR_NOTSET:
107 break;
108 default:
109 abort ();
110 }
111
112 if (variable_get ("open", VART_INT, (void**) &flags) != VAR_OK)
113 abort ();
114
115 if (flags == GDBM_NEWDB)
116 {
117 if (interactive () && variable_is_true ("confirm") &&
118 access (dbname, F_OK) == 0)
119 {
120 if (!getyn (_("database %s already exists; overwrite"), dbname))
121 return GDBMSHELL_CANCEL;
122 }
123 }
124
125 if (variable_get ("format", VART_INT, (void**) &n) != VAR_OK)
126 abort ();
127
128 flags |= n;
129
130 if (!variable_is_true ("lock"))
131 flags |= GDBM_NOLOCK;
132 if (!variable_is_true ("mmap"))
133 flags |= GDBM_NOMMAP;
134 if (variable_is_true ("sync"))
135 flags |= GDBM_SYNC;
136
137 if (variable_get ("filemode", VART_INT, (void**) &filemode))
138 abort ();
139
140 if (fd > 0)
141 db = gdbm_fd_open (fd, dbname, block_size, flags | GDBM_CLOERROR, NULL);
142 else
143 {
144 char *name = tildexpand (dbname);
145 db = gdbm_open (name, block_size, flags, filemode, NULL);
146 free (name);
147 }
148
149 if (db == NULL)
150 {
151 dberror (_("cannot open database %s"), dbname);
152 return GDBMSHELL_GDBM_ERR;
153 }
154
155 if (cache_size &&
156 gdbm_setopt (db, GDBM_CACHESIZE, &cache_size, sizeof (int)) == -1)
157 dberror (_("%s failed"), "GDBM_CACHESIZE");
158
159 if (variable_is_true ("coalesce"))
160 {
161 gdbmshell_setopt ("GDBM_SETCOALESCEBLKS", GDBM_SETCOALESCEBLKS, 1);
162 }
163 if (variable_is_true ("centfree"))
164 {
165 gdbmshell_setopt ("GDBM_SETCENTFREE", GDBM_SETCENTFREE, 1);
166 }
167
168 if (gdbm_file)
169 gdbm_close (gdbm_file);
170
171 gdbm_file = db;
172 return GDBMSHELL_OK;
173 }
174
175 static int
checkdb(void)176 checkdb (void)
177 {
178 if (!gdbm_file)
179 {
180 char *filename;
181 int fd = -1;
182 variable_get ("filename", VART_STRING, (void**) &filename);
183 variable_get ("fd", VART_INT, (void**) &fd);
184 return opendb (filename, fd);
185 }
186 return GDBMSHELL_OK;
187 }
188
189 static int
checkdb_begin(struct command_param * param GDBM_ARG_UNUSED,struct command_environ * cenv GDBM_ARG_UNUSED,size_t * exp_count GDBM_ARG_UNUSED)190 checkdb_begin (struct command_param *param GDBM_ARG_UNUSED,
191 struct command_environ *cenv GDBM_ARG_UNUSED,
192 size_t *exp_count GDBM_ARG_UNUSED)
193 {
194 return checkdb ();
195 }
196
197 static size_t
bucket_print_lines(hash_bucket * bucket)198 bucket_print_lines (hash_bucket *bucket)
199 {
200 return 6 + gdbm_file->header->bucket_elems + 3 + bucket->av_count;
201 }
202
203 static void
format_key_start(FILE * fp,bucket_element * elt)204 format_key_start (FILE *fp, bucket_element *elt)
205 {
206 int size = SMALL < elt->key_size ? SMALL : elt->key_size;
207 int i;
208
209 for (i = 0; i < size; i++)
210 {
211 if (isprint (elt->key_start[i]))
212 fprintf (fp, " %c", elt->key_start[i]);
213 else
214 fprintf (fp, " %03o", elt->key_start[i]);
215 }
216 }
217
218 /* Debug procedure to print the contents of the current hash bucket. */
219 static void
print_bucket(FILE * fp,hash_bucket * bucket,const char * mesg,...)220 print_bucket (FILE *fp, hash_bucket *bucket, const char *mesg, ...)
221 {
222 int index;
223 va_list ap;
224
225 fprintf (fp, "******* ");
226 va_start(ap, mesg);
227 vfprintf (fp, mesg, ap);
228 va_end (ap);
229 fprintf (fp, " **********\n\n");
230 fprintf (fp,
231 _("bits = %d\ncount= %d\nHash Table:\n"),
232 bucket->bucket_bits, bucket->count);
233 fprintf (fp,
234 _(" # hash value key size data size data adr home key start\n"));
235 for (index = 0; index < gdbm_file->header->bucket_elems; index++)
236 {
237 fprintf (fp, " %4d %12x %11d %11d %11lu %4d", index,
238 bucket->h_table[index].hash_value,
239 bucket->h_table[index].key_size,
240 bucket->h_table[index].data_size,
241 (unsigned long) bucket->h_table[index].data_pointer,
242 bucket->h_table[index].hash_value %
243 gdbm_file->header->bucket_elems);
244 if (bucket->h_table[index].key_size)
245 {
246 fprintf (fp, " ");
247 format_key_start (fp, &bucket->h_table[index]);
248 }
249 fprintf (fp, "\n");
250 }
251
252 fprintf (fp, _("\nAvail count = %1d\n"), bucket->av_count);
253 fprintf (fp, _("Address size\n"));
254 for (index = 0; index < bucket->av_count; index++)
255 fprintf (fp, "%11lu%9d\n",
256 (unsigned long) bucket->bucket_avail[index].av_adr,
257 bucket->bucket_avail[index].av_size);
258 }
259
260 struct avail_list_counter
261 {
262 size_t min_size;
263 size_t lines;
264 };
265
266 static int
avail_list_count(avail_block * avblk,off_t off,void * data)267 avail_list_count (avail_block *avblk, off_t off, void *data)
268 {
269 struct avail_list_counter *ctr = data;
270
271 ctr->lines += avblk->count;
272 return ctr->lines > ctr->min_size;
273 }
274
275 static size_t
_gdbm_avail_list_size(GDBM_FILE dbf,size_t min_size)276 _gdbm_avail_list_size (GDBM_FILE dbf, size_t min_size)
277 {
278 struct avail_list_counter ctr;
279 ctr.min_size = 0;
280 ctr.lines = 0;
281 gdbm_avail_traverse (dbf, avail_list_count, &ctr);
282 return ctr.lines;
283 }
284
285 static void
av_table_display(avail_elem * av_table,int count,FILE * fp)286 av_table_display (avail_elem *av_table, int count, FILE *fp)
287 {
288 int i;
289
290 for (i = 0; i < count; i++)
291 {
292 fprintf (fp, " %15d %10lu \n",
293 av_table[i].av_size, (unsigned long) av_table[i].av_adr);
294 }
295 }
296
297 static int
avail_list_print(avail_block * avblk,off_t n,void * data)298 avail_list_print (avail_block *avblk, off_t n, void *data)
299 {
300 FILE *fp = data;
301
302 fputc ('\n', fp);
303 if (n == 0)//FIXME
304 fprintf (fp, "%s", _("header block"));
305 else
306 fprintf (fp, _("block = %lu"), (unsigned long) n);
307 fprintf (fp, _("\nsize = %d\ncount = %d\n"),
308 avblk->size, avblk->count);
309 av_table_display (avblk->av_table, avblk->count, fp);
310 return 0;
311 }
312
313 static int
_gdbm_print_avail_list(FILE * fp,GDBM_FILE dbf)314 _gdbm_print_avail_list (FILE *fp, GDBM_FILE dbf)
315 {
316 int rc = gdbm_avail_traverse (dbf, avail_list_print, fp);
317 if (rc)
318 dberror (_("%s failed"), "gdbm_avail_traverse");
319 return GDBMSHELL_GDBM_ERR;
320 }
321
322 static void
_gdbm_print_bucket_cache(FILE * fp,GDBM_FILE dbf)323 _gdbm_print_bucket_cache (FILE *fp, GDBM_FILE dbf)
324 {
325 if (dbf->cache_num)
326 {
327 int i;
328 cache_elem *elem;
329
330 fprintf (fp,
331 _("Bucket Cache (size %zu/%zu):\n Index: Address Changed Data_Hash \n"),
332 dbf->cache_num, dbf->cache_size);
333 for (elem = dbf->cache_entry, i = 0; elem; elem = elem->ca_next, i++)
334 {
335 fprintf (fp, " %5d: %15lu %7s %x\n",
336 i,
337 (unsigned long) elem->ca_adr,
338 (elem->ca_changed ? _("True") : _("False")),
339 elem->ca_data.hash_val);
340 }
341 }
342 else
343 fprintf (fp, _("Bucket cache is empty.\n"));
344 }
345
346 static int
trimnl(char * str)347 trimnl (char *str)
348 {
349 int len = strlen (str);
350
351 if (str[len - 1] == '\n')
352 {
353 str[--len] = 0;
354 return 1;
355 }
356 return 0;
357 }
358
359 static int
get_screen_lines(void)360 get_screen_lines (void)
361 {
362 #ifdef TIOCGWINSZ
363 if (isatty (1))
364 {
365 struct winsize ws;
366
367 ws.ws_col = ws.ws_row = 0;
368 if ((ioctl(1, TIOCGWINSZ, (char *) &ws) < 0) || ws.ws_row == 0)
369 {
370 const char *lines = getenv ("LINES");
371 if (lines)
372 ws.ws_row = strtol (lines, NULL, 10);
373 }
374 return ws.ws_row;
375 }
376 #else
377 const char *lines = getenv ("LINES");
378 if (lines)
379 return strtol (lines, NULL, 10);
380 #endif
381 return -1;
382 }
383
384 /* Open database */
385 static int
open_handler(struct command_param * param,struct command_environ * cenv GDBM_ARG_UNUSED)386 open_handler (struct command_param *param,
387 struct command_environ *cenv GDBM_ARG_UNUSED)
388 {
389 char *filename;
390 int fd = -1;
391 int rc;
392
393 closedb ();
394
395 if (param->argc == 1)
396 filename = PARAM_STRING (param, 0);
397 else
398 {
399 variable_get ("filename", VART_STRING, (void**) &filename);
400 variable_get ("fd", VART_INT, (void**) &fd);
401 }
402
403 if ((rc = opendb (filename, fd)) == GDBMSHELL_OK)
404 {
405 variable_set ("filename", VART_STRING, filename);
406 if (fd >= 0)
407 variable_set ("fd", VART_INT, &fd);
408 else
409 variable_unset ("fd");
410 }
411 return rc;
412 }
413
414 /* Close database */
415 static int
close_handler(struct command_param * param GDBM_ARG_UNUSED,struct command_environ * cenv GDBM_ARG_UNUSED)416 close_handler (struct command_param *param GDBM_ARG_UNUSED,
417 struct command_environ *cenv GDBM_ARG_UNUSED)
418 {
419 if (!gdbm_file)
420 terror ("%s", _("nothing to close"));
421 else
422 closedb ();
423 return GDBMSHELL_OK;
424 }
425
426 static char *
count_to_str(gdbm_count_t count,char * buf,size_t bufsize)427 count_to_str (gdbm_count_t count, char *buf, size_t bufsize)
428 {
429 char *p = buf + bufsize;
430
431 *--p = 0;
432 if (count == 0)
433 *--p = '0';
434 else
435 while (count)
436 {
437 if (p == buf)
438 return NULL;
439 *--p = '0' + count % 10;
440 count /= 10;
441 }
442 return p;
443 }
444
445 /* count - count items in the database */
446 static int
count_handler(struct command_param * param GDBM_ARG_UNUSED,struct command_environ * cenv)447 count_handler (struct command_param *param GDBM_ARG_UNUSED,
448 struct command_environ *cenv)
449 {
450 gdbm_count_t count;
451
452 if (gdbm_count (gdbm_file, &count))
453 {
454 dberror (_("%s failed"), "gdbm_count");
455 return GDBMSHELL_GDBM_ERR;
456 }
457 else
458 {
459 char buf[128];
460 char *p = count_to_str (count, buf, sizeof buf);
461
462 if (!p)
463 terror ("%s", _("count buffer overflow"));
464 else
465 fprintf (cenv->fp,
466 ngettext ("There is %s item in the database.\n",
467 "There are %s items in the database.\n",
468 count),
469 p);
470 }
471 return GDBMSHELL_OK;
472 }
473
474 /* delete KEY - delete a key*/
475 static int
delete_handler(struct command_param * param,struct command_environ * cenv)476 delete_handler (struct command_param *param, struct command_environ *cenv)
477 {
478 if (gdbm_delete (gdbm_file, PARAM_DATUM (param, 0)) != 0)
479 {
480 if (gdbm_errno == GDBM_ITEM_NOT_FOUND)
481 {
482 if (!gdbm_error_is_masked (gdbm_errno))
483 terror ("%s", _("No such item found"));
484 }
485 else
486 dberror ("%s", _("Can't delete"));
487 return GDBMSHELL_GDBM_ERR;
488 }
489 return GDBMSHELL_OK;
490 }
491
492 /* fetch KEY - fetch a record by its key */
493 static int
fetch_handler(struct command_param * param,struct command_environ * cenv)494 fetch_handler (struct command_param *param, struct command_environ *cenv)
495 {
496 return_data = gdbm_fetch (gdbm_file, PARAM_DATUM (param, 0));
497 if (return_data.dptr != NULL)
498 {
499 datum_format (cenv->fp, &return_data, dsdef[DS_CONTENT]);
500 fputc ('\n', cenv->fp);
501 datum_free (&return_data);
502 return GDBMSHELL_OK;
503 }
504 else if (gdbm_errno == GDBM_ITEM_NOT_FOUND)
505 {
506 if (!gdbm_error_is_masked (gdbm_errno))
507 terror ("%s", _("No such item found"));
508 }
509 else
510 dberror ("%s", _("Can't fetch data"));
511 return GDBMSHELL_GDBM_ERR;
512 }
513
514 /* store KEY DATA - store data */
515 static int
store_handler(struct command_param * param,struct command_environ * cenv GDBM_ARG_UNUSED)516 store_handler (struct command_param *param,
517 struct command_environ *cenv GDBM_ARG_UNUSED)
518 {
519 if (gdbm_store (gdbm_file,
520 PARAM_DATUM (param, 0), PARAM_DATUM (param, 1),
521 GDBM_REPLACE) != 0)
522 {
523 dberror ("%s", _("Item not inserted"));
524 return GDBMSHELL_GDBM_ERR;
525 }
526 return GDBMSHELL_OK;
527 }
528
529 /* first - begin iteration */
530
531 static int
firstkey_handler(struct command_param * param,struct command_environ * cenv)532 firstkey_handler (struct command_param *param, struct command_environ *cenv)
533 {
534 datum_free (&key_data);
535 key_data = gdbm_firstkey (gdbm_file);
536 if (key_data.dptr != NULL)
537 {
538 datum_format (cenv->fp, &key_data, dsdef[DS_KEY]);
539 fputc ('\n', cenv->fp);
540
541 return_data = gdbm_fetch (gdbm_file, key_data);
542 datum_format (cenv->fp, &return_data, dsdef[DS_CONTENT]);
543 fputc ('\n', cenv->fp);
544
545 datum_free (&return_data);
546 return GDBMSHELL_OK;
547 }
548 else if (gdbm_errno == GDBM_ITEM_NOT_FOUND)
549 {
550 if (!gdbm_error_is_masked (gdbm_errno))
551 fprintf (cenv->fp, _("No such item found.\n"));
552 }
553 else
554 dberror ("%s", _("Can't find first key"));
555 return GDBMSHELL_GDBM_ERR;
556 }
557
558 /* next [KEY] - next key */
559 static int
nextkey_handler(struct command_param * param,struct command_environ * cenv)560 nextkey_handler (struct command_param *param, struct command_environ *cenv)
561 {
562 if (param->argc == 1)
563 {
564 datum_free (&key_data);
565 key_data.dptr = emalloc (PARAM_DATUM (param, 0).dsize);
566 key_data.dsize = PARAM_DATUM (param, 0).dsize;
567 memcpy (key_data.dptr, PARAM_DATUM (param, 0).dptr, key_data.dsize);
568 }
569 return_data = gdbm_nextkey (gdbm_file, key_data);
570 if (return_data.dptr != NULL)
571 {
572 datum_free (&key_data);
573 key_data = return_data;
574 datum_format (cenv->fp, &key_data, dsdef[DS_KEY]);
575 fputc ('\n', cenv->fp);
576
577 return_data = gdbm_fetch (gdbm_file, key_data);
578 datum_format (cenv->fp, &return_data, dsdef[DS_CONTENT]);
579 fputc ('\n', cenv->fp);
580
581 datum_free (&return_data);
582 return GDBMSHELL_OK;
583 }
584 else if (gdbm_errno == GDBM_ITEM_NOT_FOUND)
585 {
586 if (!gdbm_error_is_masked (gdbm_errno))
587 terror ("%s", _("No such item found"));
588 datum_free (&key_data);
589 }
590 else
591 dberror ("%s", _("Can't find next key"));
592 return GDBMSHELL_GDBM_ERR;
593 }
594
595 /* reorganize */
596 static int
reorganize_handler(struct command_param * param GDBM_ARG_UNUSED,struct command_environ * cenv)597 reorganize_handler (struct command_param *param GDBM_ARG_UNUSED,
598 struct command_environ *cenv)
599 {
600 if (gdbm_reorganize (gdbm_file))
601 {
602 dberror ("%s", _("Reorganization failed"));
603 return GDBMSHELL_GDBM_ERR;
604 }
605 else
606 fprintf (cenv->fp, "%s\n", _("Reorganization succeeded."));
607 return GDBMSHELL_OK;
608 }
609
610 static void
err_printer(void * data GDBM_ARG_UNUSED,char const * fmt,...)611 err_printer (void *data GDBM_ARG_UNUSED, char const *fmt, ...)
612 {
613 va_list ap;
614
615 va_start (ap, fmt);
616 vfprintf (stderr, fmt, ap);
617 va_end (ap);
618 fprintf (stderr, "\n");
619 }
620
621 /* recover sumamry verbose backup max-failed-keys=N max-failed-buckets=N max-failures=N */
622 static int
recover_handler(struct command_param * param,struct command_environ * cenv)623 recover_handler (struct command_param *param, struct command_environ *cenv)
624 {
625 gdbm_recovery rcvr;
626 int flags = 0;
627 int rc;
628 int i;
629 char *p;
630 int summary = 0;
631
632 for (i = 0; i < param->argc; i++)
633 {
634 char *arg = PARAM_STRING (param, i);
635 if (strcmp (arg, "verbose") == 0)
636 {
637 rcvr.errfun = err_printer;
638 flags |= GDBM_RCVR_ERRFUN;
639 }
640 else if (strcmp (arg, "force") == 0)
641 {
642 flags |= GDBM_RCVR_FORCE;
643 }
644 else if (strcmp (arg, "summary") == 0)
645 {
646 summary = 1;
647 }
648 else if (strcmp (arg, "backup") == 0)
649 {
650 flags |= GDBM_RCVR_BACKUP;
651 }
652 else if (strncmp (arg, "max-failures=", 13) == 0)
653 {
654 rcvr.max_failures = strtoul (arg + 13, &p, 10);
655 if (*p)
656 {
657 terror (_("not a number (stopped near %s)"), p);
658 return 1;
659 }
660 flags |= GDBM_RCVR_MAX_FAILURES;
661 }
662 else if (strncmp (arg, "max-failed-keys=", 16) == 0)
663 {
664 rcvr.max_failed_keys = strtoul (arg + 16, &p, 10);
665 if (*p)
666 {
667 terror (_("not a number (stopped near %s)"), p);
668 return 1;
669 }
670 flags |= GDBM_RCVR_MAX_FAILED_KEYS;
671 }
672 else if (strncmp (arg, "max-failed-buckets=", 19) == 0)
673 {
674 rcvr.max_failures = strtoul (arg + 19, &p, 10);
675 if (*p)
676 {
677 terror (_("not a number (stopped near %s)"), p);
678 return 1;
679 }
680 flags |= GDBM_RCVR_MAX_FAILED_BUCKETS;
681 }
682 else
683 {
684 terror (_("unrecognized argument: %s"), arg);
685 return GDBMSHELL_SYNTAX;
686 }
687 }
688
689 rc = gdbm_recover (gdbm_file, &rcvr, flags);
690
691 if (rc == 0)
692 {
693 fprintf (cenv->fp, _("Recovery succeeded.\n"));
694 if (summary)
695 {
696 fprintf (cenv->fp,
697 _("Keys recovered: %lu, failed: %lu, duplicate: %lu\n"),
698 (unsigned long) rcvr.recovered_keys,
699 (unsigned long) rcvr.failed_keys,
700 (unsigned long) rcvr.duplicate_keys);
701 fprintf (cenv->fp,
702 _("Buckets recovered: %lu, failed: %lu\n"),
703 (unsigned long) rcvr.recovered_buckets,
704 (unsigned long) rcvr.failed_buckets);
705 }
706
707 if (rcvr.backup_name)
708 {
709 fprintf (cenv->fp,
710 _("Original database preserved in file %s"),
711 rcvr.backup_name);
712 free (rcvr.backup_name);
713 }
714 fputc ('\n', cenv->fp);
715 }
716 else
717 {
718 dberror ("%s", _("Recovery failed"));
719 rc = GDBMSHELL_GDBM_ERR;
720 }
721 return rc;
722 }
723
724 /* avail - print available list */
725 static int
avail_begin(struct command_param * param GDBM_ARG_UNUSED,struct command_environ * cenv GDBM_ARG_UNUSED,size_t * exp_count)726 avail_begin (struct command_param *param GDBM_ARG_UNUSED,
727 struct command_environ *cenv GDBM_ARG_UNUSED,
728 size_t *exp_count)
729 {
730 int rc = checkdb ();
731 if (rc == GDBMSHELL_OK)
732 {
733 if (exp_count)
734 *exp_count = _gdbm_avail_list_size (gdbm_file, SIZE_T_MAX);
735 }
736 return rc;
737 }
738
739 static int
avail_handler(struct command_param * param GDBM_ARG_UNUSED,struct command_environ * cenv)740 avail_handler (struct command_param *param GDBM_ARG_UNUSED,
741 struct command_environ *cenv)
742 {
743 return _gdbm_print_avail_list (cenv->fp, gdbm_file);
744 }
745
746 /* print current bucket */
747 static int
print_current_bucket_begin(struct command_param * param GDBM_ARG_UNUSED,struct command_environ * cenv GDBM_ARG_UNUSED,size_t * exp_count)748 print_current_bucket_begin (struct command_param *param GDBM_ARG_UNUSED,
749 struct command_environ *cenv GDBM_ARG_UNUSED,
750 size_t *exp_count)
751 {
752 int rc = checkdb ();
753
754 if (rc == GDBMSHELL_OK)
755 {
756 if (exp_count)
757 *exp_count = gdbm_file->bucket
758 ? bucket_print_lines (gdbm_file->bucket) + 3
759 : 1;
760 }
761 return rc;
762 }
763
764 static int
print_current_bucket_handler(struct command_param * param,struct command_environ * cenv)765 print_current_bucket_handler (struct command_param *param,
766 struct command_environ *cenv)
767 {
768 if (!gdbm_file->bucket)
769 fprintf (cenv->fp, _("no current bucket\n"));
770 else
771 {
772 if (param->argc)
773 print_bucket (cenv->fp, gdbm_file->bucket, _("Bucket #%s"),
774 PARAM_STRING (param, 0));
775 else
776 print_bucket (cenv->fp, gdbm_file->bucket, "%s", _("Current bucket"));
777 fprintf (cenv->fp, _("\n current directory entry = %d.\n"),
778 gdbm_file->bucket_dir);
779 fprintf (cenv->fp, _(" current bucket address = %lu.\n"),
780 (unsigned long) gdbm_file->cache_entry->ca_adr);
781 }
782 return GDBMSHELL_OK;
783 }
784
785 int
getnum(int * pnum,char * arg,char ** endp)786 getnum (int *pnum, char *arg, char **endp)
787 {
788 char *p;
789 unsigned long x = strtoul (arg, &p, 10);
790 if (*p && !isspace (*p))
791 {
792 terror (_("not a number (stopped near %s)"), p);
793 return 1;
794 }
795 while (*p && isspace (*p))
796 p++;
797 if (endp)
798 *endp = p;
799 else if (*p)
800 {
801 terror (_("not a number (stopped near %s)"), p);
802 return 1;
803 }
804 *pnum = x;
805 return 0;
806 }
807
808 /* bucket NUM - print a bucket and set it as a current one.
809 Uses print_current_bucket_handler */
810 static int
print_bucket_begin(struct command_param * param,struct command_environ * cenv GDBM_ARG_UNUSED,size_t * exp_count)811 print_bucket_begin (struct command_param *param,
812 struct command_environ *cenv GDBM_ARG_UNUSED,
813 size_t *exp_count)
814 {
815 int rc;
816 int temp;
817
818 if ((rc = checkdb ()) != GDBMSHELL_OK)
819 return rc;
820
821 if (getnum (&temp, PARAM_STRING (param, 0), NULL))
822 return GDBMSHELL_SYNTAX;
823
824 if (temp >= GDBM_DIR_COUNT (gdbm_file))
825 {
826 terror (_("bucket number out of range (0..%lu)"),
827 GDBM_DIR_COUNT (gdbm_file));
828 return GDBMSHELL_SYNTAX;
829 }
830 if (_gdbm_get_bucket (gdbm_file, temp))
831 {
832 dberror (_("%s failed"), "_gdbm_get_bucket");
833 return GDBMSHELL_GDBM_ERR;
834 }
835 if (exp_count)
836 *exp_count = bucket_print_lines (gdbm_file->bucket) + 3;
837 return GDBMSHELL_OK;
838 }
839
840 /* dir - print hash directory */
841 static int
print_dir_begin(struct command_param * param GDBM_ARG_UNUSED,struct command_environ * cenv GDBM_ARG_UNUSED,size_t * exp_count)842 print_dir_begin (struct command_param *param GDBM_ARG_UNUSED,
843 struct command_environ *cenv GDBM_ARG_UNUSED,
844 size_t *exp_count)
845 {
846 int rc;
847
848 if ((rc = checkdb ()) == GDBMSHELL_OK)
849 {
850 if (exp_count)
851 *exp_count = GDBM_DIR_COUNT (gdbm_file) + 3;
852 }
853 return rc;
854 }
855
856 static size_t
bucket_count(void)857 bucket_count (void)
858 {
859 size_t count = 0;
860
861 if (gdbm_bucket_count (gdbm_file, &count))
862 {
863 dberror ("%s", "gdbm_bucket_count");
864 }
865 return count;
866 }
867
868 static int
print_dir_handler(struct command_param * param GDBM_ARG_UNUSED,struct command_environ * cenv)869 print_dir_handler (struct command_param *param GDBM_ARG_UNUSED,
870 struct command_environ *cenv)
871 {
872 int i;
873
874 fprintf (cenv->fp, _("Hash table directory.\n"));
875 fprintf (cenv->fp, _(" Size = %d. Bits = %d, Buckets = %zu.\n\n"),
876 gdbm_file->header->dir_size, gdbm_file->header->dir_bits,
877 bucket_count ());
878
879 for (i = 0; i < GDBM_DIR_COUNT (gdbm_file); i++)
880 fprintf (cenv->fp, " %10d: %12lu\n",
881 i, (unsigned long) gdbm_file->dir[i]);
882
883 return GDBMSHELL_OK;
884 }
885
886 /* header - print file handler */
887 static int
print_header_begin(struct command_param * param GDBM_ARG_UNUSED,struct command_environ * cenv GDBM_ARG_UNUSED,size_t * exp_count)888 print_header_begin (struct command_param *param GDBM_ARG_UNUSED,
889 struct command_environ *cenv GDBM_ARG_UNUSED,
890 size_t *exp_count)
891 {
892 int rc;
893 int n;
894
895 if ((rc = checkdb ()) != GDBMSHELL_OK)
896 return rc;
897
898 switch (gdbm_file->header->header_magic)
899 {
900 case GDBM_OMAGIC:
901 case GDBM_MAGIC:
902 n = 14;
903 break;
904
905 case GDBM_NUMSYNC_MAGIC:
906 n = 19;
907 break;
908
909 default:
910 abort ();
911 }
912
913 if (exp_count)
914 *exp_count = n;
915
916 return GDBMSHELL_OK;
917 }
918
919 static int
print_header_handler(struct command_param * param GDBM_ARG_UNUSED,struct command_environ * cenv)920 print_header_handler (struct command_param *param GDBM_ARG_UNUSED,
921 struct command_environ *cenv)
922 {
923 FILE *fp = cenv->fp;
924 char const *type;
925
926 switch (gdbm_file->header->header_magic)
927 {
928 case GDBM_OMAGIC:
929 type = "GDBM (old)";
930 break;
931
932 case GDBM_MAGIC:
933 type = "GDBM (standard)";
934 break;
935
936 case GDBM_NUMSYNC_MAGIC:
937 type = "GDBM (numsync)";
938 break;
939
940 default:
941 abort ();
942 }
943
944 fprintf (fp, _("\nFile Header: \n\n"));
945 fprintf (fp, _(" type = %s\n"), type);
946 fprintf (fp, _(" table = %lu\n"),
947 (unsigned long) gdbm_file->header->dir);
948 fprintf (fp, _(" table size = %d\n"), gdbm_file->header->dir_size);
949 fprintf (fp, _(" table bits = %d\n"), gdbm_file->header->dir_bits);
950 fprintf (fp, _(" block size = %d\n"), gdbm_file->header->block_size);
951 fprintf (fp, _(" bucket elems = %d\n"), gdbm_file->header->bucket_elems);
952 fprintf (fp, _(" bucket size = %d\n"), gdbm_file->header->bucket_size);
953 fprintf (fp, _(" header magic = %x\n"), gdbm_file->header->header_magic);
954 fprintf (fp, _(" next block = %lu\n"),
955 (unsigned long) gdbm_file->header->next_block);
956
957 fprintf (fp, _(" avail size = %d\n"), gdbm_file->avail->size);
958 fprintf (fp, _(" avail count = %d\n"), gdbm_file->avail->count);
959 fprintf (fp, _(" avail nx blk = %lu\n"),
960 (unsigned long) gdbm_file->avail->next_block);
961
962 if (gdbm_file->xheader)
963 {
964 fprintf (fp, _("\nExtended Header: \n\n"));
965 fprintf (fp, _(" version = %d\n"), gdbm_file->xheader->version);
966 fprintf (fp, _(" numsync = %u\n"), gdbm_file->xheader->numsync);
967 }
968
969 return GDBMSHELL_OK;
970 }
971
972 static int
sync_handler(struct command_param * param GDBM_ARG_UNUSED,struct command_environ * cenv GDBM_ARG_UNUSED)973 sync_handler (struct command_param *param GDBM_ARG_UNUSED,
974 struct command_environ *cenv GDBM_ARG_UNUSED)
975 {
976 if (gdbm_sync (gdbm_file))
977 {
978 dberror ("%s", "gdbm_sync");
979 return GDBMSHELL_GDBM_ERR;
980 }
981 return GDBMSHELL_OK;
982 }
983
984 static int
upgrade_handler(struct command_param * param GDBM_ARG_UNUSED,struct command_environ * cenv GDBM_ARG_UNUSED)985 upgrade_handler (struct command_param *param GDBM_ARG_UNUSED,
986 struct command_environ *cenv GDBM_ARG_UNUSED)
987 {
988 if (gdbm_convert (gdbm_file, GDBM_NUMSYNC))
989 {
990 dberror ("%s", "gdbm_convert");
991 return GDBMSHELL_GDBM_ERR;
992 }
993 return GDBMSHELL_OK;
994 }
995
996 static int
downgrade_handler(struct command_param * param GDBM_ARG_UNUSED,struct command_environ * cenv GDBM_ARG_UNUSED)997 downgrade_handler (struct command_param *param GDBM_ARG_UNUSED,
998 struct command_environ *cenv GDBM_ARG_UNUSED)
999 {
1000 if (gdbm_convert (gdbm_file, 0))
1001 {
1002 dberror ("%s", "gdbm_convert");
1003 return GDBMSHELL_GDBM_ERR;
1004 }
1005 return GDBMSHELL_OK;
1006 }
1007
1008 struct snapshot_status_info
1009 {
1010 char const *code;
1011 char const *descr;
1012 void (*fn) (FILE *, char const *, char const *);
1013 };
1014
1015 #define MODBUFSIZE 10
1016
1017 static char *
decode_mode(mode_t mode,char * buf)1018 decode_mode (mode_t mode, char *buf)
1019 {
1020 char *s = buf;
1021 *s++ = mode & S_IRUSR ? 'r' : '-';
1022 *s++ = mode & S_IWUSR ? 'w' : '-';
1023 *s++ = (mode & S_ISUID
1024 ? (mode & S_IXUSR ? 's' : 'S')
1025 : (mode & S_IXUSR ? 'x' : '-'));
1026 *s++ = mode & S_IRGRP ? 'r' : '-';
1027 *s++ = mode & S_IWGRP ? 'w' : '-';
1028 *s++ = (mode & S_ISGID
1029 ? (mode & S_IXGRP ? 's' : 'S')
1030 : (mode & S_IXGRP ? 'x' : '-'));
1031 *s++ = mode & S_IROTH ? 'r' : '-';
1032 *s++ = mode & S_IWOTH ? 'w' : '-';
1033 *s++ = (mode & S_ISVTX
1034 ? (mode & S_IXOTH ? 't' : 'T')
1035 : (mode & S_IXOTH ? 'x' : '-'));
1036 *s = '\0';
1037 return buf;
1038 }
1039
1040 struct error_entry
1041 {
1042 const char *msg;
1043 int gdbm_err;
1044 int sys_err;
1045 };
1046
1047 static void
error_push(struct error_entry * stk,int * tos,int maxstk,char const * text,int gdbm_err,int sys_err)1048 error_push (struct error_entry *stk, int *tos, int maxstk, char const *text,
1049 int gdbm_err, int sys_err)
1050 {
1051 if (*tos == maxstk)
1052 abort ();
1053 stk += *tos;
1054 ++ *tos;
1055 stk->msg = text;
1056 stk->gdbm_err = gdbm_err;
1057 stk->sys_err = sys_err;
1058 }
1059
1060 static void
print_snapshot(char const * snapname,FILE * fp)1061 print_snapshot (char const *snapname, FILE *fp)
1062 {
1063 struct stat st;
1064 char buf[MODBUFSIZE];
1065
1066 if (stat (snapname, &st) == 0)
1067 {
1068 # define MAXERRS 4
1069 struct error_entry errs[MAXERRS];
1070 int errn = 0;
1071 int i;
1072
1073 switch (st.st_mode & ~S_IFREG)
1074 {
1075 case S_IRUSR:
1076 case S_IWUSR:
1077 break;
1078
1079 default:
1080 error_push (errs, &errn, ARRAY_SIZE (errs), N_("bad file mode"),
1081 0, 0);
1082 }
1083
1084 fprintf (fp, "%s: ", snapname);
1085 fprintf (fp, "%03o %s ", st.st_mode & 0777,
1086 decode_mode (st.st_mode, buf));
1087 #if HAVE_STRUCT_STAT_ST_MTIM
1088 fprintf (fp, "%ld.%09ld", st.st_mtim.tv_sec, st.st_mtim.tv_nsec);
1089 #else
1090 fprintf (fp, "%ld [%s]", st.st_mtime, _("insufficient precision"));
1091 #endif
1092 if (S_ISREG (st.st_mode))
1093 {
1094 GDBM_FILE dbf;
1095
1096 dbf = gdbm_open (snapname, 0, GDBM_READER, 0, NULL);
1097 if (dbf)
1098 {
1099 if (dbf->xheader)
1100 fprintf (fp, " %u", dbf->xheader->numsync);
1101 else
1102 /* TRANSLATORS: Stands for "Not Available". */
1103 fprintf (fp, " %s", _("N/A"));
1104 }
1105 else if (gdbm_check_syserr (gdbm_errno))
1106 {
1107 if (errno == EACCES)
1108 fprintf (fp, " ?");
1109 else
1110 error_push (errs, &errn, ARRAY_SIZE (errs),
1111 N_("can't open database"),
1112 gdbm_errno, errno);
1113 }
1114 else
1115 error_push (errs, &errn, ARRAY_SIZE (errs),
1116 N_("can't open database"),
1117 gdbm_errno, 0);
1118 }
1119 else
1120 error_push (errs, &errn, ARRAY_SIZE (errs),
1121 N_("not a regular file"),
1122 0, 0);
1123 fputc ('\n', fp);
1124 for (i = 0; i < errn; i++)
1125 {
1126 fprintf (fp, "%s: %s: %s", snapname, _("ERROR"), gettext (errs[i].msg));
1127 if (errs[i].gdbm_err)
1128 fprintf (fp, ": %s", gdbm_strerror (errs[i].gdbm_err));
1129 if (errs[i].sys_err)
1130 fprintf (fp, ": %s", strerror (errs[i].sys_err));
1131 fputc ('\n', fp);
1132 }
1133 }
1134 else
1135 {
1136 fprintf (fp, _("%s: ERROR: can't stat: %s"), snapname, strerror (errno));
1137 return;
1138 }
1139 }
1140
1141 static void
snapshot_print_fn(FILE * fp,char const * sa,char const * sb)1142 snapshot_print_fn (FILE *fp, char const *sa, char const *sb)
1143 {
1144 print_snapshot (sa, fp);
1145 print_snapshot (sb, fp);
1146 }
1147
1148 static void
snapshot_err_fn(FILE * fp,char const * sa,char const * sb)1149 snapshot_err_fn (FILE *fp, char const *sa, char const *sb)
1150 {
1151 switch (errno)
1152 {
1153 default:
1154 print_snapshot (sa, fp);
1155 print_snapshot (sb, fp);
1156 break;
1157
1158 case EINVAL:
1159 fprintf (fp, "%s.\n",
1160 _("Invalid arguments in call to gdbm_latest_snapshot"));
1161 break;
1162
1163 case ENOSYS:
1164 fprintf (fp, "%s.\n",
1165 _("Function is not implemented: GDBM is built without crash-tolerance support"));
1166 break;
1167 }
1168 }
1169
1170 static struct snapshot_status_info snapshot_status_info[] = {
1171 [GDBM_SNAPSHOT_OK] = {
1172 "GDBM_SNAPSHOT_OK",
1173 N_("Selected the most recent snapshot")
1174 },
1175 [GDBM_SNAPSHOT_BAD] = {
1176 "GDBM_SNAPSHOT_BAD",
1177 N_("Neither snapshot is readable"),
1178 snapshot_print_fn
1179 },
1180 [GDBM_SNAPSHOT_ERR] = {
1181 "GDBM_SNAPSHOT_ERR",
1182 N_("Error selecting snapshot"),
1183 snapshot_err_fn
1184 },
1185 [GDBM_SNAPSHOT_SAME] = {
1186 "GDBM_SNAPSHOT_SAME",
1187 N_("Snapshot modes and dates are the same"),
1188 snapshot_print_fn
1189 },
1190 [GDBM_SNAPSHOT_SUSPICIOUS] = {
1191 "GDBM_SNAPSHOT_SUSPICIOUS",
1192 N_("Snapshot sync counters differ by more than 1"),
1193 snapshot_print_fn
1194 }
1195 };
1196
1197 static int
snapshot_handler(struct command_param * param,struct command_environ * cenv)1198 snapshot_handler (struct command_param *param, struct command_environ *cenv)
1199 {
1200 char *sa = tildexpand (PARAM_STRING (param, 0));
1201 char *sb = tildexpand (PARAM_STRING (param, 1));
1202 char const *sel;
1203 int rc = gdbm_latest_snapshot (sa, sb, &sel);
1204
1205 if (rc >= 0 && rc < ARRAY_SIZE (snapshot_status_info))
1206 {
1207 fprintf (cenv->fp,
1208 "%s: %s.\n",
1209 snapshot_status_info[rc].code,
1210 gettext (snapshot_status_info[rc].descr));
1211 if (snapshot_status_info[rc].fn)
1212 snapshot_status_info[rc].fn (cenv->fp, sa, sb);
1213 if (rc == GDBM_SNAPSHOT_OK)
1214 print_snapshot (sel, cenv->fp);
1215 }
1216 else
1217 {
1218 terror (_("unexpected error code: %d"), rc);
1219 return GDBMSHELL_ERR;
1220 }
1221 return GDBMSHELL_OK;
1222 }
1223
1224
1225 /* hash KEY - hash the key */
1226 static int
hash_handler(struct command_param * param GDBM_ARG_UNUSED,struct command_environ * cenv)1227 hash_handler (struct command_param *param GDBM_ARG_UNUSED,
1228 struct command_environ *cenv)
1229 {
1230 if (gdbm_file)
1231 {
1232 int hashval, bucket, off;
1233 _gdbm_hash_key (gdbm_file, PARAM_DATUM (param, 0),
1234 &hashval, &bucket, &off);
1235 fprintf (cenv->fp, _("hash value = %x, bucket #%u, slot %u"),
1236 hashval,
1237 hashval >> (GDBM_HASH_BITS - gdbm_file->header->dir_bits),
1238 hashval % gdbm_file->header->bucket_elems);
1239 }
1240 else
1241 fprintf (cenv->fp, _("hash value = %x"),
1242 _gdbm_hash (PARAM_DATUM (param, 0)));
1243 fprintf (cenv->fp, ".\n");
1244 return GDBMSHELL_OK;
1245 }
1246
1247 /* cache - print the bucket cache */
1248 static int
print_cache_begin(struct command_param * param GDBM_ARG_UNUSED,struct command_environ * cenv GDBM_ARG_UNUSED,size_t * exp_count)1249 print_cache_begin (struct command_param *param GDBM_ARG_UNUSED,
1250 struct command_environ *cenv GDBM_ARG_UNUSED,
1251 size_t *exp_count)
1252 {
1253 int rc;
1254
1255 if ((rc = checkdb ()) == GDBMSHELL_OK)
1256 {
1257 if (exp_count)
1258 *exp_count = gdbm_file->cache_num + 1;
1259 }
1260 return rc;
1261 }
1262
1263 static int
print_cache_handler(struct command_param * param GDBM_ARG_UNUSED,struct command_environ * cenv)1264 print_cache_handler (struct command_param *param GDBM_ARG_UNUSED,
1265 struct command_environ *cenv)
1266 {
1267 _gdbm_print_bucket_cache (cenv->fp, gdbm_file);
1268 return GDBMSHELL_OK;
1269 }
1270
1271 /* version - print GDBM version */
1272 static int
print_version_handler(struct command_param * param GDBM_ARG_UNUSED,struct command_environ * cenv)1273 print_version_handler (struct command_param *param GDBM_ARG_UNUSED,
1274 struct command_environ *cenv)
1275 {
1276 fprintf (cenv->fp, "%s\n", gdbm_version);
1277 return GDBMSHELL_OK;
1278 }
1279
1280 /* list - List all entries */
1281 static int
list_begin(struct command_param * param GDBM_ARG_UNUSED,struct command_environ * cenv GDBM_ARG_UNUSED,size_t * exp_count)1282 list_begin (struct command_param *param GDBM_ARG_UNUSED,
1283 struct command_environ *cenv GDBM_ARG_UNUSED,
1284 size_t *exp_count)
1285 {
1286 int rc;
1287
1288 if ((rc = checkdb ()) == GDBMSHELL_OK)
1289 {
1290 if (exp_count)
1291 {
1292 gdbm_count_t count;
1293
1294 if (gdbm_count (gdbm_file, &count))
1295 *exp_count = 0;
1296 else if (count > SIZE_T_MAX)
1297 *exp_count = SIZE_T_MAX;
1298 else
1299 *exp_count = count;
1300 }
1301 }
1302
1303 return rc;
1304 }
1305
1306 static int
list_handler(struct command_param * param GDBM_ARG_UNUSED,struct command_environ * cenv)1307 list_handler (struct command_param *param GDBM_ARG_UNUSED,
1308 struct command_environ *cenv)
1309 {
1310 datum key;
1311 datum data;
1312 int rc = GDBMSHELL_OK;
1313
1314 key = gdbm_firstkey (gdbm_file);
1315 if (!key.dptr && gdbm_errno != GDBM_ITEM_NOT_FOUND)
1316 {
1317 dberror ("%s", "gdbm_firstkey");
1318 return GDBMSHELL_GDBM_ERR;
1319 }
1320 while (key.dptr)
1321 {
1322 datum nextkey;
1323
1324 data = gdbm_fetch (gdbm_file, key);
1325 if (!data.dptr)
1326 {
1327 dberror ("%s", "gdbm_fetch");
1328 terror ("%s", _("the key was:"));
1329 datum_format (stderr, &key, dsdef[DS_KEY]);
1330 rc = GDBMSHELL_GDBM_ERR;
1331 }
1332 else
1333 {
1334 datum_format (cenv->fp, &key, dsdef[DS_KEY]);
1335 fputc (' ', cenv->fp);
1336 datum_format (cenv->fp, &data, dsdef[DS_CONTENT]);
1337 fputc ('\n', cenv->fp);
1338 free (data.dptr);
1339 }
1340 nextkey = gdbm_nextkey (gdbm_file, key);
1341 free (key.dptr);
1342 key = nextkey;
1343 }
1344 if (gdbm_errno != GDBM_ITEM_NOT_FOUND)
1345 {
1346 dberror ("%s", "gdbm_nextkey");
1347 rc = GDBMSHELL_GDBM_ERR;
1348 }
1349 return rc;
1350 }
1351
1352 /* quit - quit the program */
1353 static int
quit_handler(struct command_param * param GDBM_ARG_UNUSED,struct command_environ * cenv GDBM_ARG_UNUSED)1354 quit_handler (struct command_param *param GDBM_ARG_UNUSED,
1355 struct command_environ *cenv GDBM_ARG_UNUSED)
1356 {
1357 input_context_drain ();
1358 if (input_context_push (instream_null_create ()))
1359 exit (EXIT_FATAL);
1360 return GDBMSHELL_OK;
1361 }
1362
1363 /* export FILE [truncate] - export to a flat file format */
1364 static int
export_handler(struct command_param * param,struct command_environ * cenv GDBM_ARG_UNUSED)1365 export_handler (struct command_param *param,
1366 struct command_environ *cenv GDBM_ARG_UNUSED)
1367 {
1368 int format = GDBM_DUMP_FMT_ASCII;
1369 int flags = GDBM_WRCREAT;
1370 int i;
1371 int filemode;
1372 int rc = GDBMSHELL_OK;
1373
1374 for (i = 1; i < param->argc; i++)
1375 {
1376 if (strcmp (PARAM_STRING (param, i), "truncate") == 0)
1377 flags = GDBM_NEWDB;
1378 else if (strcmp (PARAM_STRING (param, i), "binary") == 0)
1379 format = GDBM_DUMP_FMT_BINARY;
1380 else if (strcmp (PARAM_STRING (param, i), "ascii") == 0)
1381 format = GDBM_DUMP_FMT_ASCII;
1382 else
1383 {
1384 terror (_("unrecognized argument: %s"), PARAM_STRING (param, i));
1385 return GDBMSHELL_SYNTAX;
1386 }
1387 }
1388
1389 if (variable_get ("filemode", VART_INT, (void**) &filemode))
1390 abort ();
1391 if (gdbm_dump (gdbm_file, PARAM_STRING (param, 0), format, flags, filemode))
1392 {
1393 dberror ("%s", _("error dumping database"));
1394 rc = GDBMSHELL_GDBM_ERR;
1395 }
1396 return rc;
1397 }
1398
1399 /* import FILE [replace] [nometa] - import from a flat file */
1400 static int
import_handler(struct command_param * param,struct command_environ * cenv GDBM_ARG_UNUSED)1401 import_handler (struct command_param *param,
1402 struct command_environ *cenv GDBM_ARG_UNUSED)
1403 {
1404 int flag = GDBM_INSERT;
1405 unsigned long err_line;
1406 int meta_mask = 0;
1407 int i;
1408 int rc = GDBMSHELL_OK;
1409 char *file_name;
1410
1411 for (i = 0; i < param->argc; i++)
1412 {
1413 if (strcmp (PARAM_STRING (param, i), "replace") == 0)
1414 flag = GDBM_REPLACE;
1415 else if (strcmp (PARAM_STRING (param, i), "nometa") == 0)
1416 meta_mask = GDBM_META_MASK_MODE | GDBM_META_MASK_OWNER;
1417 else
1418 {
1419 terror (_("unrecognized argument: %s"),
1420 PARAM_STRING (param, i));
1421 return GDBMSHELL_SYNTAX;
1422 }
1423 }
1424
1425 rc = gdbm_load (&gdbm_file, PARAM_STRING (param, 0), flag,
1426 meta_mask, &err_line);
1427 if (rc && gdbm_errno == GDBM_NO_DBNAME)
1428 {
1429 char *save_mode;
1430
1431 variable_get ("open", VART_STRING, (void**) &save_mode);
1432 save_mode = estrdup (save_mode);
1433 variable_set ("open", VART_STRING, "newdb");
1434
1435 rc = checkdb ();
1436 variable_set ("open", VART_STRING, save_mode);
1437 free (save_mode);
1438
1439 if (rc)
1440 return rc;
1441
1442 rc = gdbm_load (&gdbm_file, PARAM_STRING (param, 0), flag,
1443 meta_mask, &err_line);
1444 }
1445 if (rc)
1446 {
1447 switch (gdbm_errno)
1448 {
1449 case GDBM_ERR_FILE_OWNER:
1450 case GDBM_ERR_FILE_MODE:
1451 dberror ("%s", _("error restoring metadata"));
1452 break;
1453
1454 default:
1455 if (err_line)
1456 dberror ("%s:%lu", PARAM_STRING (param, 0), err_line);
1457 else
1458 dberror (_("cannot load from %s"), PARAM_STRING (param, 0));
1459 }
1460 return GDBMSHELL_GDBM_ERR;
1461 }
1462
1463 free (file_name);
1464 if (gdbm_setopt (gdbm_file, GDBM_GETDBNAME, &file_name, sizeof (file_name)))
1465 {
1466 dberror ("%s", "GDBM_GETDBNAME");
1467 rc = GDBMSHELL_GDBM_ERR;
1468 }
1469 else
1470 {
1471 variable_set ("filename", VART_STRING, file_name);
1472 variable_unset ("fd");
1473 }
1474 return rc;
1475 }
1476
1477 /* status - print current program status */
1478 static int
status_handler(struct command_param * param GDBM_ARG_UNUSED,struct command_environ * cenv)1479 status_handler (struct command_param *param GDBM_ARG_UNUSED,
1480 struct command_environ *cenv)
1481 {
1482 char *file_name;
1483
1484 variable_get ("filename", VART_STRING, (void**) &file_name);
1485 fprintf (cenv->fp, _("Database file: %s\n"), file_name);
1486 if (gdbm_file)
1487 fprintf (cenv->fp, "%s\n", _("Database is open"));
1488 else
1489 fprintf (cenv->fp, "%s\n", _("Database is not open"));
1490 dsprint (cenv->fp, DS_KEY, dsdef[DS_KEY]);
1491 dsprint (cenv->fp, DS_CONTENT, dsdef[DS_CONTENT]);
1492 return GDBMSHELL_OK;
1493 }
1494
1495 #if GDBM_DEBUG_ENABLE
1496 static int
debug_flag_printer(void * data,int flag,char const * tok)1497 debug_flag_printer (void *data, int flag, char const *tok)
1498 {
1499 FILE *fp = data;
1500 fprintf (fp, " %s", tok);
1501 return 0;
1502 }
1503 #endif
1504
1505 static int
debug_handler(struct command_param * param,struct command_environ * cenv)1506 debug_handler (struct command_param *param, struct command_environ *cenv)
1507 {
1508 #if GDBM_DEBUG_ENABLE
1509 if (param->vararg)
1510 {
1511 struct gdbmarg *arg;
1512 int i;
1513
1514 for (arg = param->vararg, i = 0; arg; arg = arg->next, i++)
1515 {
1516 if (arg->type == GDBM_ARG_STRING)
1517 {
1518 int flag;
1519 int negate;
1520 char const *tok = arg->v.string;
1521
1522 if (tok[0] == '-')
1523 {
1524 ++tok;
1525 negate = 1;
1526 }
1527 else if (tok[0] == '+')
1528 {
1529 ++tok;
1530 negate = 0;
1531 }
1532 else
1533 negate = 0;
1534
1535 flag = gdbm_debug_token (tok);
1536 if (flag)
1537 {
1538 if (negate)
1539 gdbm_debug_flags &= ~flag;
1540 else
1541 gdbm_debug_flags |= flag;
1542 }
1543 else
1544 terror (_("unknown debug flag: %s"), tok);
1545 }
1546 else
1547 terror (_("invalid type of argument %d"), i);
1548 }
1549 }
1550 else
1551 {
1552 fprintf (cenv->fp, _("Debug flags:"));
1553 if (gdbm_debug_flags)
1554 {
1555 gdbm_debug_parse_state (debug_flag_printer, cenv->fp);
1556 }
1557 else
1558 fprintf (cenv->fp, " %s", _("none"));
1559 fputc ('\n', cenv->fp);
1560 }
1561 #else
1562 terror ("%s", _("compiled without debug support"));
1563 #endif
1564 return GDBMSHELL_OK;
1565 }
1566
1567 static int
shell_handler(struct command_param * param,struct command_environ * cenv GDBM_ARG_UNUSED)1568 shell_handler (struct command_param *param,
1569 struct command_environ *cenv GDBM_ARG_UNUSED)
1570 {
1571 char *argv[4];
1572 pid_t pid, rc;
1573 int status;
1574
1575 argv[0] = getenv ("$SHELL");
1576 if (!argv[0])
1577 argv[0] = "/bin/sh";
1578 if (param->vararg)
1579 {
1580 argv[1] = "-c";
1581 argv[2] = param->vararg->v.string;
1582 argv[3] = NULL;
1583 }
1584 else
1585 {
1586 argv[1] = NULL;
1587 }
1588
1589 pid = fork ();
1590 if (pid == -1)
1591 {
1592 terror ("fork: %s", strerror (errno));
1593 return GDBMSHELL_ERR;
1594 }
1595 if (pid == 0)
1596 {
1597 execv (argv[0], argv);
1598 _exit (127);
1599 }
1600
1601 rc = waitpid (pid, &status, 0);
1602 if (rc == -1)
1603 {
1604 terror ("waitpid: %s", strerror (errno));
1605 rc = GDBMSHELL_ERR;
1606 }
1607 else if (!interactive ())
1608 {
1609 if (WIFEXITED (status))
1610 {
1611 if (WEXITSTATUS (status) != 0)
1612 terror (_("command failed with status %d"), WEXITSTATUS (status));
1613 }
1614 else if (WIFSIGNALED (status))
1615 terror (_("command terminated on signal %d"), WTERMSIG (status));
1616 }
1617 return rc;
1618 }
1619
1620 static int
source_handler(struct command_param * param,struct command_environ * cenv GDBM_ARG_UNUSED)1621 source_handler (struct command_param *param,
1622 struct command_environ *cenv GDBM_ARG_UNUSED)
1623 {
1624 char *fname = tildexpand (PARAM_STRING (param, 0));
1625 instream_t istr = instream_file_create (fname);
1626 free (fname);
1627 if (istr && input_context_push (istr) == 0)
1628 {
1629 yyparse ();
1630 input_context_drain ();
1631 yylex_destroy ();
1632 }
1633 return GDBMSHELL_OK;
1634 }
1635
1636 static int
perror_handler(struct command_param * param,struct command_environ * cenv)1637 perror_handler (struct command_param *param, struct command_environ *cenv)
1638 {
1639 int n;
1640
1641 if (param->argc)
1642 {
1643 if (getnum (&n, PARAM_STRING (param, 0), NULL))
1644 return GDBMSHELL_SYNTAX;
1645 }
1646 else if ((n = checkdb ()) != GDBMSHELL_OK)
1647 {
1648 return n;
1649 }
1650 else
1651 {
1652 n = gdbm_last_errno (gdbm_file);
1653 }
1654 fprintf (cenv->fp, "GDBM error code %d: \"%s\"\n", n, gdbm_strerror (n));
1655 if (gdbm_check_syserr (n))
1656 {
1657 if (param->argc)
1658 fprintf (cenv->fp, "Examine errno.\n");
1659 else
1660 fprintf (cenv->fp, "System error code %d: \"%s\"\n",
1661 gdbm_last_syserr (gdbm_file),
1662 strerror (gdbm_last_syserr (gdbm_file)));
1663 }
1664 return GDBMSHELL_OK;
1665 }
1666
1667 struct history_param
1668 {
1669 int from;
1670 int count;
1671 };
1672
1673 static int
input_history_begin(struct command_param * param,struct command_environ * cenv GDBM_ARG_UNUSED,size_t * exp_count)1674 input_history_begin (struct command_param *param,
1675 struct command_environ *cenv GDBM_ARG_UNUSED,
1676 size_t *exp_count)
1677 {
1678 struct history_param *p;
1679 int hlen = input_history_size ();
1680 int from = 0, count = hlen;
1681
1682 if (hlen == -1)
1683 {
1684 /* TRANSLATORS: %s is the stream name */
1685 terror (_("input history is not available for %s input stream"),
1686 input_stream_name ());
1687 return GDBMSHELL_OK;
1688 }
1689
1690 switch (param->argc)
1691 {
1692 case 1:
1693 if (getnum (&count, param->argv[0]->v.string, NULL))
1694 return 1;
1695 if (count > hlen)
1696 count = hlen;
1697 else
1698 from = hlen - count;
1699 break;
1700
1701 case 2:
1702 if (getnum (&from, param->argv[0]->v.string, NULL))
1703 return 1;
1704 if (from)
1705 --from;
1706 if (getnum (&count, param->argv[1]->v.string, NULL))
1707 return GDBMSHELL_OK;
1708
1709 if (count > hlen)
1710 count = hlen;
1711 }
1712 p = emalloc (sizeof *p);
1713 p->from = from;
1714 p->count = count;
1715 cenv->data = p;
1716 if (exp_count)
1717 *exp_count = count;
1718 return GDBMSHELL_OK;
1719 }
1720
1721 static int
input_history_handler(struct command_param * param GDBM_ARG_UNUSED,struct command_environ * cenv)1722 input_history_handler (struct command_param *param GDBM_ARG_UNUSED,
1723 struct command_environ *cenv)
1724 {
1725 struct history_param *p = cenv->data;
1726 int i;
1727 FILE *fp = cenv->fp;
1728
1729 for (i = 0; i < p->count; i++)
1730 {
1731 const char *s = input_history_get (p->from + i);
1732 if (!s)
1733 break;
1734 fprintf (fp, "%4d) %s\n", p->from + i + 1, s);
1735 }
1736 return GDBMSHELL_OK;
1737 }
1738
1739
1740 static int help_handler (struct command_param *, struct command_environ *);
1741 static int help_begin (struct command_param *, struct command_environ *,
1742 size_t *);
1743
1744 struct argdef
1745 {
1746 char *name;
1747 int type;
1748 int ds;
1749 };
1750
1751 #define NARGS 10
1752
1753 enum command_repeat_type
1754 {
1755 REPEAT_NEVER,
1756 REPEAT_ALWAYS,
1757 REPEAT_NOARG
1758 };
1759
1760 struct command
1761 {
1762 char *name; /* Command name */
1763 size_t len; /* Name length */
1764 int tok;
1765 int (*begin) (struct command_param *param, struct command_environ *cenv, size_t *);
1766 int (*handler) (struct command_param *param, struct command_environ *cenv);
1767 void (*end) (void *data);
1768 struct argdef args[NARGS];
1769 int variadic;
1770 enum command_repeat_type repeat;
1771 char *doc;
1772 };
1773
1774 static struct command command_tab[] = {
1775 {
1776 .name = "count",
1777 .doc = N_("count (number of entries)"),
1778 .tok = T_CMD,
1779 .begin = checkdb_begin,
1780 .handler = count_handler,
1781 .variadic = FALSE,
1782 .repeat = REPEAT_NEVER,
1783 },
1784 {
1785 .name = "delete",
1786 .args = {
1787 { N_("KEY"), GDBM_ARG_DATUM, DS_KEY },
1788 { NULL }
1789 },
1790 .doc = N_("delete a record"),
1791 .tok = T_CMD,
1792 .begin = checkdb_begin,
1793 .handler = delete_handler,
1794 .variadic = FALSE,
1795 .repeat = REPEAT_NEVER,
1796 },
1797 {
1798 .name = "export",
1799 .args = {
1800 { N_("FILE"), GDBM_ARG_STRING },
1801 { "[truncate]", GDBM_ARG_STRING },
1802 { "[binary|ascii]", GDBM_ARG_STRING },
1803 { NULL }
1804 },
1805 .doc = N_("export"),
1806 .tok = T_CMD,
1807 .begin = checkdb_begin,
1808 .handler = export_handler,
1809 .variadic = FALSE,
1810 .repeat = REPEAT_NEVER,
1811 },
1812 {
1813 .name = "fetch",
1814 .args = {
1815 { N_("KEY"), GDBM_ARG_DATUM, DS_KEY },
1816 { NULL }
1817 },
1818 .doc = N_("fetch record"),
1819 .tok = T_CMD,
1820 .begin = checkdb_begin,
1821 .handler = fetch_handler,
1822 .variadic = FALSE,
1823 .repeat = REPEAT_NEVER,
1824 },
1825 {
1826 .name = "import",
1827 .args = {
1828 { N_("FILE"), GDBM_ARG_STRING },
1829 { "[replace]", GDBM_ARG_STRING },
1830 { "[nometa]" , GDBM_ARG_STRING },
1831 { NULL }
1832 },
1833 .doc = N_("import"),
1834 .tok = T_CMD,
1835 .handler = import_handler,
1836 .variadic = FALSE,
1837 .repeat = REPEAT_NEVER,
1838 },
1839 {
1840 .name = "list",
1841 .doc = N_("list"),
1842 .tok = T_CMD,
1843 .begin = list_begin,
1844 .handler = list_handler,
1845 .variadic = FALSE,
1846 .repeat = REPEAT_NEVER,
1847 },
1848 {
1849 .name = "next",
1850 .args = {
1851 { N_("[KEY]"), GDBM_ARG_DATUM, DS_KEY },
1852 { NULL }
1853 },
1854 .doc = N_("continue iteration: get next key and datum"),
1855 .tok = T_CMD,
1856 .begin = checkdb_begin,
1857 .handler = nextkey_handler,
1858 .variadic = FALSE,
1859 .repeat = REPEAT_NOARG,
1860 },
1861 {
1862 .name = "store",
1863 .args = {
1864 { N_("KEY"), GDBM_ARG_DATUM, DS_KEY },
1865 { N_("DATA"), GDBM_ARG_DATUM, DS_CONTENT },
1866 { NULL }
1867 },
1868 .doc = N_("store"),
1869 .tok = T_CMD,
1870 .begin = checkdb_begin,
1871 .handler = store_handler,
1872 .variadic = FALSE,
1873 .repeat = REPEAT_NEVER,
1874 },
1875 {
1876 .name = "first",
1877 .doc = N_("begin iteration: get first key and datum"),
1878 .tok = T_CMD,
1879 .begin = checkdb_begin,
1880 .handler = firstkey_handler,
1881 .variadic = FALSE,
1882 .repeat = REPEAT_NEVER,
1883 },
1884 {
1885 .name = "reorganize",
1886 .doc = N_("reorganize"),
1887 .tok = T_CMD,
1888 .begin = checkdb_begin,
1889 .handler = reorganize_handler,
1890 .variadic = FALSE,
1891 .repeat = REPEAT_NEVER,
1892 },
1893 {
1894 .name = "recover",
1895 .args = {
1896 { "[verbose]", GDBM_ARG_STRING },
1897 { "[summary]", GDBM_ARG_STRING },
1898 { "[backup]", GDBM_ARG_STRING },
1899 { "[force]", GDBM_ARG_STRING },
1900 { "[max-failed-keys=N]", GDBM_ARG_STRING },
1901 { "[max-failed-buckets=N]", GDBM_ARG_STRING },
1902 { "[max-failures=N]", GDBM_ARG_STRING },
1903 { NULL }
1904 },
1905 .doc = N_("recover the database"),
1906 .tok = T_CMD,
1907 .begin = checkdb_begin,
1908 .handler = recover_handler,
1909 .variadic = FALSE,
1910 .repeat = REPEAT_NEVER,
1911 },
1912 {
1913 .name = "avail",
1914 .doc = N_("print avail list"),
1915 .tok = T_CMD,
1916 .begin = avail_begin,
1917 .handler = avail_handler,
1918 .variadic = FALSE,
1919 .repeat = REPEAT_NEVER,
1920 },
1921 {
1922 .name = "bucket",
1923 .args = {
1924 { N_("NUMBER"), GDBM_ARG_STRING },
1925 { NULL }
1926 },
1927 .doc = N_("print a bucket"),
1928 .tok = T_CMD,
1929 .begin = print_bucket_begin,
1930 .handler = print_current_bucket_handler,
1931 .variadic = FALSE,
1932 .repeat = REPEAT_NEVER,
1933 },
1934 {
1935 .name = "current",
1936 .doc = N_("print current bucket"),
1937 .tok = T_CMD,
1938 .begin = print_current_bucket_begin,
1939 .handler = print_current_bucket_handler,
1940 .variadic = FALSE,
1941 .repeat = REPEAT_NEVER,
1942 },
1943 {
1944 .name = "dir",
1945 .doc = N_("print hash directory"),
1946 .tok = T_CMD,
1947 .begin = print_dir_begin,
1948 .handler = print_dir_handler,
1949 .variadic = FALSE,
1950 .repeat = REPEAT_NEVER,
1951 },
1952 {
1953 .name = "header",
1954 .doc = N_("print database file header"),
1955 .tok = T_CMD,
1956 .begin = print_header_begin,
1957 .handler = print_header_handler,
1958 .variadic = FALSE,
1959 .repeat = REPEAT_NEVER,
1960 },
1961 {
1962 .name = "hash",
1963 .args = {
1964 { N_("KEY"), GDBM_ARG_DATUM, DS_KEY },
1965 { NULL }
1966 },
1967 .doc = N_("hash value of key"),
1968 .tok = T_CMD,
1969 .handler = hash_handler,
1970 .variadic = FALSE,
1971 .repeat = REPEAT_NEVER,
1972 },
1973 {
1974 .name = "cache",
1975 .doc = N_("print the bucket cache"),
1976 .tok = T_CMD,
1977 .begin = print_cache_begin,
1978 .handler = print_cache_handler,
1979 .variadic = FALSE,
1980 .repeat = REPEAT_NEVER,
1981 },
1982 {
1983 .name = "status",
1984 .doc = N_("print current program status"),
1985 .tok = T_CMD,
1986 .handler = status_handler,
1987 .variadic = FALSE,
1988 .repeat = REPEAT_NEVER,
1989 },
1990 {
1991 .name = "sync",
1992 .doc = N_("Synchronize the database with disk copy"),
1993 .tok = T_CMD,
1994 .begin = checkdb_begin,
1995 .handler = sync_handler,
1996 .variadic = FALSE,
1997 .repeat = REPEAT_NEVER,
1998 },
1999 {
2000 .name = "upgrade",
2001 .doc = N_("Upgrade the database to extended format"),
2002 .tok = T_CMD,
2003 .begin = checkdb_begin,
2004 .handler = upgrade_handler,
2005 .variadic = FALSE,
2006 .repeat = REPEAT_NEVER,
2007 },
2008 {
2009 .name = "downgrade",
2010 .doc = N_("Downgrade the database to standard format"),
2011 .tok = T_CMD,
2012 .begin = checkdb_begin,
2013 .handler = downgrade_handler,
2014 .variadic = FALSE,
2015 .repeat = REPEAT_NEVER,
2016 },
2017 {
2018 .name = "snapshot",
2019 .args = {
2020 { "FILE", GDBM_ARG_STRING },
2021 { "FILE", GDBM_ARG_STRING },
2022 { NULL }
2023 },
2024 .doc = N_("analyze two database snapshots"),
2025 .tok = T_CMD,
2026 .handler = snapshot_handler,
2027 .variadic = FALSE,
2028 .repeat = REPEAT_NEVER,
2029 },
2030 {
2031 .name = "version",
2032 .doc = N_("print version of gdbm"),
2033 .tok = T_CMD,
2034 .handler = print_version_handler,
2035 .variadic = FALSE,
2036 .repeat = REPEAT_NEVER,
2037 },
2038 {
2039 .name = "help",
2040 .doc = N_("print this help list"),
2041 .tok = T_CMD,
2042 .begin = help_begin,
2043 .handler = help_handler,
2044 .variadic = FALSE,
2045 .repeat = REPEAT_NEVER,
2046 },
2047 {
2048 .name = "quit",
2049 .doc = N_("quit the program"),
2050 .tok = T_CMD,
2051 .handler = quit_handler,
2052 .variadic = FALSE,
2053 .repeat = REPEAT_NEVER,
2054 },
2055 {
2056 .name = "set",
2057 .args = {
2058 { "[VAR=VALUE...]" },
2059 { NULL }
2060 },
2061 .doc = N_("set or list variables"),
2062 .tok = T_SET,
2063 .variadic = FALSE,
2064 .repeat = REPEAT_NEVER,
2065 },
2066 {
2067 .name = "unset",
2068 .args = {
2069 { "VAR..." },
2070 { NULL }
2071 },
2072 .doc = N_("unset variables"),
2073 .tok = T_UNSET,
2074 .variadic = FALSE,
2075 .repeat = REPEAT_NEVER,
2076 },
2077 {
2078 .name = "define",
2079 .args = {
2080 { "key|content", GDBM_ARG_STRING },
2081 { "{ FIELD-LIST }", GDBM_ARG_STRING },
2082 { NULL }
2083 },
2084 .doc = N_("define datum structure"),
2085 .tok = T_DEF,
2086 .variadic = FALSE,
2087 .repeat = REPEAT_NEVER,
2088 },
2089 {
2090 .name = "source",
2091 .args = {
2092 { "FILE", GDBM_ARG_STRING },
2093 { NULL }
2094 },
2095 .doc = N_("source command script"),
2096 .tok = T_CMD,
2097 .handler = source_handler,
2098 .variadic = FALSE,
2099 .repeat = REPEAT_NEVER,
2100 },
2101 {
2102 .name = "close",
2103 .doc = N_("close the database"),
2104 .tok = T_CMD,
2105 .handler = close_handler,
2106 .variadic = FALSE,
2107 .repeat = REPEAT_NEVER,
2108 },
2109 {
2110 .name = "open",
2111 .args = {
2112 { "[FILE]", GDBM_ARG_STRING },
2113 { NULL }
2114 },
2115 .doc = N_("open new database"),
2116 .tok = T_CMD,
2117 .handler = open_handler,
2118 .variadic = FALSE,
2119 .repeat = REPEAT_NEVER,
2120 },
2121 {
2122 .name = "history",
2123 .args = {
2124 { N_("[FROM]"), GDBM_ARG_STRING },
2125 { N_("[COUNT]"), GDBM_ARG_STRING },
2126 { NULL }
2127 },
2128 .doc = N_("show input history"),
2129 .tok = T_CMD,
2130 .begin = input_history_begin,
2131 .handler = input_history_handler,
2132 .variadic = FALSE,
2133 .repeat = REPEAT_NEVER,
2134 },
2135 {
2136 .name = "debug",
2137 .doc = N_("query/set debug level"),
2138 .tok = T_CMD,
2139 .handler = debug_handler,
2140 .variadic = TRUE,
2141 .repeat = REPEAT_NEVER,
2142 },
2143 {
2144 .name = "shell",
2145 .doc = N_("invoke the shell"),
2146 .tok = T_SHELL,
2147 .handler = shell_handler,
2148 .variadic = TRUE,
2149 .repeat = REPEAT_NEVER,
2150 },
2151 {
2152 .name = "perror",
2153 .args = {
2154 { "[CODE]", GDBM_ARG_STRING },
2155 { NULL }
2156 },
2157 .doc = N_("describe GDBM error code"),
2158 .tok = T_CMD,
2159 .handler = perror_handler,
2160 .variadic = FALSE,
2161 .repeat = REPEAT_NEVER,
2162 },
2163 { NULL }
2164 };
2165
2166 static int commands_sorted;
2167
2168 static int
cmdcmp(const void * a,const void * b)2169 cmdcmp (const void *a, const void *b)
2170 {
2171 struct command const *ac = a;
2172 struct command const *bc = b;
2173 return strcmp (ac->name, bc->name);
2174 }
2175
2176 /* Generator function for command completion. STATE lets us know whether
2177 to start from scratch; without any state (i.e. STATE == 0), then we
2178 start at the top of the list. */
2179 char *
command_generator(const char * text,int state)2180 command_generator (const char *text, int state)
2181 {
2182 const char *name;
2183 static int len;
2184 static struct command *cmd;
2185
2186 /* If this is a new word to complete, initialize now. This includes
2187 saving the length of TEXT for efficiency, and initializing the index
2188 variable to 0. */
2189 if (!state)
2190 {
2191 cmd = command_tab;
2192 len = strlen (text);
2193 }
2194
2195 if (!cmd || !cmd->name)
2196 return NULL;
2197
2198 /* Return the next name which partially matches from the command list. */
2199 while ((name = cmd->name))
2200 {
2201 cmd++;
2202 if (strncmp (name, text, len) == 0)
2203 return strdup (name);
2204 }
2205
2206 /* If no names matched, then return NULL. */
2207 return NULL;
2208 }
2209
2210 /* ? - help handler */
2211 #define CMDCOLS 30
2212
2213 static int
help_begin(struct command_param * param GDBM_ARG_UNUSED,struct command_environ * cenv GDBM_ARG_UNUSED,size_t * exp_count)2214 help_begin (struct command_param *param GDBM_ARG_UNUSED,
2215 struct command_environ *cenv GDBM_ARG_UNUSED,
2216 size_t *exp_count)
2217 {
2218 if (exp_count)
2219 *exp_count = ARRAY_SIZE (command_tab) + 1;
2220 return 0;
2221 }
2222
2223 static int
help_handler(struct command_param * param GDBM_ARG_UNUSED,struct command_environ * cenv)2224 help_handler (struct command_param *param GDBM_ARG_UNUSED,
2225 struct command_environ *cenv)
2226 {
2227 struct command *cmd;
2228 FILE *fp = cenv->fp;
2229
2230 for (cmd = command_tab; cmd->name; cmd++)
2231 {
2232 int i;
2233 int n;
2234 int optoff;
2235
2236 n = fprintf (fp, " %s", cmd->name);
2237 optoff = n;
2238
2239 for (i = 0; i < NARGS && cmd->args[i].name; i++)
2240 {
2241 if (n >= CMDCOLS)
2242 {
2243 fputc ('\n', fp);
2244 n = fprintf (fp, "%*.*s", optoff, optoff, "");
2245 }
2246 n += fprintf (fp, " %s", gettext (cmd->args[i].name));
2247 }
2248
2249 if (n < CMDCOLS)
2250 fprintf (fp, "%*.s", CMDCOLS-n, "");
2251 else
2252 fprintf (fp, "\n%*.*s", CMDCOLS, CMDCOLS, "");
2253 fprintf (fp, " %s", gettext (cmd->doc));
2254 fputc ('\n', fp);
2255 }
2256 return 0;
2257 }
2258
2259 int
command_lookup(const char * str,struct locus * loc,struct command ** pcmd)2260 command_lookup (const char *str, struct locus *loc, struct command **pcmd)
2261 {
2262 enum { fcom_init, fcom_found, fcom_ambig, fcom_abort } state = fcom_init;
2263 struct command *cmd, *found = NULL;
2264 size_t len = strlen (str);
2265
2266 for (cmd = command_tab; state != fcom_abort && cmd->name; cmd++)
2267 {
2268 size_t n = len < cmd->len ? len : cmd->len;
2269 if (memcmp (cmd->name, str, n) == 0 && str[n] == 0)
2270 {
2271 switch (state)
2272 {
2273 case fcom_init:
2274 found = cmd;
2275 state = fcom_found;
2276 break;
2277
2278 case fcom_found:
2279 if (!interactive ())
2280 {
2281 state = fcom_abort;
2282 found = NULL;
2283 continue;
2284 }
2285 fprintf (stderr, "ambiguous command: %s\n", str);
2286 fprintf (stderr, " %s\n", found->name);
2287 found = NULL;
2288 state = fcom_ambig;
2289 /* fall through */
2290 case fcom_ambig:
2291 fprintf (stderr, " %s\n", cmd->name);
2292 break;
2293
2294 case fcom_abort:
2295 /* should not happen */
2296 abort ();
2297 }
2298 }
2299 }
2300
2301 if (state == fcom_init)
2302 lerror (loc, interactive () ? _("Invalid command. Try ? for help.") :
2303 _("Unknown command"));
2304 if (!found)
2305 return T_BOGUS;
2306
2307 *pcmd = found;
2308 return found->tok;
2309 }
2310
2311 struct gdbmarg *
gdbmarg_string(char * string,struct locus * loc)2312 gdbmarg_string (char *string, struct locus *loc)
2313 {
2314 struct gdbmarg *arg = ecalloc (1, sizeof (*arg));
2315 arg->next = NULL;
2316 arg->type = GDBM_ARG_STRING;
2317 arg->ref = 1;
2318 if (loc)
2319 arg->loc = *loc;
2320 arg->v.string = string;
2321 return arg;
2322 }
2323
2324 struct gdbmarg *
gdbmarg_datum(datum * dat,struct locus * loc)2325 gdbmarg_datum (datum *dat, struct locus *loc)
2326 {
2327 struct gdbmarg *arg = ecalloc (1, sizeof (*arg));
2328 arg->next = NULL;
2329 arg->type = GDBM_ARG_DATUM;
2330 arg->ref = 1;
2331 if (loc)
2332 arg->loc = *loc;
2333 arg->v.dat = *dat;
2334 return arg;
2335 }
2336
2337 struct gdbmarg *
gdbmarg_kvpair(struct kvpair * kvp,struct locus * loc)2338 gdbmarg_kvpair (struct kvpair *kvp, struct locus *loc)
2339 {
2340 struct gdbmarg *arg = ecalloc (1, sizeof (*arg));
2341 arg->next = NULL;
2342 arg->type = GDBM_ARG_KVPAIR;
2343 arg->ref = 1;
2344 if (loc)
2345 arg->loc = *loc;
2346 arg->v.kvpair = kvp;
2347 return arg;
2348 }
2349
2350 struct slist *
slist_new_s(char * s)2351 slist_new_s (char *s)
2352 {
2353 struct slist *lp = emalloc (sizeof (*lp));
2354 lp->next = NULL;
2355 lp->str = s;
2356 return lp;
2357 }
2358
2359 struct slist *
slist_new(char const * s)2360 slist_new (char const *s)
2361 {
2362 return slist_new_s (estrdup (s));
2363 }
2364
2365 struct slist *
slist_new_l(char const * s,size_t l)2366 slist_new_l (char const *s, size_t l)
2367 {
2368 char *copy = emalloc (l + 1);
2369 memcpy (copy, s, l);
2370 copy[l] = 0;
2371 return slist_new_s (copy);
2372 }
2373
2374 void
slist_free(struct slist * lp)2375 slist_free (struct slist *lp)
2376 {
2377 while (lp)
2378 {
2379 struct slist *next = lp->next;
2380 free (lp->str);
2381 free (lp);
2382 lp = next;
2383 }
2384 }
2385
2386 void
slist_insert(struct slist ** where,struct slist * what)2387 slist_insert (struct slist **where, struct slist *what)
2388 {
2389 if (*where)
2390 {
2391 while (what->next)
2392 what = what->next;
2393 what->next = (*where)->next;
2394 (*where)->next = what;
2395 }
2396 else
2397 what->next = NULL;
2398 *where = what;
2399 }
2400
2401 struct kvpair *
kvpair_string(struct locus * loc,char * val)2402 kvpair_string (struct locus *loc, char *val)
2403 {
2404 struct kvpair *p = ecalloc (1, sizeof (*p));
2405 p->type = KV_STRING;
2406 if (loc)
2407 p->loc = *loc;
2408 p->val.s = val;
2409 return p;
2410 }
2411
2412 struct kvpair *
kvpair_list(struct locus * loc,struct slist * s)2413 kvpair_list (struct locus *loc, struct slist *s)
2414 {
2415 struct kvpair *p = ecalloc (1, sizeof (*p));
2416 p->type = KV_LIST;
2417 if (loc)
2418 p->loc = *loc;
2419 p->val.l = s;
2420 return p;
2421 }
2422
2423 void
kvlist_free(struct kvpair * kvp)2424 kvlist_free (struct kvpair *kvp)
2425 {
2426 while (kvp)
2427 {
2428 struct kvpair *next = kvp->next;
2429 free (kvp->key);
2430 switch (kvp->type)
2431 {
2432 case KV_STRING:
2433 free (kvp->val.s);
2434 break;
2435
2436 case KV_LIST:
2437 slist_free (kvp->val.l);
2438 break;
2439 }
2440 free (kvp);
2441 kvp = next;
2442 }
2443 }
2444
2445 struct kvpair *
kvlist_find(struct kvpair * kv,char const * tag)2446 kvlist_find (struct kvpair *kv, char const *tag)
2447 {
2448 for (; kv; kv = kv->next)
2449 if (kv->key && strcmp (kv->key, tag) == 0)
2450 break;
2451 return kv;
2452 }
2453
2454 int
gdbmarg_free(struct gdbmarg * arg)2455 gdbmarg_free (struct gdbmarg *arg)
2456 {
2457 if (arg && --arg->ref == 0)
2458 {
2459 switch (arg->type)
2460 {
2461 case GDBM_ARG_STRING:
2462 free (arg->v.string);
2463 break;
2464
2465 case GDBM_ARG_KVPAIR:
2466 kvlist_free (arg->v.kvpair);
2467 break;
2468
2469 case GDBM_ARG_DATUM:
2470 free (arg->v.dat.dptr);
2471 break;
2472 }
2473 free (arg);
2474 return 0;
2475 }
2476 return 1;
2477 }
2478
2479 void
gdbmarg_destroy(struct gdbmarg ** parg)2480 gdbmarg_destroy (struct gdbmarg **parg)
2481 {
2482 if (parg && gdbmarg_free (*parg))
2483 *parg = NULL;
2484 }
2485
2486 void
gdbmarglist_init(struct gdbmarglist * lst,struct gdbmarg * arg)2487 gdbmarglist_init (struct gdbmarglist *lst, struct gdbmarg *arg)
2488 {
2489 if (arg)
2490 arg->next = NULL;
2491 lst->head = lst->tail = arg;
2492 }
2493
2494 void
gdbmarglist_add(struct gdbmarglist * lst,struct gdbmarg * arg)2495 gdbmarglist_add (struct gdbmarglist *lst, struct gdbmarg *arg)
2496 {
2497 arg->next = NULL;
2498 if (lst->tail)
2499 lst->tail->next = arg;
2500 else
2501 lst->head = arg;
2502 lst->tail = arg;
2503 }
2504
2505 void
gdbmarglist_free(struct gdbmarglist * lst)2506 gdbmarglist_free (struct gdbmarglist *lst)
2507 {
2508 struct gdbmarg *arg;
2509
2510 for (arg = lst->head; arg; )
2511 {
2512 struct gdbmarg *next = arg->next;
2513 gdbmarg_free (arg);
2514 arg = next;
2515 }
2516 lst->head = lst->tail = NULL;
2517 }
2518
2519 static void
param_expand(struct command_param * p)2520 param_expand (struct command_param *p)
2521 {
2522 if (p->argc == p->argmax)
2523 p->argv = e2nrealloc (p->argv, &p->argmax, sizeof (p->argv[0]));
2524 }
2525
2526 static void
param_free_argv(struct command_param * p)2527 param_free_argv (struct command_param *p)
2528 {
2529 size_t i;
2530
2531 for (i = 0; i < p->argc; i++)
2532 gdbmarg_destroy (&p->argv[i]);
2533 p->argc = 0;
2534 }
2535
2536 static void
param_free(struct command_param * p)2537 param_free (struct command_param *p)
2538 {
2539 param_free_argv (p);
2540 free (p->argv);
2541 p->argv = NULL;
2542 p->argmax = 0;
2543 }
2544
2545 static struct gdbmarg *coerce (struct gdbmarg *arg, struct argdef *def);
2546
2547 static int
param_push_arg(struct command_param * p,struct gdbmarg * arg,struct argdef * def)2548 param_push_arg (struct command_param *p, struct gdbmarg *arg,
2549 struct argdef *def)
2550 {
2551 param_expand (p);
2552 if ((p->argv[p->argc] = coerce (arg, def)) == NULL)
2553 {
2554 return 1;
2555 }
2556 p->argc++;
2557 return 0;
2558 }
2559
2560 static void
param_term(struct command_param * p)2561 param_term (struct command_param *p)
2562 {
2563 param_expand (p);
2564 p->argv[p->argc] = NULL;
2565 }
2566
2567 typedef struct gdbmarg *(*coerce_type_t) (struct gdbmarg *arg,
2568 struct argdef *def);
2569
2570 struct gdbmarg *
2571 coerce_ref (struct gdbmarg *arg, struct argdef *def)
2572 {
2573 ++arg->ref;
2574 return arg;
2575 }
2576
2577 struct gdbmarg *
2578 coerce_k2d (struct gdbmarg *arg, struct argdef *def)
2579 {
2580 datum d;
2581
2582 if (datum_scan (&d, dsdef[def->ds], arg->v.kvpair))
2583 return NULL;
2584 return gdbmarg_datum (&d, &arg->loc);
2585 }
2586
2587 struct gdbmarg *
2588 coerce_s2d (struct gdbmarg *arg, struct argdef *def)
2589 {
2590 datum d;
2591 struct kvpair kvp;
2592
2593 memset (&kvp, 0, sizeof (kvp));
2594 kvp.type = KV_STRING;
2595 kvp.val.s = arg->v.string;
2596
2597 if (datum_scan (&d, dsdef[def->ds], &kvp))
2598 return NULL;
2599 return gdbmarg_datum (&d, &arg->loc);
2600 }
2601
2602 #define coerce_fail NULL
2603
2604 coerce_type_t coerce_tab[GDBM_ARG_MAX][GDBM_ARG_MAX] = {
2605 /* s d k */
2606 /* s */ { coerce_ref, coerce_fail, coerce_fail },
2607 /* d */ { coerce_s2d, coerce_ref, coerce_k2d },
2608 /* k */ { coerce_fail, coerce_fail, coerce_ref }
2609 };
2610
2611 char *argtypestr[] = { "string", "datum", "k/v pair" };
2612
2613 static struct gdbmarg *
coerce(struct gdbmarg * arg,struct argdef * def)2614 coerce (struct gdbmarg *arg, struct argdef *def)
2615 {
2616 if (!coerce_tab[def->type][arg->type])
2617 {
2618 lerror (&arg->loc, _("cannot coerce %s to %s"),
2619 argtypestr[arg->type], argtypestr[def->type]);
2620 return NULL;
2621 }
2622 return coerce_tab[def->type][arg->type] (arg, def);
2623 }
2624
2625 static struct command *last_cmd;
2626 static struct gdbmarglist last_args;
2627
2628 int
run_last_command(void)2629 run_last_command (void)
2630 {
2631 if (interactive ())
2632 {
2633 if (last_cmd)
2634 {
2635 switch (last_cmd->repeat)
2636 {
2637 case REPEAT_NEVER:
2638 break;
2639 case REPEAT_NOARG:
2640 gdbmarglist_free (&last_args);
2641 /* FALLTHROUGH */
2642 case REPEAT_ALWAYS:
2643 return run_command (last_cmd, &last_args);
2644
2645 default:
2646 abort ();
2647 }
2648 }
2649 }
2650 return 0;
2651 }
2652
2653 static void
format_arg(struct gdbmarg * arg,struct argdef * def,FILE * fp)2654 format_arg (struct gdbmarg *arg, struct argdef *def, FILE *fp)
2655 {
2656 switch (arg->type)
2657 {
2658 case GDBM_ARG_STRING:
2659 fprintf (fp, " %s", arg->v.string);
2660 break;
2661
2662 case GDBM_ARG_DATUM:
2663 if (def && def->type == GDBM_ARG_DATUM)
2664 {
2665 fputc (' ', fp);
2666 datum_format (fp, &arg->v.dat, dsdef[def->ds]);
2667 }
2668 else
2669 /* Shouldn't happen */
2670 terror ("%s:%d: INTERNAL ERROR: unexpected data type in arglist",
2671 __FILE__, __LINE__);
2672 break;
2673
2674 case GDBM_ARG_KVPAIR:
2675 {
2676 struct kvpair *kvp = arg->v.kvpair;
2677 fprintf (fp, " %s ", kvp->key);
2678 switch (kvp->type)
2679 {
2680 case KV_STRING:
2681 fprintf (fp, "%s", kvp->val.s);
2682 break;
2683
2684 case KV_LIST:
2685 {
2686 struct slist *p = kvp->val.l;
2687 fprintf (fp, "%s", p->str);
2688 while ((p = p->next) != NULL)
2689 fprintf (fp, ", %s", p->str);
2690 }
2691 }
2692 }
2693 }
2694 }
2695
2696 struct timing
2697 {
2698 struct timeval real;
2699 struct timeval user;
2700 struct timeval sys;
2701 };
2702
2703 void
timing_start(struct timing * t)2704 timing_start (struct timing *t)
2705 {
2706 struct rusage r;
2707 gettimeofday (&t->real, NULL);
2708 getrusage (RUSAGE_SELF, &r);
2709 t->user = r.ru_utime;
2710 t->sys = r.ru_stime;
2711 }
2712
2713 static inline struct timeval
timeval_sub(struct timeval a,struct timeval b)2714 timeval_sub (struct timeval a, struct timeval b)
2715 {
2716 struct timeval diff;
2717
2718 diff.tv_sec = a.tv_sec - b.tv_sec;
2719 diff.tv_usec = a.tv_usec - b.tv_usec;
2720 if (diff.tv_usec < 0)
2721 {
2722 --diff.tv_sec;
2723 diff.tv_usec += 1000000;
2724 }
2725
2726 return diff;
2727 }
2728
2729 void
timing_stop(struct timing * t)2730 timing_stop (struct timing *t)
2731 {
2732 struct rusage r;
2733 struct timeval now;
2734
2735 gettimeofday (&now, NULL);
2736 getrusage (RUSAGE_SELF, &r);
2737 t->real = timeval_sub (now, t->real);
2738 t->user = timeval_sub (r.ru_utime, t->user);
2739 t->sys = timeval_sub (r.ru_stime, t->sys);
2740 }
2741
2742 int
run_command(struct command * cmd,struct gdbmarglist * arglist)2743 run_command (struct command *cmd, struct gdbmarglist *arglist)
2744 {
2745 int i;
2746 struct gdbmarg *arg;
2747 char *pager = NULL;
2748 char argbuf[128];
2749 size_t expected_lines, *expected_lines_ptr;
2750 FILE *pagfp = NULL;
2751 struct command_param param = HANDLER_PARAM_INITIALIZER;
2752 struct command_environ cenv = COMMAND_ENVIRON_INITIALIZER;
2753 int rc = 0;
2754 struct timing tm;
2755
2756 variable_get ("pager", VART_STRING, (void**) &pager);
2757
2758 arg = arglist ? arglist->head : NULL;
2759
2760 for (i = 0; cmd->args[i].name && arg; i++, arg = arg->next)
2761 {
2762 if (param_push_arg (¶m, arg, &cmd->args[i]))
2763 {
2764 param_free (¶m);
2765 return 1;
2766 }
2767 }
2768
2769 for (; cmd->args[i].name; i++)
2770 {
2771 char *argname = cmd->args[i].name;
2772 struct gdbmarg *t;
2773
2774 if (*argname == '[')
2775 /* Optional argument */
2776 break;
2777
2778 if (!interactive ())
2779 {
2780 terror (_("%s: not enough arguments"), cmd->name);
2781 param_free (¶m);
2782 return 1;
2783 }
2784 printf ("%s? ", argname);
2785 fflush (stdout);
2786 if (fgets (argbuf, sizeof argbuf, stdin) == NULL)
2787 {
2788 terror (_("unexpected eof"));
2789 exit (EXIT_USAGE);
2790 }
2791
2792 trimnl (argbuf);
2793
2794 t = gdbmarg_string (estrdup (argbuf), &yylloc);
2795 if (param_push_arg (¶m, t, &cmd->args[i]))
2796 {
2797 param_free (¶m);
2798 gdbmarg_free (t);
2799 return 1;
2800 }
2801 }
2802
2803 if (arg && !cmd->variadic)
2804 {
2805 terror (_("%s: too many arguments"), cmd->name);
2806 param_free (¶m);
2807 return 1;
2808 }
2809
2810 /* Prepare for calling the handler */
2811 param_term (¶m);
2812 param.vararg = arg;
2813 pagfp = NULL;
2814
2815 if (variable_is_true ("trace"))
2816 {
2817 fprintf (stderr, "+ %s", cmd->name);
2818 for (i = 0; i < param.argc; i++)
2819 {
2820 format_arg (param.argv[i], &cmd->args[i], stderr);
2821 }
2822
2823 if (param.vararg)
2824 {
2825 struct gdbmarg *arg;
2826 for (arg = param.vararg; arg; arg = arg->next)
2827 format_arg (arg, NULL, stderr);
2828 }
2829 fputc ('\n', stderr);
2830 }
2831
2832 expected_lines = 0;
2833 expected_lines_ptr = (interactive () && pager) ? &expected_lines : NULL;
2834 rc = 0;
2835 if (!(cmd->begin && (rc = cmd->begin (¶m, &cenv, expected_lines_ptr)) != 0))
2836 {
2837 if (pager && expected_lines > get_screen_lines ())
2838 {
2839 pagfp = popen (pager, "w");
2840 if (pagfp)
2841 cenv.fp = pagfp;
2842 else
2843 {
2844 terror (_("cannot run pager `%s': %s"), pager,
2845 strerror (errno));
2846 pager = NULL;
2847 cenv.fp = stdout;
2848 }
2849 }
2850 else
2851 cenv.fp = stdout;
2852
2853 timing_start (&tm);
2854 rc = cmd->handler (¶m, &cenv);
2855 timing_stop (&tm);
2856 if (cmd->end)
2857 cmd->end (cenv.data);
2858 else if (cenv.data)
2859 free (cenv.data);
2860
2861 if (variable_is_true ("timing"))
2862 {
2863 fprintf (cenv.fp, "[%s r=%lu.%06lu u=%lu.%06lu s=%lu.%06lu]\n",
2864 cmd->name,
2865 tm.real.tv_sec, tm.real.tv_usec,
2866 tm.user.tv_sec, tm.user.tv_usec,
2867 tm.sys.tv_sec, tm.sys.tv_usec);
2868 }
2869
2870 if (pagfp)
2871 pclose (pagfp);
2872 }
2873
2874 param_free (¶m);
2875
2876 last_cmd = cmd;
2877 if (arglist->head != last_args.head)
2878 {
2879 gdbmarglist_free (&last_args);
2880 last_args = *arglist;
2881 }
2882
2883 if (rc == GDBMSHELL_GDBM_ERR && variable_has_errno ("errorexit", gdbm_errno))
2884 rc = 1;
2885 else
2886 rc = 0;
2887
2888 return rc;
2889 }
2890
2891 int
gdbmshell_run(int (* init)(void *,instream_t *),void * data)2892 gdbmshell_run (int (*init) (void *, instream_t *), void *data)
2893 {
2894 int rc;
2895 int i;
2896 instream_t instream;
2897
2898 if (!commands_sorted)
2899 {
2900 /* Initialize .len fields */
2901 for (i = 0; command_tab[i].name; i++)
2902 command_tab[i].len = strlen (command_tab[i].name);
2903 /* Sort the entries by name. */
2904 qsort (command_tab, i, sizeof (command_tab[0]), cmdcmp);
2905 commands_sorted = 1;
2906 }
2907
2908 /* Initialize variables. */
2909 dsdef[DS_KEY] = dsegm_new_field (datadef_lookup ("string"), NULL, 1);
2910 dsdef[DS_CONTENT] = dsegm_new_field (datadef_lookup ("string"), NULL, 1);
2911
2912 variables_init ();
2913 variable_set ("open", VART_STRING, "wrcreat");
2914 variable_set ("pager", VART_STRING, getenv ("PAGER"));
2915
2916 last_cmd = NULL;
2917 gdbmarglist_init (&last_args, NULL);
2918
2919 lex_trace (0);
2920
2921 rc = init (data, &instream);
2922 if (rc == 0)
2923 {
2924 rc = input_context_push (instream);
2925 if (rc == 0)
2926 {
2927 struct sigaction act, old_act;
2928
2929 act.sa_flags = 0;
2930 sigemptyset(&act.sa_mask);
2931 act.sa_handler = SIG_IGN;
2932 sigaction (SIGPIPE, &act, &old_act);
2933 /* Welcome message. */
2934 if (instream_interactive (instream) && !variable_is_true ("quiet"))
2935 printf (_("\nWelcome to the gdbm tool. Type ? for help.\n\n"));
2936 rc = yyparse ();
2937 input_context_drain ();
2938 yylex_destroy ();
2939 closedb ();
2940 sigaction (SIGPIPE, &old_act, NULL);
2941 }
2942 else
2943 instream_close (instream);
2944 }
2945
2946 gdbmarglist_free (&last_args);
2947
2948 for (i = 0; i < DS_MAX; i++)
2949 {
2950 dsegm_list_free (dsdef[i]);
2951 dsdef[i] = NULL;
2952 }
2953
2954 variables_free ();
2955
2956 return rc;
2957 }
2958
2959 static int
init(void * data,instream_t * pinstr)2960 init (void *data, instream_t *pinstr)
2961 {
2962 *pinstr = data;
2963 return 0;
2964 }
2965
2966 int
gdbmshell(instream_t input)2967 gdbmshell (instream_t input)
2968 {
2969 return gdbmshell_run (init, input);
2970 }
2971