/* $Id: dbutil.c,v 1.16 2006/02/04 01:10:33 dm Exp $ */
/*
*
* 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;
}
syntax highlighted by Code2HTML, v. 0.9.1