Coverage Report

Created: 2023-06-07 07:16

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