X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=libatalk%2Fcnid%2Fcnid_open.c;h=7b7d065c6bf6c1aece299d3ab45c2bf6f49396bc;hb=c3ebdbc0834268f9ca598a6208c1659f34f759ef;hp=10dda27de6166c2ac83023d2a39a34f92b64a4d3;hpb=31843674b7bd32eabcce3a1ad6159b4f94921f79;p=netatalk.git diff --git a/libatalk/cnid/cnid_open.c b/libatalk/cnid/cnid_open.c index 10dda27d..7b7d065c 100644 --- a/libatalk/cnid/cnid_open.c +++ b/libatalk/cnid/cnid_open.c @@ -1,4 +1,6 @@ -/* +/* + * $Id: cnid_open.c,v 1.34 2002-01-21 04:48:14 jmarcus Exp $ + * * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu) * All Rights Reserved. See COPYRIGHT. * @@ -28,16 +30,30 @@ * 1 -- parent of root directory (handled by afpd) * 2 -- root directory (handled by afpd) * - * so, CNID_START begins at 3. + * CNIDs 4-16 are reserved according to page 31 of the AFP 3.0 spec so, + * CNID_START begins at 17. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + +#ifdef CNID_DB +#include #include #include +#ifdef HAVE_UNISTD_H #include +#endif /* HAVE_UNISTD_H */ +#ifdef HAVE_FCNTL_H #include +#endif /* HAVE_FCNTL_H */ #include #include -#include +#include +#ifdef HAVE_SYS_TIME_H +#include +#endif /* HAVE_SYS_TIME_H */ #include @@ -49,19 +65,18 @@ #ifndef MIN #define MIN(a, b) ((a) < (b) ? (a) : (b)) -#endif - -#define ROOTINFO "RootInfo" -#define ROOTINFO_LEN 8 - -#define DBHOME ".AppleDB" -#define DBCNID "cnid.db" -#define DBDEVINO "devino.db" -#define DBDIDNAME "didname.db" /* did/full name mapping */ -#define DBSHORTNAME "shortname.db" /* did/8+3 mapping */ -#define DBMACNAME "macname.db" /* did/31 mapping */ -#define DBLONGNAME "longname.db" /* did/unicode mapping */ -#define DBLOCKFILE "/cnid.lock" +#endif /* ! MIN */ + +#define DBHOME ".AppleDB" +#define DBCNID "cnid.db" +#define DBDEVINO "devino.db" +#define DBDIDNAME "didname.db" /* did/full name mapping */ +#define DBSHORTNAME "shortname.db" /* did/8+3 mapping */ +#define DBMACNAME "macname.db" /* did/31 mapping */ +#define DBLONGNAME "longname.db" /* did/unicode mapping */ +#define DBLOCKFILE "cnid.lock" +#define DBRECOVERFILE "cnid.dbrecover" +#define DBCLOSEFILE "cnid.close" #define DBHOMELEN 8 #define DBLEN 10 @@ -74,296 +89,501 @@ #define DBVERSION1 0x00000001U #define DBVERSION DBVERSION1 +#if DB_VERSION_MINOR > 1 +#define DBOPTIONS (DB_CREATE | DB_INIT_MPOOL | DB_INIT_LOCK | \ +DB_INIT_LOG | DB_INIT_TXN) +#else /* DB_VERSION_MINOR < 1 */ +/*#define DBOPTIONS (DB_CREATE | DB_INIT_MPOOL | DB_INIT_LOCK | \ +DB_INIT_LOG | DB_INIT_TXN | DB_TXN_NOSYNC)*/ #define DBOPTIONS (DB_CREATE | DB_INIT_MPOOL | DB_INIT_LOCK | \ -DB_INIT_LOG | DB_INIT_TXN | DB_TXN_NOSYNC | DB_RECOVER) +DB_INIT_LOG | DB_INIT_TXN) +#endif /* DB_VERSION_MINOR */ -#define MAXITER 0xFFFF /* maximum number of simultaneously open CNID - * databases. */ +/* Let's try and use the youngest lock detector if present. + * If we can't do that, then let DB3 use its default deadlock detector. */ +#if defined DB_LOCK_YOUNGEST +#define DEAD_LOCK_DETECT DB_LOCK_YOUNGEST +#else /* DB_LOCK_YOUNGEST */ +#define DEAD_LOCK_DETECT DB_LOCK_DEFAULT +#endif /* DB_LOCK_YOUNGEST */ + +#define MAXITER 0xFFFF /* maximum number of simultaneously open CNID +* databases. */ /* the first compare that's always done. */ static __inline__ int compare_did(const DBT *a, const DBT *b) { - u_int32_t dida, didb; + u_int32_t dida, didb; - memcpy(&dida, a->data, sizeof(dida)); - memcpy(&didb, b->data, sizeof(didb)); - return dida - didb; + memcpy(&dida, a->data, sizeof(dida)); + memcpy(&didb, b->data, sizeof(didb)); + return dida - didb; } /* sort did's and then names. this is for unix paths. * i.e., did/unixname lookups. */ +#if DB_VERSION_MINOR > 1 +static int compare_unix(DB *db, const DBT *a, const DBT *b) +#else /* DB_VERSION_MINOR < 1 */ static int compare_unix(const DBT *a, const DBT *b) +#endif /* DB_VERSION_MINOR */ { - u_int8_t *sa, *sb; - int len, ret; - - /* sort by did */ - if (ret = compare_did(a, b)) - return ret; - - sa = a->data + 4; /* shift past did */ - sb = b->data + 4; - for (len = MIN(a->size, b->size); len-- > 4; sa++, sb++) - if (ret = (*sa - *sb)) - return ret; /* sort by lexical ordering */ - return a->size - b->size; /* sort by length */ + u_int8_t *sa, *sb; + int len, ret; + + /* sort by did */ + if ((ret = compare_did(a, b))) + return ret; + + sa = (u_int8_t *) a->data + 4; /* shift past did */ + sb = (u_int8_t *) b->data + 4; + for (len = MIN(a->size, b->size); len-- > 4; sa++, sb++) + if ((ret = (*sa - *sb))) + return ret; /* sort by lexical ordering */ + + return a->size - b->size; /* sort by length */ } /* sort did's and then names. this is for macified paths (i.e., * did/macname, and did/shortname. i think did/longname needs a * unicode table to work. also, we can't use strdiacasecmp as that * returns a match if a < b. */ -static int compare_mac(const DBT *a, const DBT *b) +#if DB_VERSION_MINOR > 1 +static int compare_mac(DB *db, const DBT *a, const DBT *b) +#else /* DB_VERSION_MINOR < 1 */ +static int compare_mac(const DBT *a, const DBT *b) +#endif /* DB_VERSION_MINOR */ { - u_int8_t *sa, *sb; - int len, ret; - - /* sort by did */ - if (ret = compare_did(a, b)) - return ret; - - sa = a->data + 4; - sb = b->data + 4; - for (len = MIN(a->size, b->size); len-- > 4; sa++, sb++) - if (ret = (_diacasemap[*sa] - _diacasemap[*sb])) - return ret; /* sort by lexical ordering */ - return a->size - b->size; /* sort by length */ + u_int8_t *sa, *sb; + int len, ret; + + /* sort by did */ + if ((ret = compare_did(a, b))) + return ret; + + sa = (u_int8_t *) a->data + 4; + sb = (u_int8_t *) b->data + 4; + for (len = MIN(a->size, b->size); len-- > 4; sa++, sb++) + if ((ret = (_diacasemap[*sa] - _diacasemap[*sb]))) + return ret; /* sort by lexical ordering */ + + return a->size - b->size; /* sort by length */ } /* for unicode names -- right now it's the same as compare_mac. */ -#define compare_unicode(a, b) compare_mac((a), (b)) - -void *cnid_open(const char *dir) +#if DB_VERSION_MINOR > 1 +static int compare_unicode(DB *db, const DBT *a, const DBT *b) +#else /* DB_VERSION_MINOR < 1 */ +static int compare_unicode(const DBT *a, const DBT *b) +#endif /* DB_VERSION_MINOR */ { - struct stat st; - struct flock lock; - char path[MAXPATHLEN + 1]; - CNID_private *db; - DB_INFO dbi; - DBT key, data; - int open_flag, len; - - if (!dir) - return NULL; +#if DB_VERSION_MINOR > 1 + return compare_mac(db,a,b); +#else /* DB_VERSION_MINOR < 1 */ + return compare_mac(a,b); +#endif /* DB_VERSION_MINOR */ +} - /* this checks both RootInfo and .AppleDB */ - if ((len = strlen(dir)) > (MAXPATHLEN - DBLEN - 1)) { - syslog(LOG_ERR, "cnid_open: path too large"); - return NULL; - } - - if ((db = (CNID_private *) calloc(1, sizeof(CNID_private))) == NULL) { - syslog(LOG_ERR, "cnid_open: unable to allocate memory"); - return NULL; - } - db->magic = CNID_DB_MAGIC; - - strcpy(path, dir); - if (path[len - 1] != '/') { +static int have_lock = 0; + +void *cnid_open(const char *dir) { + struct stat st, rsb, csb; + struct flock lock; + char path[MAXPATHLEN + 1]; + char recover_file[MAXPATHLEN + 1]; + CNID_private *db; + DBT key, data; + DB_TXN *tid; + u_int32_t DBEXTRAS = 0; + int open_flag, len; + int rc, rfd = -1; + + if (!dir) { + return NULL; + } + + /* this checks .AppleDB */ + if ((len = strlen(dir)) > (MAXPATHLEN - DBLEN - 1)) { + LOG(log_error, logtype_default, "cnid_open: Pathname too large: %s", dir); + return NULL; + } + + if ((db = (CNID_private *)calloc(1, sizeof(CNID_private))) == NULL) { + LOG(log_error, logtype_default, "cnid_open: Unable to allocate memory for database"); + return NULL; + } + + db->magic = CNID_DB_MAGIC; + + strcpy(path, dir); + if (path[len - 1] != '/') { + strcat(path, "/"); + len++; + } + + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + + strcpy(path + len, DBHOME); + if ((stat(path, &st) < 0) && (ad_mkdir(path, 0777) < 0)) { + LOG(log_error, logtype_default, "cnid_open: DBHOME mkdir failed for %s", path); + goto fail_adouble; + } + + /* Make sure cnid.lock goes in .AppleDB. */ strcat(path, "/"); len++; - } - - lock.l_type = F_WRLCK; - lock.l_whence = SEEK_SET; - - /* we create and initialize RootInfo if it doesn't exist. */ - strcat(path, ROOTINFO); - if (ad_open(path, ADFLAGS_HF, O_RDWR, 0666, &db->rootinfo) < 0) { - cnid_t id; - - /* see if we can open it read-only. if it's read-only, we can't - * add CNIDs. */ - memset(&db->rootinfo, 0, sizeof(db->rootinfo)); - if (ad_open(path, ADFLAGS_HF, O_RDONLY, 0666, &db->rootinfo) == 0) { - db->flags = CNIDFLAG_ROOTINFO_RO; - syslog(LOG_INFO, "cnid_open: read-only RootInfo"); - goto mkdir_appledb; - } - - /* create the file */ - memset(&db->rootinfo, 0, sizeof(db->rootinfo)); - if (ad_open(path, ADFLAGS_HF, O_CREAT | O_RDWR, 0666, - &db->rootinfo) < 0) { - syslog(LOG_ERR, "cnid_open: ad_open(RootInfo)"); - goto fail_db; - } - - /* lock the RootInfo file. this and cnid_add are the only places - * that should fiddle with RootInfo. */ - lock.l_start = ad_getentryoff(&db->rootinfo, ADEID_DID); - lock.l_len = ad_getentrylen(&db->rootinfo, ADEID_DID); - if (fcntl(ad_hfileno(&db->rootinfo), F_SETLKW, &lock) < 0) { - syslog(LOG_ERR, "cnid_open: can't establish lock: %m"); - goto fail_adouble; - } - - /* store the beginning CNID */ - id = htonl(CNID_START); - memcpy(ad_entry(&db->rootinfo, ADEID_DID), &id, sizeof(id)); - ad_flush(&db->rootinfo, ADFLAGS_HF); - - /* unlock it */ - lock.l_type = F_UNLCK; - fcntl(ad_hfileno(&db->rootinfo), F_SETLK, &lock); - lock.l_type = F_WRLCK; - } - -mkdir_appledb: - strcpy(path + len, DBHOME); - if ((stat(path, &st) < 0) && (ad_mkdir(path, 0777) < 0)) { - syslog(LOG_ERR, "cnid_open: mkdir failed"); - goto fail_adouble; - } - - /* search for a byte lock. this allows us to cleanup the log files - * at cnid_close() in a clean fashion. - * - * NOTE: this won't work if multiple volumes for the same user refer - * to the same directory. */ - strcat(path, DBLOCKFILE); - if ((db->lockfd = open(path, O_RDWR | O_CREAT, 0666)) > -1) { - lock.l_start = 0; - lock.l_len = 1; - while (fcntl(db->lockfd, F_SETLK, &lock) < 0) { - if (++lock.l_start > MAXITER) { - syslog(LOG_INFO, "cnid_open: can't establish logfile cleanup lock."); - close(db->lockfd); - db->lockfd = -1; - break; - } - } - } - - path[len + DBHOMELEN] = '\0'; - open_flag = DB_CREATE; - /* try a full-blown transactional environment */ - if (db_appinit(path, NULL, &db->dbenv, DBOPTIONS)) { - - /* try with a shared memory pool */ - memset(&db->dbenv, 0, sizeof(db->dbenv)); - if (db_appinit(path, NULL, &db->dbenv, DB_INIT_MPOOL)) { - - /* try without any options. */ - memset(&db->dbenv, 0, sizeof(db->dbenv)); - if (db_appinit(path, NULL, &db->dbenv, 0)) { - syslog(LOG_ERR, "cnid_open: db_appinit failed"); - goto fail_lock; - } - } - db->flags |= CNIDFLAG_DB_RO; - open_flag = DB_RDONLY; - syslog(LOG_INFO, "cnid_open: read-only CNID database"); - } - - memset(&dbi, 0, sizeof(dbi)); - - /* did/name reverse mapping. we use a btree for this one. */ - dbi.bt_compare = compare_unix; - if (db_open(DBDIDNAME, DB_BTREE, open_flag, 0666, &db->dbenv, &dbi, - &db->db_didname)) { - goto fail_appinit; - } - - /* check for version. this way we can update the database if we need - to change the format in any way. */ - memset(&key, 0, sizeof(key)); - memset(&data, 0, sizeof(data)); - key.data = DBVERSION_KEY; - key.len = DBVERSION_KEY_LEN; - while (errno = db->db_didname->get(db->db_didname, NULL, &key, &data, 0)) { - switch (errno) { - case EAGAIN: - continue; - - case DB_NOTFOUND: - u_int32_t version = htonl(DBVERSION); - - data.data = &version; - data.len = sizeof(version); -dbversion_retry: - if (db->db_didname->put(db->db_didname, NULL, &key, &data, - DB_NOOVERWRITE)) - if (errno == EAGAIN) - goto dbversion_retry; - break; - default: - /* uh oh. something bad happened. bail. */ - db->db_didname->close(db->db_didname, 0); - goto fail_appinit; - } - } - - /* XXX: in the future, we might check for version number here. */ + + strcpy(db->close_file, path); + strcat(db->close_file, DBCLOSEFILE); + + /* Check to make sure that a client isn't in the process of closing + * the database environment. To do this, select on the close file. */ + while(stat(db->close_file, &csb) == 0) { + struct timeval ct; + ct.tv_sec = 1; + ct.tv_usec = 0; + (void)select(0, NULL, NULL, NULL, &ct); + } + + strcpy(recover_file, path); + strcat(recover_file, DBRECOVERFILE); + + /* Search for a byte lock. This allows us to cleanup the log files + * at cnid_close() in a clean fashion. + * + * NOTE: This won't work if multiple volumes for the same user refer + * to the sahe directory. */ + strcat(path, DBLOCKFILE); + if ((db->lockfd = open(path, O_RDWR | O_CREAT, 0666)) > -1) { + lock.l_start = 0; + lock.l_len = 1; + while (fcntl(db->lockfd, F_SETLK, &lock) < 0) { + if (++lock.l_start > MAXITER) { + LOG(log_error, logtype_default, "cnid_open: Cannot establish logfile cleanup for database environment %s lock (lock failed)", path); + close(db->lockfd); + db->lockfd = -1; + break; + } + } + } + else { + LOG(log_error, logtype_default, "cnid_open: Cannot establish logfile cleanup lock for database environment %s (open() failed)", path); + } + + /* Create a file to represent database recovery. While this file + * exists, the database is being recovered, and all other clients will + * select until recovery is complete, and this file goes away. */ + if (!have_lock && db->lockfd > -1 && lock.l_start == 0) { + if (stat(recover_file, &rsb) == 0) { + (void)remove(recover_file); + } + if ((rfd = open(recover_file, O_RDWR | O_CREAT, 0666)) > -1) { + DBEXTRAS |= DB_RECOVER; + have_lock = 1; + } + } + else if (!have_lock) { + while (stat(recover_file, &rsb) == 0) { + struct timeval rt; + rt.tv_sec = 1; + rt.tv_usec = 0; + (void)select(0, NULL, NULL, NULL, &rt); + } + } + + path[len + DBHOMELEN] = '\0'; + open_flag = DB_CREATE; + + /* We need to be able to open the database environment with full + * transaction, logging, and locking support if we ever hope to + * be a true multi-acess file server. */ + if ((rc = db_env_create(&db->dbenv, 0)) != 0) { + LOG(log_error, logtype_default, "cnid_open: db_env_create: %s", db_strerror(rc)); + goto fail_lock; + } + + /* Setup internal deadlock detection. */ + if ((rc = db->dbenv->set_lk_detect(db->dbenv, DEAD_LOCK_DETECT)) != 0) { + LOG(log_error, logtype_default, "cnid_open: set_lk_detect: %s", db_strerror(rc)); + goto fail_lock; + } + +#if DB_VERSION_MINOR > 1 #if 0 - memcpy(&version, data.data, sizeof(version)); - if (version != htonl(DBVERSION)) { - /* fix up stuff */ - } + /* Take care of setting the DB_TXN_NOSYNC flag in db3 > 3.1.x. */ + if ((rc = db->dbenv->set_flags(db->dbenv, DB_TXN_NOSYNC, 1)) != 0) { + LOG(log_error, logtype_default, "cnid_open: set_flags: %s", db_strerror(rc)); + goto fail_lock; + } #endif +#endif /* DB_VERSION_MINOR > 1 */ + + /* Open the database environment. */ + if ((rc = db->dbenv->open(db->dbenv, path, DBOPTIONS | DBEXTRAS, 0666)) != 0) { + if (rc == DB_RUNRECOVERY) { + /* This is the mother of all errors. We _must_ fail here. */ + LOG(log_error, logtype_default, "cnid_open: CATASTROPHIC ERROR opening database environment %s. Run db_recovery -c immediately", path); + goto fail_lock; + } + + /* We can't get a full transactional environment, so multi-access + * is out of the question. Let's assume a read-only environment, + * and try to at least get a shared memory pool. */ + if ((rc = db->dbenv->open(db->dbenv, path, DB_INIT_MPOOL, 0666)) != 0) { + /* Nope, not a MPOOL, either. Last-ditch effort: we'll try to + * open the environment with no flags. */ + if ((rc = db->dbenv->open(db->dbenv, path, 0, 0666)) != 0) { + LOG(log_error, logtype_default, "cnid_open: dbenv->open of %s failed: %s", + path, db_strerror(rc)); + goto fail_lock; + } + } + db->flags |= CNIDFLAG_DB_RO; + open_flag = DB_RDONLY; + LOG(log_info, logtype_default, "cnid_open: Obtained read-only database environment %s", path); + } + + /* If we have the recovery lock, close the file, remove it, so other + * clients can proceed opening the DB environment. */ + if (rfd > -1) { + (void)remove(recover_file); + switch(errno) { + case 0: + case ENOENT: + break; + default: + LOG(log_error, logtype_default, "cnid_open: Unable to remove %s: %s", + recover_file, strerror(errno)); + } + close(rfd); + rfd = -1; + } + + /* did/name reverse mapping. We use a BTree for this one. */ + if ((rc = db_create(&db->db_didname, db->dbenv, 0)) != 0) { + LOG(log_error, logtype_default, "cnid_open: Failed to create did/name database: %s", + db_strerror(rc)); + goto fail_appinit; + } + + /*db->db_didname->set_bt_compare(db->db_didname, &compare_unix);*/ + if ((rc = db->db_didname->open(db->db_didname, DBDIDNAME, NULL, + DB_HASH, open_flag, 0666))) { + LOG(log_error, logtype_default, "cnid_open: Failed to open did/name database: %s", + db_strerror(rc)); + goto fail_appinit; + } + + /* Check for version. This way we can update the database if we need + * to change the format in any way. */ + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + key.data = DBVERSION_KEY; + key.size = DBVERSION_KEYLEN; + +dbversion_retry: + if ((rc = txn_begin(db->dbenv, NULL, &tid, 0)) != 0) { + LOG(log_error, logtype_default, "cnid_open: txn_begin: failed to check db version: %s", + db_strerror(rc)); + db->db_didname->close(db->db_didname, 0); + goto fail_appinit; + } + + while ((rc = db->db_didname->get(db->db_didname, tid, &key, &data, DB_RMW))) { + int ret; + switch (rc) { + case DB_LOCK_DEADLOCK: + if ((ret = txn_abort(tid)) != 0) { + LOG(log_error, logtype_default, "cnid_open: txn_abort: %s", db_strerror(ret)); + db->db_didname->close(db->db_didname, 0); + goto fail_appinit; + } + goto dbversion_retry; + case DB_NOTFOUND: + { + u_int32_t version = htonl(DBVERSION); + + data.data = &version; + data.size = sizeof(version); + } + + if ((ret = db->db_didname->put(db->db_didname, tid, &key, &data, + DB_NOOVERWRITE))) { + if (ret == DB_LOCK_DEADLOCK) { + if ((ret = txn_abort(tid)) != 0) { + LOG(log_error, logtype_default, "cnid_open: txn_abort: %s", + db_strerror(ret)); + db->db_didname->close(db->db_didname, 0); + goto fail_appinit; + } + goto dbversion_retry; + } + else if (ret == DB_RUNRECOVERY) { + /* At this point, we don't care if the transaction aborts + * successfully or not. */ + txn_abort(tid); + LOG(log_error, logtype_default, "cnid_open: Error putting new version: %s", + db_strerror(ret)); + db->db_didname->close(db->db_didname, 0); + goto fail_appinit; + } + } + break; /* while loop */ + default: + txn_abort(tid); + LOG(log_error, logtype_default, "cnid_open: Failed to check db version: %s", + db_strerror(rc)); + db->db_didname->close(db->db_didname, 0); + goto fail_appinit; + } + } + + if ((rc = txn_commit(tid, 0)) != 0) { + LOG(log_error, logtype_default, "cnid_open: Failed to commit db version: %s", + db_strerror(rc)); + db->db_didname->close(db->db_didname, 0); + goto fail_appinit; + } + + /* TODO In the future we might check for version number here. */ +#if 0 + memcpy(&version, data.data, sizeof(version)); + if (version != ntohl(DBVERSION)) { + /* Do stuff here. */ + } +#endif /* 0 */ + +#ifdef EXTENDED_DB + /* did/macname (31 character) mapping. Use a BTree for this one. */ + if ((rc = db_create(&db->db_macname, db->dbenv, 0)) != 0) { + LOG(log_error, logtype_default, "cnid_open: Failed to create did/macname database: %s", + db_strerror(rc)); + db->db_didname->close(db->db_didname, 0); + goto fail_appinit; + } + + db->db_macname->set_bt_compare(db->db_macname, &compare_mac); + if ((rc = db->db_macname->open(db->db_macname, DBMACNAME, NULL, DB_BTREE, open_flag, 0666)) != 0) { + LOG(log_error, logtype_default, "cnid_open: Failed to open did/macname database: %s", + db_strerror(rc)); + db->db_didname->close(db->db_didname, 0); + goto fail_appinit; + } + + /* did/shortname (DOS 8.3) mapping. Use a BTree for this one. */ + if ((rc = db_create(&db->db_shortname, db->dbenv, 0)) != 0) { + LOG(log_error, logtype_default, "cnid_open: Failed to create did/shortname database: %s", + db_strerror(rc)); + db->db_didname->close(db->db_didname, 0); + db->db_macname->close(db->db_macname, 0); + goto fail_appinit; + } + + db->db_shortname->set_bt_compare(db->db_shortname, &compare_mac); + if ((rc = db->db_shortname->open(db->db_shortname, DBSHORTNAME, NULL, DB_BTREE, open_flag, 0666)) != 0) { + LOG(log_error, logtype_default, "cnid_open: Failed to open did/shortname database: %s", + db_strerror(rc)); + db->db_didname->close(db->db_didname, 0); + db->db_macname->close(db->db_macname, 0); + goto fail_appinit; + } + + /* did/longname (Unicode) mapping. Use a BTree for this one. */ + if ((rc = db_create(&db->db_longname, db->dbenv, 0)) != 0) { + LOG(log_error, logtype_default, "cnid_open: Failed to create did/longname database: %s", + db_strerror(rc)); + db->db_didname->close(db->db_didname, 0); + db->db_macname->close(db->db_macname, 0); + db->db_shortname->close(db->db_shortname, 0); + goto fail_appinit; + } + + db->db_longname->set_bt_compare(db->db_longname, &compare_unicode); + if ((rc = db->db_longname->open(db->db_longname, DBLONGNAME, NULL, DB_BTREE, open_flag, 0666)) != 0) { + LOG(log_error, logtype_default, "cnid_open: Failed to open did/longname database: %s", + db_strerror(rc)); + db->db_didname->close(db->db_didname, 0); + db->db_macname->close(db->db_macname, 0); + db->db_shortname->close(db->db_shortname, 0); + goto fail_appinit; + } +#endif /* EXTENDED_DB */ + + /* dev/ino reverse mapping. Use a hash for this one. */ + if ((rc = db_create(&db->db_devino, db->dbenv, 0)) != 0) { + LOG(log_error, logtype_default, "cnid_open: Failed to create dev/ino database: %s", + db_strerror(rc)); + db->db_didname->close(db->db_didname, 0); +#ifdef EXTENDED_DB + db->db_macname->close(db->db_macname, 0); + db->db_shortname->close(db->db_shortname, 0); + db->db_longname->close(db->db_longname, 0); +#endif /* EXTENDED_DB */ + goto fail_appinit; + } + + if ((rc = db->db_devino->open(db->db_devino, DBDEVINO, NULL, DB_HASH, open_flag, 0666)) != 0) { + LOG(log_error, logtype_default, "cnid_open: Failed to open devino database: %s", + db_strerror(rc)); + db->db_didname->close(db->db_didname, 0); +#ifdef EXTENDED_DB + db->db_macname->close(db->db_macname, 0); + db->db_shortname->close(db->db_shortname, 0); + db->db_longname->close(db->db_longname, 0); +#endif /* EXTENDED_DB */ + goto fail_appinit; + } + + /* Main CNID database. Use a hash for this one. */ + if ((rc = db_create(&db->db_cnid, db->dbenv, 0)) != 0) { + LOG(log_error, logtype_default, "cnid_open: Failed to create cnid database: %s", + db_strerror(rc)); + db->db_didname->close(db->db_didname, 0); +#ifdef EXTENDED_DB + db->db_macname->close(db->db_macname, 0); + db->db_shortname->close(db->db_shortname, 0); + db->db_longname->close(db->db_longname, 0); +#endif /* EXTENDED_DB */ + db->db_devino->close(db->db_devino, 0); + goto fail_appinit; + } + + + if ((rc = db->db_cnid->open(db->db_cnid, DBCNID, NULL, DB_HASH, open_flag, 0666)) != 0) { + LOG(log_error, logtype_default, "cnid_open: Failed to open dev/ino database: %s", + db_strerror(rc)); + db->db_didname->close(db->db_didname, 0); +#ifdef EXTENDED_DB + db->db_macname->close(db->db_macname, 0); + db->db_shortname->close(db->db_shortname, 0); + db->db_longname->close(db->db_longname, 0); +#endif /* EXTENDED_DB */ + goto fail_appinit; + } + + return db; - /* did/macname mapping. btree this one. */ - dbi.bt_compare = compare_mac; - if (db_open(DBMACNAME, DB_BTREE, open_flag, 0666, &db->dbenv, &dbi, - &db->db_macname)) { - db->db_didname->close(db->db_didname, 0); - goto fail_appinit; - } - - /* did/shortname mapping */ - if (db_open(DBSHORTNAME, DB_BTREE, open_flag, 0666, &db->dbenv, &dbi, - &db->db_shortname)) { - db->db_didname->close(db->db_didname, 0); - db->db_macname->close(db->db_macname, 0); - goto fail_appinit; - } - - /* did/longname mapping */ - dbi.bt_compare = compare_unicode; - if (db_open(DBLONGNAME, DB_BTREE, open_flag, 0666, &db->dbenv, &dbi, - &db->db_longname)) { - db->db_didname->close(db->db_didname, 0); - db->db_macname->close(db->db_macname, 0); - db->db_shortname->close(db->db_shortname, 0); - goto fail_appinit; - } - - /* dev/ino reverse mapping. we hash this one. */ - dbi.bt_compare = NULL; - if (db_open(DBDEVINO, DB_HASH, open_flag, 0666, &db->dbenv, &dbi, - &db->db_devino)) { - db->db_didname->close(db->db_didname, 0); - db->db_macname->close(db->db_macname, 0); - db->db_shortname->close(db->db_shortname, 0); - db->db_longname->close(db->db_longname, 0); - goto fail_appinit; - } - - /* main cnid database. we hash this one as well. */ - if (db_open(DBCNID, DB_HASH, open_flag, 0666, &db->dbenv, &dbi, - &db->db_cnid)) { - db->db_didname->close(db->db_didname, 0); - db->db_macname->close(db->db_macname, 0); - db->db_shortname->close(db->db_shortname, 0); - db->db_longname->close(db->db_longname, 0); - db->db_devino->close(db->db_devino, 0); - goto fail_appinit; - } - return db; - fail_appinit: - syslog(LOG_ERR, "cnid_open: db_open failed"); - db_appexit(&db->dbenv); + LOG(log_error, logtype_default, "cnid_open: Failed to setup CNID DB environment"); + db->dbenv->close(db->dbenv, 0); fail_lock: - if (db->lockfd > -1) - close(db->lockfd); + if (db->lockfd > -1) { + close(db->lockfd); + } + if (rfd > -1) { + (void)remove(recover_file); + close(rfd); + } fail_adouble: - ad_close(&db->rootinfo, ADFLAGS_HF); fail_db: - free(db); - return NULL; + free(db); + return NULL; } +#endif /* CNID_DB */ + +