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=fa8ed2a8e6311f727cf7e99dc79790d8af35614e;hpb=f1c2f1b1a3f55ca6b6ae87b3fcb2562038b613cc;p=netatalk.git diff --git a/libatalk/cnid/cnid_open.c b/libatalk/cnid/cnid_open.c index fa8ed2a8..7b7d065c 100644 --- a/libatalk/cnid/cnid_open.c +++ b/libatalk/cnid/cnid_open.c @@ -1,5 +1,5 @@ /* - * $Id: cnid_open.c,v 1.9 2001-09-18 22:21:47 jmarcus Exp $ + * $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. @@ -30,7 +30,8 @@ * 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 @@ -49,7 +50,10 @@ #endif /* HAVE_FCNTL_H */ #include #include -#include +#include +#ifdef HAVE_SYS_TIME_H +#include +#endif /* HAVE_SYS_TIME_H */ #include @@ -63,14 +67,16 @@ #define MIN(a, b) ((a) < (b) ? (a) : (b)) #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 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 @@ -85,47 +91,57 @@ #if DB_VERSION_MINOR > 1 #define DBOPTIONS (DB_CREATE | DB_INIT_MPOOL | DB_INIT_LOCK | \ -DB_INIT_LOG | DB_INIT_TXN | DB_RECOVER) -#else +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) -#endif +DB_INIT_LOG | DB_INIT_TXN) +#endif /* DB_VERSION_MINOR */ + +/* 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. */ +* 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 +#else /* DB_VERSION_MINOR < 1 */ static int compare_unix(const DBT *a, const DBT *b) -#endif +#endif /* DB_VERSION_MINOR */ { - u_int8_t *sa, *sb; - int len, ret; + u_int8_t *sa, *sb; + int len, ret; - /* sort by did */ - if ((ret = compare_did(a, b))) - return 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 */ + 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 */ + return a->size - b->size; /* sort by length */ } /* sort did's and then names. this is for macified paths (i.e., @@ -134,261 +150,440 @@ static int compare_unix(const DBT *a, const DBT *b) * returns a match if a < b. */ #if DB_VERSION_MINOR > 1 static int compare_mac(DB *db, const DBT *a, const DBT *b) -#else +#else /* DB_VERSION_MINOR < 1 */ static int compare_mac(const DBT *a, const DBT *b) -#endif +#endif /* DB_VERSION_MINOR */ { - u_int8_t *sa, *sb; - int len, ret; + u_int8_t *sa, *sb; + int len, ret; - /* sort by did */ - if ((ret = compare_did(a, b))) - return 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 */ + 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 */ + return a->size - b->size; /* sort by length */ } /* for unicode names -- right now it's the same as compare_mac. */ #if DB_VERSION_MINOR > 1 static int compare_unicode(DB *db, const DBT *a, const DBT *b) -#else +#else /* DB_VERSION_MINOR < 1 */ static int compare_unicode(const DBT *a, const DBT *b) -#endif +#endif /* DB_VERSION_MINOR */ { #if DB_VERSION_MINOR > 1 - return compare_mac(db,a,b); -#else - return compare_mac(a,b); -#endif + return compare_mac(db,a,b); +#else /* DB_VERSION_MINOR < 1 */ + return compare_mac(a,b); +#endif /* DB_VERSION_MINOR */ } -void *cnid_open(const char *dir) -{ - struct stat st; - struct flock lock; - char path[MAXPATHLEN + 1]; - CNID_private *db; - DBT key, data; - int open_flag, len; - - if (!dir) - return NULL; +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)) { - 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; + /* 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; + } - strcpy(path, dir); - if (path[len - 1] != '/') { + /* Make sure cnid.lock goes in .AppleDB. */ strcat(path, "/"); len++; - } - - lock.l_type = F_WRLCK; - lock.l_whence = SEEK_SET; - -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_env_create(&db->dbenv, 0)) { - syslog(LOG_ERR, "cnid_open: db_env_create failed"); - goto fail_lock; - } - - /* Check to see if a DBENV already exists. If it does, join it. */ -#if DB_VERSION_MINOR > 1 - if (db->dbenv->open(db->dbenv, path, DB_JOINENV, 0666)) { -#endif - if (db->dbenv->open(db->dbenv, path, DBOPTIONS, 0666)) { - /* try with a shared memory pool */ - if (db->dbenv->open(db->dbenv, path, DB_INIT_MPOOL, 0666)) { + strcpy(db->close_file, path); + strcat(db->close_file, DBCLOSEFILE); - /* try without any options. */ - if (db->dbenv->open(db->dbenv, path, 0, 0666)) { - syslog(LOG_ERR, "cnid_open: db_env_open failed"); - goto fail_lock; - } + /* 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; } - db->flags |= CNIDFLAG_DB_RO; - open_flag = DB_RDONLY; - syslog(LOG_INFO, "cnid_open: read-only CNID database"); - } -#if DB_VERSION_MINOR > 1 - } -#endif #if DB_VERSION_MINOR > 1 - db->dbenv->set_flags(db->dbenv, DB_TXN_NOSYNC, 1); +#if 0 + /* 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; - /* did/name reverse mapping. we use a btree for this one. */ - if (db_create(&db->db_didname, db->dbenv, 0)) - goto fail_appinit; - - db->db_didname->set_bt_compare(db->db_didname, &compare_unix); - if (db->db_didname->open(db->db_didname, DBDIDNAME, NULL, DB_BTREE, open_flag, 0666)) { - 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; - while ((errno = db->db_didname->get(db->db_didname, NULL, &key, &data, 0))) { - switch (errno) { - case DB_LOCK_DEADLOCK: - continue; - - case DB_NOTFOUND: - { - u_int32_t version = htonl(DBVERSION); - - data.data = &version; - data.size = sizeof(version); - } dbversion_retry: - if (db->db_didname->put(db->db_didname, NULL, &key, &data, - DB_NOOVERWRITE)) - if (errno == DB_LOCK_DEADLOCK) - 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. */ + 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 != htonl(DBVERSION)) { - /* fix up stuff */ - } + memcpy(&version, data.data, sizeof(version)); + if (version != ntohl(DBVERSION)) { + /* Do stuff here. */ + } #endif /* 0 */ #ifdef EXTENDED_DB - /* did/macname mapping. btree this one. */ - if (db_create(&db->db_macname, db->dbenv, 0)) - goto fail_appinit; - - db->db_macname->set_bt_compare(db->db_macname, &compare_mac); - if (db->db_macname->open(db->db_macname, DBMACNAME, NULL, DB_BTREE, open_flag, 0666)) { - db->db_didname->close(db->db_didname, 0); - goto fail_appinit; - } - - /* did/shortname mapping */ - if (db_create(&db->db_shortname, db->dbenv, 0)) - goto fail_appinit; - - db->db_shortname->set_bt_compare(db->db_shortname, &compare_mac); - if (db->db_shortname->open(db->db_shortname, DBSHORTNAME, NULL, DB_BTREE, open_flag, 0666)) { - db->db_didname->close(db->db_didname, 0); - db->db_macname->close(db->db_macname, 0); - goto fail_appinit; - } - - /* did/longname mapping */ - if (db_create(&db->db_longname, db->dbenv, 0)) - goto fail_appinit; - - db->db_longname->set_bt_compare(db->db_longname, &compare_unicode); - if (db->db_longname->open(db->db_longname, DBLONGNAME, NULL, DB_BTREE, open_flag, 0666)) { - 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; - } + /* 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; + } - /* dev/ino reverse mapping. we hash this one. */ - if (db_create(&db->db_devino, db->dbenv, 0)) - 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; + } - if (db->db_devino->open(db->db_devino, DBDEVINO, NULL, DB_HASH, open_flag, 0666)) { - db->db_didname->close(db->db_didname, 0); + /* 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); + 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; - } + db->db_devino->close(db->db_devino, 0); + goto fail_appinit; + } - /* main cnid database. we hash this one as well. */ - if (db_create(&db->db_cnid, db->dbenv, 0)) - goto fail_appinit; - if (db->db_cnid->open(db->db_cnid, DBCNID, NULL, DB_HASH, open_flag, 0666)) { - db->db_didname->close(db->db_didname, 0); + 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); + 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; - } + goto fail_appinit; + } - return db; + return db; fail_appinit: - syslog(LOG_ERR, "cnid_open: db_open failed"); - db->dbenv->close(db->dbenv, 0); + 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: fail_db: - free(db); - return NULL; + free(db); + return NULL; } #endif /* CNID_DB */ + +