Logo Search packages:      
Sourcecode: mailavenger version File versions  Download package

dbutil.c

/* $Id$ */

/*
 *
 * Copyright (C) 2004 David Mazieres (dm@uun.org)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 *
 */

#include "avutil.h"
#include "dbexp.h"
#include <ctype.h>
#include "getopt_long.h"

char *progname;
dbenv *env;
int opt_sync = 1;

static char *
_do_dump_time (time_t t)
{
  static char buf[80];
  int n;
  if ((u_int32_t) t == 0xffffffff)
    return "";
  n = strftime (buf, sizeof (buf) - 1, " (%a %b %e %Y %H:%M:%S)",
            localtime (&t));
  if (n)
    return buf;
  else
    return "";
}
int
do_dump (const char *db)
{
  dbexp *dbx;
  DBC *c;
  int err;
  DBT k, v;
  int ret = 0;

  if (!(dbx = dbexp_alloc (env, db, 1)))
    return 2;

  err = dbx->db->cursor (dbx->db, NULL, &c, 0);
  if (err) {
    fprintf (stderr, "%s; %s\n", db, db_strerror (err));
    dbexp_free (dbx, 0);
    return 2;
  }

  bzero (&k, sizeof (k));
  bzero (&v, sizeof (v));

  err = c->c_get (c, &k, &v, DB_FIRST);
  while (!err) {
    if (v.size >= 4) {
      time_t t = getint (v.data);
      printf ("%.*s %.*s%s\n", (int) k.size, (char *) k.data,
            (int) v.size - 4, (char *) v.data + 4,
            _do_dump_time (t));
    }
    err = c->c_get (c, &k, &v, DB_NEXT);
  }
  if (err && err != DB_NOTFOUND) {
    fprintf (stderr, "%s; %s\n", db, db_strerror (err));
    ret = 2;
  }

  c->c_close (c);
  dbexp_free (dbx, 0);

  return ret;
}

int
do_update (const char *db, const char *key, const char *val, int opt_n,
         const char *opt_expire)
{
  dbexp *dbx;
  DBT k, v;
  int ret = 0;
  int err;
  long exp;

  if (!(dbx = dbexp_alloc (env, db, 0)) || dbexp_clean (dbx))
    return 2;

  bzero (&k, sizeof (k));
  k.data = (void *) key;
  k.size = strlen (key);

  bzero (&v, sizeof (v));
  v.size = 4 + strlen (val);
  v.data = xmalloc (v.size + 1);
  if (opt_expire && (exp = parse_expire (opt_expire, time (NULL))) != -1)
    putint (v.data, exp);
  else
    putint (v.data, 0xffffffff);
  strcpy ((char *) v.data + 4, val);

  err = dbx->db->put (dbx->db, NULL, &k, &v,
                  dbx->dbe->txnflag | (opt_n ? DB_NOOVERWRITE : 0));
  if (err == DB_KEYEXIST)
    ret = 1;
  else if (err) {
    fprintf (stderr, "%s; %s\n", db, db_strerror (err));
    ret = 2;
  }

  err = dbexp_free (dbx, opt_sync);
  if (err && ret < 2) {
    fprintf (stderr, "%s; %s\n", db, db_strerror (err));
    ret = 2;
  }

  return ret;
}

int
do_query (const char *db, const char *key, int opt_t, const char *opt_expire)
{
  dbexp *dbx;
  DBT k, v;
  int err;
  u_int32_t now = time (NULL);

  if (!(dbx = dbexp_alloc (env, db, !opt_expire))
      || (opt_expire && dbexp_clean (dbx)))
    return 2;

  bzero (&k, sizeof (k));
  k.data = (void *) key;
  k.size = strlen (key);
  bzero (&v, sizeof (v));
  err = dbx->db->get (dbx->db, NULL, &k, &v, 0);
  if (err == DB_NOTFOUND) {
    dbexp_free (dbx, 0);
    return 1;
  }
  else if (err) {
    fprintf (stderr, "%s: %s\n", db, db_strerror (err));
    dbexp_free (dbx, 0);
    return 2;
  }
  else if (v.size < 4) {
    fprintf (stderr, "%s: record too short\n", db);
    dbexp_free (dbx, 0);
    return 2;
  }

  if (now > getint (v.data)) {
    dbexp_free (dbx, opt_expire && opt_sync);
    return 1;
  }

  if (opt_t)
    printf ("%lu\n", (unsigned long) getint (v.data));
  else
    printf ("%.*s\n", (int) (v.size - 4), (char *) v.data + 4);

  if (opt_expire) {
    long exp = parse_expire (opt_expire, time (NULL));
    if (exp != -1) {
      putint (v.data, exp);
      v.size = 4;
      v.dlen = 4;
      v.flags |= DB_DBT_PARTIAL;
      err = dbx->db->put (dbx->db, NULL, &k, &v, dbx->dbe->txnflag);
      if (err)
      fprintf (stderr, "%s; %s\n", dbx->path, db_strerror (err));
    }
    else
      opt_expire = NULL;
  }

  err = dbexp_free (dbx, opt_expire && opt_sync);
  if (err) {
    fprintf (stderr, "%s; %s\n", dbx->path, db_strerror (err));
    return 2;
  }
  return 0;
}

int
do_delete (const char *db, const char *key)
{
  dbexp *dbx;
  DBT k;
  int ret = 0;
  int err;

  if (!(dbx = dbexp_alloc (env, db, 0)) || dbexp_clean (dbx))
    return 2;

  bzero (&k, sizeof (k));
  k.data = (void *) key;
  k.size = strlen (key);

  err = dbx->db->del (dbx->db, NULL, &k, dbx->dbe->txnflag);
  if (err == DB_NOTFOUND)
    ret = 1;
  else if (err) {
    fprintf (stderr, "%s; %s\n", db, db_strerror (err));
    ret = 2;
  }

  err = dbexp_free (dbx, opt_sync);
  if (err)
    return 2;
  return 0;
}

static void usage (void) __attribute__ ((noreturn));
static void
usage (void)
{
  fprintf (stderr, "usage: %s options {-d | --dump} db\n",
         progname);
  fprintf (stderr, "       %s options {-q | --query}"
         " [-t] db key\n", progname); 
  fprintf (stderr, "       %s options {-u | --update}"
         " [-n] db key [value]\n", progname); 
  fprintf (stderr, "       %s options {-x | --delete} db key\n",
         progname);
  fprintf (stderr, "       %s -t\n", progname);
  fprintf (stderr, "options are:\n"
         "  --dbhome=DB_HOME  Specify directory for DB log files\n"
         "  --expire=date     Specify timestamp for expiration\n");
  exit (1);
}

#define opt_dbenv 0x101
int
main (int argc, char **argv)
{
  int mode = 0;
  struct option o[] = {
    { "nosync", no_argument, NULL, 'N' },
    { "version", no_argument, &mode, 'v' },
    { "dbhome", required_argument, NULL, opt_dbenv },
    { "dump", no_argument, NULL, 'd' },
    { "query", no_argument, NULL, 'q' },
    { "update", no_argument, NULL, 'u' },
    { "delete", no_argument, NULL, 'x' },
    { "expire", required_argument, NULL, 'e' },
    { NULL, 0, NULL, 0 }
  };
  int c;
  int opt_n = 0, opt_t = 0;
  int ret = 0;
  char *opt_expire = NULL;
  char *dbenvdir = getenv ("DB_HOME");

  progname = strrchr (argv[0], '/');
  if (progname)
    progname++;
  else
    progname = argv[0];

  while ((c = getopt_long (argc, argv, "Ndquxnte", o, NULL)) != -1)
    switch (c) {
    case 0:
      break;
    case 'N':
      opt_sync = 0;
      break;
    case 'e':
      opt_expire = optarg;
      break;
    case 'n':
      opt_n = 1;
      break;
    case 't':
      opt_t = 1;
      break;
    case 'd':
    case 'q':
    case 'u':
    case 'x':
      if (mode)
      usage ();
      mode = c;
      break;
    case opt_dbenv:
      dbenvdir = optarg;
      break;
    default:
      usage ();
    }

  if (mode == 'v')
    version (progname, 1);

  if (opt_n && mode != 'u')
    usage ();
  if (opt_t && !mode) {
    if (optind + 1 == argc) {
      long exp = parse_expire (argv[optind], time (NULL));
      if (exp == -1)
      exit (2);
      printf ("%lu\n", exp);
    }
    else if (optind == argc)
      printf ("%lu\n", (unsigned long) time (NULL));
    else
      usage ();
    exit (0);
  }
  if (opt_t && mode != 'q')
    usage ();

  env = dbenv_alloc (dbenvdir);
  if (!env)
    exit (2);

  switch (mode) {
  case 'd':
    if (argc != optind + 1)
      usage ();
    ret = do_dump (argv[optind]);
    break;
  case 'q':
    if (argc != optind + 2)
      usage ();
    ret = do_query (argv[optind], argv[optind+1], opt_t, opt_expire);
    break;
  case 'u':
    if (argc < optind + 2 || argc > optind + 3)
      usage ();
    ret = do_update (argv[optind], argv[optind+1],
                 argc < optind + 3 ? "" : argv[optind+2], opt_n,
                 opt_expire);
    break;
  case 'x':
    if (argc != optind + 2)
      usage ();
    ret = do_delete (argv[optind], argv[optind+1]);
    break;
  default:
    usage ();
  }

  dbenv_free (env);

  return ret;
}

Generated by  Doxygen 1.6.0   Back to index