/* $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 #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; }