]> arthur.barton.de Git - netatalk.git/commitdiff
Add an indexes check and rebuild, optionnal for dbd (parameter check
authordidg <didg>
Tue, 21 Dec 2004 13:36:11 +0000 (13:36 +0000)
committerdidg <didg>
Tue, 21 Dec 2004 13:36:11 +0000 (13:36 +0000)
default no), standalone prg cnid_index for cdb.

bin/cnid/Makefile.am
bin/cnid/cnid_index.c [new file with mode: 0644]
etc/cnid_dbd/Makefile.am
etc/cnid_dbd/db_param.c
etc/cnid_dbd/db_param.h
etc/cnid_dbd/dbd.h
etc/cnid_dbd/dbd_dbcheck.c [new file with mode: 0644]
etc/cnid_dbd/dbif.c
etc/cnid_dbd/dbif.h
etc/cnid_dbd/main.c

index 77653ee7700d467ba569f7ee5f6232cc7c0c1478..53924c1282fa3c3cbc6bb92b9d4e149befed0c66 100644 (file)
@@ -4,6 +4,15 @@ EXTRA_DIST = cnid_maint.in cnid2_create.in
 
 #if COMPILE_CNID
 bin_SCRIPTS = cnid_maint cnid2_create
+bin_PROGRAMS = cnid_index
 #else
 #bin_SCRIPTS = 
 #endif
+
+cnid_index_SOURCES = cnid_index.c 
+
+cnid_index_LDADD = $(top_builddir)/libatalk/libatalk.la       
+
+LIBS = @LIBS@ @BDB_LIBS@
+CFLAGS = @CFLAGS@ @BDB_CFLAGS@ 
diff --git a/bin/cnid/cnid_index.c b/bin/cnid/cnid_index.c
new file mode 100644 (file)
index 0000000..08328d5
--- /dev/null
@@ -0,0 +1,582 @@
+/*
+ * $Id: cnid_index.c,v 1.1.2.1 2004-12-21 13:36:11 didg Exp $
+ *
+ * All Rights Reserved.  See COPYING.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif /* HAVE_FCNTL_H */
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif /* HAVE_SYS_TYPES_H */
+#include <sys/param.h>
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif /* HAVE_SYS_STAT_H */
+#include <time.h>
+#include <sys/file.h>
+
+#include <netatalk/endian.h>
+#include <atalk/cnid_dbd_private.h>
+#include <atalk/logger.h>
+
+#define LOCKFILENAME  "lock"
+static int exit_sig = 0;
+
+/* Copy and past from etc/cnid_dbd/dbif.c */
+#include <db.h>
+
+#define DB_ERRLOGFILE "db_errlog"
+
+static DB_ENV *db_env = NULL;
+static DB_TXN *db_txn = NULL;
+static FILE   *db_errlog = NULL;
+
+#ifdef CNID_BACKEND_DBD_TXN
+#define DBOPTIONS    (DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN)
+#else
+#define DBOPTIONS    (DB_CREATE | DB_INIT_CDB | DB_INIT_MPOOL | DB_PRIVATE) 
+#endif
+
+#define DBIF_DB_CNT 3
+
+#define DBIF_IDX_CNID      0
+#define DBIF_IDX_DEVINO    1
+#define DBIF_IDX_DIDNAME   2
+
+static struct db_table {
+     char            *name;
+     DB              *db;
+     u_int32_t       general_flags;
+     DBTYPE          type;
+} db_table[] =
+{
+     { "cnid2.db",       NULL,      0, DB_BTREE},
+     { "devino.db",      NULL,      0, DB_BTREE},
+     { "didname.db",     NULL,      0, DB_BTREE},
+};
+
+static char *old_dbfiles[] = {"cnid.db", NULL};
+
+/* --------------- */
+int didname(dbp, pkey, pdata, skey)
+DB *dbp;
+const DBT *pkey, *pdata;
+DBT *skey;
+{
+int len;
+    memset(skey, 0, sizeof(DBT));
+    skey->data = (char *)pdata->data + CNID_DID_OFS;
+    /* FIXME: At least DB 4.0.14 and 4.1.25 pass in the correct length of
+       pdata.size. strlen is therefore not needed. Also, skey should be zeroed
+       out already. */
+    len = strlen((char *)skey->data + CNID_DID_LEN);
+    skey->size = CNID_DID_LEN + len + 1;
+    return (0);
+}
+/* --------------- */
+int devino(dbp, pkey, pdata, skey)
+DB *dbp;
+const DBT *pkey, *pdata;
+DBT *skey;
+{
+    memset(skey, 0, sizeof(DBT));
+    skey->data = (char *)pdata->data + CNID_DEVINO_OFS;
+    skey->size = CNID_DEVINO_LEN;
+    return (0);
+}
+
+/* --------------- */
+static int  db_compat_associate (DB *p, DB *s,
+                   int (*callback)(DB *, const DBT *,const DBT *, DBT *),
+                   u_int32_t flags)
+{
+#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
+    return p->associate(p, db_txn, s, callback, flags);
+#else
+#if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 0)
+    return p->associate(p,       s, callback, flags);
+#else
+    return 0;
+#endif
+#endif
+}
+
+/* --------------- */
+static int db_compat_open(DB *db, char *file, char *name, DBTYPE type, int mode)
+{
+    int ret;
+
+#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
+    ret = db->open(db, db_txn, file, name, type, DB_CREATE, mode); 
+#else
+    ret = db->open(db,       file, name, type, DB_CREATE, mode); 
+#endif
+
+    if (ret) {
+        LOG(log_error, logtype_cnid, "error opening database %s: %s", name, db_strerror(ret));
+        return -1;
+    } else {
+        return 0;
+    }
+}
+
+/* --------------- */
+static int dbif_open(int do_truncate)
+{
+    int ret;
+    int i;
+    u_int32_t count;
+
+    for (i = 0; i != DBIF_DB_CNT; i++) {
+        if ((ret = db_create(&(db_table[i].db), db_env, 0))) {
+            LOG(log_error, logtype_cnid, "error creating handle for database %s: %s", 
+                db_table[i].name, db_strerror(ret));
+            return -1;
+        }
+
+        if (db_table[i].general_flags) { 
+            if ((ret = db_table[i].db->set_flags(db_table[i].db, db_table[i].general_flags))) {
+                LOG(log_error, logtype_cnid, "error setting flags for database %s: %s", 
+                    db_table[i].name, db_strerror(ret));
+                return -1;
+            }
+        }
+
+        if (db_compat_open(db_table[i].db, db_table[0].name, db_table[i].name, db_table[i].type, 0664) < 0)
+            return -1;
+        if (db_errlog != NULL)
+            db_table[i].db->set_errfile(db_table[i].db, db_errlog);
+
+        if (do_truncate && i > 0) {
+           if ((ret = db_table[i].db->truncate(db_table[i].db, db_txn, &count, 0))) {
+                LOG(log_error, logtype_cnid, "error truncating database %s: %s", 
+                    db_table[i].name, db_strerror(ret));
+                return -1;
+            }
+        }
+    }
+
+    /* TODO: Implement CNID DB versioning info on new databases. */
+    /* TODO: Make transaction support a runtime option. */
+    /* Associate the secondary with the primary. */
+    if ((ret = db_compat_associate(db_table[0].db, db_table[DBIF_IDX_DIDNAME].db, didname, (do_truncate)?DB_CREATE:0)) != 0) {
+        LOG(log_error, logtype_cnid, "Failed to associate didname database: %s",db_strerror(ret));
+        return -1;
+    }
+    if ((ret = db_compat_associate(db_table[0].db, db_table[DBIF_IDX_DEVINO].db, devino, (do_truncate)?DB_CREATE:0)) != 0) {
+        LOG(log_error, logtype_cnid, "Failed to associate devino database: %s",db_strerror(ret));
+       return -1;
+    }
+
+    return 0;
+}
+
+/* ------------------------ */
+static int dbif_closedb(void)
+{
+    int i;
+    int ret;
+    int err = 0;
+
+    for (i = DBIF_DB_CNT -1; i >= 0; i--) {
+        if (db_table[i].db != NULL && (ret = db_table[i].db->close(db_table[i].db, 0))) {
+            LOG(log_error, logtype_cnid, "error closing database %s: %s", db_table[i].name, db_strerror(ret));
+            err++;
+        }
+    }
+    if (err)
+        return -1;
+    return 0;
+}
+
+/* ------------------------ */
+static int dbif_close(void)
+{
+    int ret;
+    int err = 0;
+    
+    if (dbif_closedb()) 
+       err++;
+     
+    if (db_env != NULL && (ret = db_env->close(db_env, 0))) { 
+        LOG(log_error, logtype_cnid, "error closing DB environment: %s", db_strerror(ret));
+        err++;
+    }
+    if (db_errlog != NULL && fclose(db_errlog) == EOF) {
+        LOG(log_error, logtype_cnid, "error closing DB logfile: %s", strerror(errno));
+        err++;
+    }
+    if (err)
+        return -1;
+    return 0;
+}
+/* --------------- */
+static int upgrade_required(void)
+{
+    int i;
+    int found = 0;
+    struct stat st;
+    
+    for (i = 0; old_dbfiles[i] != NULL; i++) {
+       if ( !(stat(old_dbfiles[i], &st) < 0) ) {
+           found++;
+           continue;
+       }
+       if (errno != ENOENT) {
+           LOG(log_error, logtype_cnid, "cnid_open: Checking %s gave %s", old_dbfiles[i], strerror(errno));
+           found++;
+       }
+    }
+    return found;
+}
+
+/* -------------------------- */
+static int dbif_sync(void)
+{
+    int i;
+    int ret;
+    int err = 0;
+     
+    for (i = 0; i != /* DBIF_DB_CNT*/ 1; i++) {
+        if ((ret = db_table[i].db->sync(db_table[i].db, 0))) {
+            LOG(log_error, logtype_cnid, "error syncing database %s: %s", db_table[i].name, db_strerror(ret));
+            err++;
+        }
+    }
+    if (err)
+        return -1;
+    else
+        return 0;
+}
+
+/* -------------------------- */
+static int dbif_count(const int dbi, u_int32_t *count) 
+{
+    int ret;
+    DB_BTREE_STAT *sp;
+    DB *db = db_table[dbi].db;
+
+    ret = db->stat(db, &sp, 0);
+
+    if (ret) {
+        LOG(log_error, logtype_cnid, "error getting stat infotmation on database: %s", db_strerror(errno));
+        return -1;
+    }
+
+    *count = sp->bt_ndata;
+    free(sp);
+
+    return 0;
+}
+
+/* -------------------------- */
+static int dbd_check(char *dbdir)
+{
+    u_int32_t c_didname = 0, c_devino = 0, c_cnid = 0;
+
+    LOG(log_debug, logtype_cnid, "CNID database at `%s' is being checked (quick)", dbdir);
+
+    if (dbif_count(DBIF_IDX_CNID, &c_cnid)) 
+        return -1;
+
+    if (dbif_count(DBIF_IDX_DIDNAME, &c_didname)) 
+        return -1;
+    
+    /* bailout after the first error */
+    if (dbif_count(DBIF_IDX_DEVINO, &c_devino))
+        return -1;
+
+    if ( c_cnid != c_devino) {
+        LOG(log_error, logtype_cnid, "CNID database at `%s' corrupted (%u/%u)", dbdir, c_cnid, c_devino);
+        return 1;
+    }
+
+    if ( c_cnid != c_didname) {
+        LOG(log_error, logtype_cnid, "CNID database at `%s' corrupted (%u/%u)", dbdir, c_cnid, c_didname);
+        return 1;
+    }
+
+    LOG(log_debug, logtype_cnid, "CNID database at `%s' seems ok, %u entries.", dbdir, c_cnid);
+    return 0;  
+}
+
+/* --------------- */
+/*
+ *  We assume our current directory is already the BDB homedir. Otherwise
+ *  opening the databases will not work as expected. If we use transactions,
+ *  dbif_env_init(), dbif_close() and dbif_stamp() are the only interface
+ *  functions that can be called without a valid transaction handle in db_txn.
+ */
+static int dbif_env_init(void)
+{
+    int ret;
+#ifdef CNID_BACKEND_DBD_TXN
+    char **logfiles = NULL;
+    char **file;
+#endif
+
+    /* Refuse to do anything if this is an old version of the CNID database */
+    if (upgrade_required()) {
+       LOG(log_error, logtype_cnid, "Found version 1 of the CNID database. Please upgrade to version 2");
+       return -1;
+    }
+
+    if ((db_errlog = fopen(DB_ERRLOGFILE, "a")) == NULL)
+        LOG(log_warning, logtype_cnid, "error creating/opening DB errlogfile: %s", strerror(errno));
+
+#ifdef CNID_BACKEND_DBD_TXN
+    if ((ret = db_env_create(&db_env, 0))) {
+        LOG(log_error, logtype_cnid, "error creating DB environment: %s", 
+            db_strerror(ret));
+        db_env = NULL;
+        return -1;
+    }    
+    if (db_errlog != NULL)
+        db_env->set_errfile(db_env, db_errlog); 
+    db_env->set_verbose(db_env, DB_VERB_RECOVERY, 1);
+    db_env->set_verbose(db_env, DB_VERB_CHKPOINT, 1);
+    if ((ret = db_env->open(db_env, ".", DBOPTIONS | DB_PRIVATE | DB_RECOVER, 0))) {
+        LOG(log_error, logtype_cnid, "error opening DB environment: %s", 
+            db_strerror(ret));
+        db_env->close(db_env, 0);
+        db_env = NULL;
+        return -1;
+    }
+
+    if (db_errlog != NULL)
+        fflush(db_errlog);
+
+    if ((ret = db_env->close(db_env, 0))) {
+        LOG(log_error, logtype_cnid, "error closing DB environment after recovery: %s", 
+            db_strerror(ret));
+        db_env = NULL;
+        return -1;
+    }
+#endif
+    if ((ret = db_env_create(&db_env, 0))) {
+        LOG(log_error, logtype_cnid, "error creating DB environment after recovery: %s",
+            db_strerror(ret));
+        db_env = NULL;
+        return -1;
+    }
+    if (db_errlog != NULL)
+        db_env->set_errfile(db_env, db_errlog);
+    if ((ret = db_env->open(db_env, ".", DBOPTIONS , 0))) {
+        LOG(log_error, logtype_cnid, "error opening DB environment after recovery: %s",
+            db_strerror(ret));
+        db_env->close(db_env, 0);
+        db_env = NULL;
+        return -1;      
+    }
+
+#ifdef CNID_BACKEND_DBD_TXN
+    if (db_env->log_archive(db_env, &logfiles, 0)) {
+       LOG(log_error, logtype_cnid, "error getting list of stale logfiles: %s",
+            db_strerror(ret));
+        db_env->close(db_env, 0);
+        db_env = NULL;
+        return -1;
+    }
+    if (logfiles != NULL) {
+       for (file = logfiles; *file != NULL; file++) {
+           if (unlink(*file) < 0)
+               LOG(log_warning, logtype_cnid, "Error removing stale logfile %s: %s", *file, strerror(errno));
+       }
+       free(logfiles);
+    }
+#endif
+    return 0;
+}
+
+
+static void sig_exit(int signo)
+{
+    exit_sig = signo;
+    return;
+}
+
+static void block_sigs_onoff(int block)
+{
+    sigset_t set;
+    
+    sigemptyset(&set);
+    sigaddset(&set, SIGINT);
+    sigaddset(&set, SIGTERM);
+    if (block)
+        sigprocmask(SIG_BLOCK, &set, NULL);
+    else
+        sigprocmask(SIG_UNBLOCK, &set, NULL);
+    return;
+}
+
+/* ------------------------ */
+int get_lock(void)
+{
+    int lockfd;
+    struct flock lock;
+
+    if ((lockfd = open(LOCKFILENAME, O_RDWR | O_CREAT, 0644)) < 0) {
+       LOG(log_error, logtype_cnid, "main: error opening lockfile: %s", strerror(errno));
+       exit(1);
+    }
+    
+    lock.l_start  = 0;
+    lock.l_whence = SEEK_SET;
+    lock.l_len    = 0;
+    lock.l_type   = F_WRLCK;
+
+    if (fcntl(lockfd, F_SETLK, &lock) < 0) {
+       if (errno == EACCES || errno == EAGAIN) {
+           exit(0);
+       } else {
+           LOG(log_error, logtype_cnid, "main: fcntl F_WRLCK lockfile: %s", strerror(errno));
+           exit(1);
+       }
+    }
+    
+    return lockfd;
+}
+
+/* ----------------------- */
+void set_signal(void)
+{
+    struct sigaction sv;
+
+    sv.sa_handler = sig_exit;
+    sv.sa_flags = 0;
+    sigemptyset(&sv.sa_mask);
+    sigaddset(&sv.sa_mask, SIGINT);
+    sigaddset(&sv.sa_mask, SIGTERM);
+    if (sigaction(SIGINT, &sv, NULL) < 0 || sigaction(SIGTERM, &sv, NULL) < 0) {
+        LOG(log_error, logtype_cnid, "main: sigaction: %s", strerror(errno));
+        exit(1);
+    }
+    sv.sa_handler = SIG_IGN;
+    sigemptyset(&sv.sa_mask);
+    if (sigaction(SIGPIPE, &sv, NULL) < 0) {
+        LOG(log_error, logtype_cnid, "main: sigaction: %s", strerror(errno));
+        exit(1);
+    }
+}
+
+/* ----------------------- */
+void free_lock(int lockfd)
+{
+    struct flock lock;
+
+    lock.l_start  = 0;
+    lock.l_whence = SEEK_SET;
+    lock.l_len    = 0;
+    lock.l_type = F_UNLCK;
+    fcntl(lockfd, F_SETLK, &lock);
+    close(lockfd);
+}
+
+/* ------------------------ */
+int main(int argc, char *argv[])
+{
+    int err = 0;
+    int ret;
+    int lockfd;
+    char *dir;
+       
+    set_processname("cnid_index");
+    syslog_setup(log_debug, logtype_default, logoption_ndelay | logoption_pid, logfacility_daemon);
+    
+    if (argc  != 2) {
+        LOG(log_error, logtype_cnid, "main: not enough arguments");
+        exit(1);
+    }
+
+    dir = argv[1];
+
+    if (chdir(dir) < 0) {
+        LOG(log_error, logtype_cnid, "chdir to %s failed: %s", dir, strerror(errno));
+        exit(1);
+    }
+    
+    /* Before we do anything else, check if there is an instance of cnid_dbd
+       running already and silently exit if yes. */
+    lockfd = get_lock();
+    
+    LOG(log_info, logtype_cnid, "Startup, DB dir %s", dir);
+    
+    set_signal();
+    
+    /* SIGINT and SIGTERM are always off, unless we get a return code of 0 from
+       comm_rcv (no requests for one second, see above in loop()). That means we
+       only shut down after one second of inactivity. */
+    block_sigs_onoff(1);
+
+    if (dbif_env_init() < 0)
+        exit(2); /* FIXME: same exit code as failure for dbif_open() */  
+    
+#ifdef CNID_BACKEND_DBD_TXN
+    if (dbif_txn_begin() < 0)
+       exit(6);
+#endif
+    
+    if (dbif_open(0) < 0) {
+#ifdef CNID_BACKEND_DBD_TXN
+       dbif_txn_abort();
+#endif
+        dbif_close();
+        exit(2);
+    }
+
+#ifndef CNID_BACKEND_DBD_TXN
+    if ((ret = dbd_check(dir))) {
+        if (ret < 0) {
+            dbif_close();
+            exit(2);
+        }
+        dbif_closedb();
+       LOG(log_info, logtype_cnid, "main: re-opening, secondaries will be rebuilt. This may take some time");
+        if (dbif_open(1) < 0) {
+           LOG(log_info, logtype_cnid, "main: re-opening databases failed");
+            dbif_close();
+            exit(2);
+        }
+       LOG(log_info, logtype_cnid, "main: rebuilt done");
+    }
+#endif
+
+#ifdef CNID_BACKEND_DBD_TXN
+    if (dbif_txn_commit() < 0)
+       exit(6);
+#endif
+
+#ifndef CNID_BACKEND_DBD_TXN
+    /* FIXME: Do we really need to sync before closing the DB? Just closing it
+       should be enough. */
+    if (dbif_sync() < 0)
+        err++;
+#endif
+
+    if (dbif_close() < 0)
+        err++;
+        
+    free_lock(lockfd);
+    
+    if (err)
+        exit(4);
+    return 0;
+}
index 1a320bfd6471bea25793997d44288d64ba7be2ab..bded38b16bad41dba02187ee0552e9a5a19c605a 100644 (file)
@@ -8,7 +8,8 @@ endif
 
 cnid_dbd_SOURCES = dbif.c pack.c comm.c db_param.c main.c \
                    dbd_add.c dbd_get.c dbd_resolve.c dbd_lookup.c \
-                   dbd_update.c dbd_delete.c dbd_getstamp.c
+                   dbd_update.c dbd_delete.c dbd_getstamp.c \
+                   dbd_dbcheck.c
 
 cnid_dbd_LDADD = $(top_builddir)/libatalk/libatalk.la
 
index acba65aa192ec218b785855051bcbdf48673b94b..a397be5300862daac075b4d9f737f4a455abeef9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: db_param.c,v 1.1.4.4 2004-04-29 18:09:14 lenneis Exp $
+ * $Id: db_param.c,v 1.1.4.4.2.1 2004-12-21 13:36:12 didg Exp $
  *
  * Copyright (C) Joerg Lenneis 2003
  * All Rights Reserved.  See COPYING.
@@ -38,6 +38,7 @@
 #define DEFAULT_USOCK_FILE         "usock"
 #define DEFAULT_FD_TABLE_SIZE      16
 #define DEFAULT_IDLE_TIMEOUT       600
+#define DEFAULT_CHECK              0
 
 static struct db_param params;
 static int parse_err;
@@ -71,14 +72,16 @@ static int make_pathname(char *path, char *dir, char *fn, int maxlen)
 
 static void default_params(struct db_param *dbp, char *dir)
 {        
+    dbp->check               = DEFAULT_CHECK;
     dbp->logfile_autoremove  = DEFAULT_LOGFILE_AUTOREMOVE;
     dbp->cachesize           = DEFAULT_CACHESIZE;
     dbp->nosync              = DEFAULT_NOSYNC;
     dbp->flush_frequency     = DEFAULT_FLUSH_FREQUENCY;
     dbp->flush_interval      = DEFAULT_FLUSH_INTERVAL;
-    if (make_pathname(dbp->usock_file, dir, DEFAULT_USOCK_FILE, usock_maxlen()) < 0)
+    if (make_pathname(dbp->usock_file, dir, DEFAULT_USOCK_FILE, usock_maxlen()) < 0) {
         /* Not an error yet, it might be set in the config file */
         dbp->usock_file[0] = '\0';
+    }
     dbp->fd_table_size       = DEFAULT_FD_TABLE_SIZE;
     dbp->idle_timeout        = DEFAULT_IDLE_TIMEOUT;
     return;
@@ -145,6 +148,8 @@ struct db_param *db_param_read(char *dir)
             params.cachesize = parse_int(val);
         else if (! strcmp(key, "nosync"))
             params.nosync = parse_int(val);
+        else if (! strcmp(key, "check"))
+            params.check = parse_int(val);
         else if (! strcmp(key, "flush_frequency"))
             params.flush_frequency = parse_int(val);
         else if (! strcmp(key, "flush_interval"))
index 15e055dab64276382c29f35d434f03b44cd29a6e..647ac2ed81d8ddd1f84ced0cd0f248e9a0b49b4d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: db_param.h,v 1.1.4.4 2004-04-29 18:09:16 lenneis Exp $
+ * $Id: db_param.h,v 1.1.4.4.2.1 2004-12-21 13:36:12 didg Exp $
  *
  * Copyright (C) Joerg Lenneis 2003
  * All Rights Reserved.  See COPYING.
@@ -13,6 +13,7 @@
 
 
 struct db_param {
+    int check;
     int logfile_autoremove;
     int cachesize;
     int nosync;
index 154e669961fd8dec9bf12a248274fe0b6e7c8833..2128a857f5514c35b960d906f262fd854a9bc1f8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: dbd.h,v 1.1.4.3 2004-01-09 21:05:50 lenneis Exp $
+ * $Id: dbd.h,v 1.1.4.3.2.1 2004-12-21 13:36:12 didg Exp $
  *
  * Copyright (C) Joerg Lenneis 2003
  * All Rights Reserved.  See COPYING.
@@ -19,5 +19,6 @@ extern int      dbd_lookup  __P((struct cnid_dbd_rqst *, struct cnid_dbd_rply *)
 extern int      dbd_update  __P((struct cnid_dbd_rqst *, struct cnid_dbd_rply *));
 extern int      dbd_delete  __P((struct cnid_dbd_rqst *, struct cnid_dbd_rply *));
 extern int      dbd_getstamp  __P((struct cnid_dbd_rqst *, struct cnid_dbd_rply *));
+extern int      dbd_check  __P((char *));
 
 #endif /* CNID_DBD_DBD_H */
diff --git a/etc/cnid_dbd/dbd_dbcheck.c b/etc/cnid_dbd/dbd_dbcheck.c
new file mode 100644 (file)
index 0000000..652bf2d
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * $Id: dbd_dbcheck.c,v 1.1.2.1 2004-12-21 13:36:12 didg Exp $
+ *
+ * Copyright (C) Joerg Lenneis 2003
+ * All Rights Reserved.  See COPYING.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/param.h>
+#include <errno.h>
+#include <netatalk/endian.h>
+#include <atalk/logger.h>
+#include <atalk/cnid_dbd_private.h>
+
+#include "pack.h"
+#include "dbif.h"
+#include "dbd.h"
+
+int dbd_check(char *dbdir)
+{
+    u_int32_t c_didname = 0, c_devino = 0, c_cnid = 0;
+#if 0
+    char dbdir[MAXPATHLEN];
+
+    if (NULL == getcwd(dbdir, sizeof(dbdir)) )
+        return -1;
+#endif
+
+    LOG(log_debug, logtype_cnid, "CNID database at `%s' is being checked (quick)", dbdir);
+
+    if (dbif_count(DBIF_IDX_CNID, &c_cnid)) 
+        return -1;
+
+    if (dbif_count(DBIF_IDX_DIDNAME, &c_didname)) 
+        return -1;
+    
+    /* bailout after the first error */
+    if (dbif_count(DBIF_IDX_DEVINO, &c_devino))
+        return -1;
+
+    if ( c_cnid != c_devino) {
+        LOG(log_error, logtype_cnid, "CNID database at `%s' corrupted (%u/%u)", dbdir, c_cnid, c_devino);
+        return 1;
+    }
+
+    if ( c_cnid != c_didname) {
+        LOG(log_error, logtype_cnid, "CNID database at `%s' corrupted (%u/%u)", dbdir, c_cnid, c_didname);
+        return 1;
+    }
+
+    LOG(log_debug, logtype_cnid, "CNID database at `%s' seems ok, %u entries.", dbdir, c_cnid);
+    return 0;  
+}
+
index 4518f2929b91507f0ec85972e7a0d34bdb687571..c7eda9bd8e5bd700d9747c5c49598d0ecd5dcb3f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: dbif.c,v 1.1.4.15 2004-04-29 18:09:16 lenneis Exp $
+ * $Id: dbif.c,v 1.1.4.15.2.1 2004-12-21 13:36:12 didg Exp $
  *
  * Copyright (C) Joerg Lenneis 2003
  * All Rights Reserved.  See COPYING.
@@ -11,6 +11,7 @@
 
 #include <stdio.h>
 #include <errno.h>
+#include <stdlib.h>
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
 #endif /* HAVE_SYS_TYPES_H */
@@ -232,10 +233,11 @@ int dbif_env_init(struct db_param *dbp)
 }
 
 /* --------------- */
-int dbif_open(struct db_param *dbp)
+int dbif_open(struct db_param *dbp, int do_truncate)
 {
     int ret;
     int i;
+    u_int32_t count;
 
     for (i = 0; i != DBIF_DB_CNT; i++) {
         if ((ret = db_create(&(db_table[i].db), db_env, 0))) {
@@ -243,6 +245,7 @@ int dbif_open(struct db_param *dbp)
                 db_table[i].name, db_strerror(ret));
             return -1;
         }
+
         if (db_table[i].general_flags) { 
             if ((ret = db_table[i].db->set_flags(db_table[i].db, db_table[i].general_flags))) {
                 LOG(log_error, logtype_cnid, "error setting flags for database %s: %s", 
@@ -250,6 +253,7 @@ int dbif_open(struct db_param *dbp)
                 return -1;
             }
         }
+
 #if 0
 #ifndef CNID_BACKEND_DBD_TXN
         if ((ret = db_table[i].db->set_cachesize(db_table[i].db, 0, 1024 * dbp->cachesize, 0))) {
@@ -263,17 +267,25 @@ int dbif_open(struct db_param *dbp)
             return -1;
         if (db_errlog != NULL)
             db_table[i].db->set_errfile(db_table[i].db, db_errlog);
+
+        if (do_truncate && i > 0) {
+           if ((ret = db_table[i].db->truncate(db_table[i].db, db_txn, &count, 0))) {
+                LOG(log_error, logtype_cnid, "error truncating database %s: %s", 
+                    db_table[i].name, db_strerror(ret));
+                return -1;
+            }
+        }
     }
-    
+
     /* TODO: Implement CNID DB versioning info on new databases. */
     /* TODO: Make transaction support a runtime option. */
     /* Associate the secondary with the primary. */
-    if ((ret = db_compat_associate(db_table[0].db, db_table[DBIF_IDX_DIDNAME].db, didname, 0)) != 0) {
+    if ((ret = db_compat_associate(db_table[0].db, db_table[DBIF_IDX_DIDNAME].db, didname, (do_truncate)?DB_CREATE:0)) != 0) {
         LOG(log_error, logtype_cnid, "Failed to associate didname database: %s",db_strerror(ret));
         return -1;
     }
  
-    if ((ret = db_compat_associate(db_table[0].db, db_table[DBIF_IDX_DEVINO].db, devino, 0)) != 0) {
+    if ((ret = db_compat_associate(db_table[0].db, db_table[DBIF_IDX_DEVINO].db, devino, (do_truncate)?DB_CREATE:0)) != 0) {
         LOG(log_error, logtype_cnid, "Failed to associate devino database: %s",db_strerror(ret));
        return -1;
     }
@@ -282,18 +294,32 @@ int dbif_open(struct db_param *dbp)
 }
 
 /* ------------------------ */
-int dbif_close()
+int dbif_closedb()
 {
     int i;
     int ret;
     int err = 0;
-     
+
     for (i = DBIF_DB_CNT -1; i >= 0; i--) {
         if (db_table[i].db != NULL && (ret = db_table[i].db->close(db_table[i].db, 0))) {
             LOG(log_error, logtype_cnid, "error closing database %s: %s", db_table[i].name, db_strerror(ret));
             err++;
         }
     }
+    if (err)
+        return -1;
+    return 0;
+}
+
+/* ------------------------ */
+int dbif_close()
+{
+    int ret;
+    int err = 0;
+    
+    if (dbif_closedb()) 
+       err++;
+     
     if (db_env != NULL && (ret = db_env->close(db_env, 0))) { 
         LOG(log_error, logtype_cnid, "error closing DB environment: %s", db_strerror(ret));
         err++;
@@ -304,8 +330,7 @@ int dbif_close()
     }
     if (err)
         return -1;
-    else
-        return 0;
+    return 0;
 }
 
 /*
@@ -482,5 +507,24 @@ int dbif_sync()
         return 0;
 }
 
+
+int dbif_count(const int dbi, u_int32_t *count) 
+{
+    int ret;
+    DB_BTREE_STAT *sp;
+    DB *db = db_table[dbi].db;
+
+    ret = db->stat(db, &sp, 0);
+
+    if (ret) {
+        LOG(log_error, logtype_cnid, "error getting stat infotmation on database: %s", db_strerror(errno));
+        return -1;
+    }
+
+    *count = sp->bt_ndata;
+    free(sp);
+
+    return 0;
+}
 #endif /* CNID_BACKEND_DBD_TXN */
 
index deab292db0552a7d92cd76725135dc63527c5f16..89012a2cd364f13b7a5d59b442eec2b3dbc35484 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: dbif.h,v 1.1.4.6 2004-01-09 21:05:50 lenneis Exp $
+ * $Id: dbif.h,v 1.1.4.6.2.1 2004-12-21 13:36:12 didg Exp $
  *
  * Copyright (C) Joerg Lenneis 2003
  * All Rights Reserved.  See COPYING.
 
 extern int        dbif_stamp  __P((void *, int));
 extern int        dbif_env_init  __P((struct db_param *));
-extern int        dbif_open  __P((struct db_param *));
+extern int        dbif_open  __P((struct db_param *, int));
 extern int        dbif_close __P((void));
+extern int        dbif_closedb __P((void));
 extern int        dbif_get __P((const int, DBT *, DBT *, u_int32_t));
 extern int        dbif_pget __P((const int, DBT *, DBT *, DBT *, u_int32_t));
 extern int        dbif_put __P((const int, DBT *, DBT *, u_int32_t));
 extern int        dbif_del __P((const int, DBT *, u_int32_t));
 
+extern int        dbif_count __P((const int, u_int32_t *));
+
+
 #ifdef CNID_BACKEND_DBD_TXN
 extern int        dbif_txn_begin  __P((void));
 extern int        dbif_txn_commit  __P((void));
index cfd13f73ef6b066943bb8122fd454009ae44c581..e45adb076d9de1b462b02a6929a1de5202ccb56e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: main.c,v 1.1.4.10.2.1 2004-12-11 12:38:20 didg Exp $
+ * $Id: main.c,v 1.1.4.10.2.2 2004-12-21 13:36:12 didg Exp $
  *
  * Copyright (C) Joerg Lenneis 2003
  * All Rights Reserved.  See COPYING.
@@ -279,6 +279,7 @@ int main(int argc, char *argv[])
 {
     struct db_param *dbp;
     int err = 0;
+    int ret;
     int lockfd, ctrlfd, clntfd;
     char *dir;
        
@@ -320,13 +321,31 @@ int main(int argc, char *argv[])
        exit(6);
 #endif
     
-    if (dbif_open(dbp) < 0) {
+    if (dbif_open(dbp, 0) < 0) {
 #ifdef CNID_BACKEND_DBD_TXN
        dbif_txn_abort();
 #endif
         dbif_close();
         exit(2);
     }
+
+#ifndef CNID_BACKEND_DBD_TXN
+    if (dbp->check && (ret = dbd_check(dir))) {
+        if (ret < 0) {
+            dbif_close();
+            exit(2);
+        }
+        dbif_closedb();
+       LOG(log_info, logtype_cnid, "main: re-opening, secondaries will be rebuilt. This may take some time");
+        if (dbif_open(dbp, 1) < 0) {
+           LOG(log_info, logtype_cnid, "main: re-opening databases failed");
+            dbif_close();
+            exit(2);
+        }
+       LOG(log_info, logtype_cnid, "main: rebuilt done");
+    }
+#endif
+
     if (dbd_stamp() < 0) {
 #ifdef CNID_BACKEND_DBD_TXN
        dbif_txn_abort();