X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=etc%2Fcnid_dbd%2Fdbif.c;h=217fdd6d73d7255e6e1a16acc8c9acc3f7ada82b;hb=056d3ef4c88ba09eabb1fcbf06bdd9fe6e7af4cf;hp=2b5b91ac0f3bcdd7f397b26193840e9f193bbf2d;hpb=c73d2fc78e3e4513c1f00178016151ca072906a0;p=netatalk.git diff --git a/etc/cnid_dbd/dbif.c b/etc/cnid_dbd/dbif.c index 2b5b91ac..217fdd6d 100644 --- a/etc/cnid_dbd/dbif.c +++ b/etc/cnid_dbd/dbif.c @@ -14,13 +14,14 @@ #include #include #include -#include #include +#include #include #include #include +#include #include "db_param.h" #include "dbif.h" @@ -33,27 +34,28 @@ */ static int dbif_stamp(DBD *dbd, void *buffer, int size) { + EC_INIT; struct stat st; - int rc,cwd; + int cwd = -1; if (size < 8) - return -1; + EC_FAIL; /* Remember cwd */ if ((cwd = open(".", O_RDONLY)) < 0) { LOG(log_error, logtype_cnid, "error opening cwd: %s", strerror(errno)); - return -1; + EC_FAIL; } /* chdir to db_envhome */ if ((chdir(dbd->db_envhome)) != 0) { LOG(log_error, logtype_cnid, "error chdiring to db_env '%s': %s", dbd->db_envhome, strerror(errno)); - return -1; + EC_FAIL; } - if ((rc = stat(dbd->db_table[DBIF_CNID].name, &st)) < 0) { + if (stat(dbd->db_table[DBIF_CNID].name, &st) < 0) { LOG(log_error, logtype_cnid, "error stating database %s: %s", dbd->db_table[DBIF_CNID].name, db_strerror(errno)); - return -1; + EC_FAIL; } LOG(log_maxdebug, logtype_cnid,"stamp: %s", asctime(localtime(&st.st_ctime))); @@ -61,12 +63,15 @@ static int dbif_stamp(DBD *dbd, void *buffer, int size) memset(buffer, 0, size); memcpy(buffer, &st.st_ctime, sizeof(st.st_ctime)); - if ((fchdir(cwd)) != 0) { - LOG(log_error, logtype_cnid, "error chdiring back: %s", strerror(errno)); - return -1; +EC_CLEANUP: + if (cwd != -1) { + if (fchdir(cwd) != 0) { + LOG(log_error, logtype_cnid, "error chdiring back: %s", strerror(errno)); + EC_STATUS(-1); + } + close(cwd); } - - return 0; + EC_EXIT; } /*! @@ -105,6 +110,10 @@ static int dbif_init_rootinfo(DBD *dbd, int version) if (dbif_put(dbd, DBIF_CNID, &key, &data, 0) < 0) return -1; + if (dbif_txn_commit(dbd) != 1) { + LOG(log_error, logtype_cnid, "dbif_init_rootinfo: cant commit txn"); + return -1; + } return 0; } @@ -121,6 +130,9 @@ static int dbif_getversion(DBD *dbd, uint32_t *version) DBT key, data; int ret; + LOG(log_maxdebug, logtype_cnid, "dbif_getversion: reading version info"); + + *version = -1; memset(&key, 0, sizeof(key)); memset(&data, 0, sizeof(data)); key.data = ROOTINFO_KEY; @@ -134,9 +146,11 @@ static int dbif_getversion(DBD *dbd, uint32_t *version) ret = 1; break; case 0: /* not found */ + LOG(log_debug, logtype_cnid, "dbif_getversion: no version info found"); ret = 0; break; default: + LOG(log_error, logtype_cnid, "dbif_getversion: database error"); ret = -1; break; } @@ -147,7 +161,7 @@ static int dbif_getversion(DBD *dbd, uint32_t *version) /*! * Set CNID database version number * - * Initializes rootinfo key as neccessary, as does dbif_getversion + * Initializes rootinfo key as neccessary * @returns -1 on error, 0 on success */ static int dbif_setversion(DBD *dbd, uint32_t version) @@ -185,16 +199,22 @@ static int dbif_setversion(DBD *dbd, uint32_t version) } /*! - * Upgrade CNID database versions + * Upgrade CNID database versions, initialize rootinfo key as as necessary in dbif_setversion() * * For now this does nothing, as upgrading from ver. 0 to 1 is done in dbif_open */ +#define UNINTIALIZED_DB UINT32_MAX static int dbif_upgrade(DBD *dbd) { - uint32_t version; + uint32_t version = CNID_VERSION_UNINTIALIZED_DB; if (dbif_getversion(dbd, &version) == -1) return -1; + if (version == CNID_VERSION_UNINTIALIZED_DB) { + version = CNID_VERSION; + if (dbif_setversion(dbd, CNID_VERSION) != 0) + return -1; + } /* * Do upgrade stuff ... @@ -306,6 +326,91 @@ exit: return ret; } +/*! + * Get lock on db lock file + * + * @args cmd (r) lock command: + * LOCK_FREE: close lockfd + * LOCK_UNLOCK: unlock lockm keep lockfd open + * LOCK_EXCL: F_WRLCK on lockfd + * LOCK_SHRD: F_RDLCK on lockfd + * @args dbpath (r) path to lockfile, only used on first call, + * later the stored fd is used + * @returns LOCK_FREE/LOCK_UNLOCK return 0 on success, -1 on error + * LOCK_EXCL/LOCK_SHRD return LOCK_EXCL or LOCK_SHRD respectively on + * success, 0 if the lock couldn't be acquired, -1 on other errors + */ +int get_lock(int cmd, const char *dbpath) +{ + static int lockfd = -1; + int ret; + char lockpath[PATH_MAX]; + struct stat st; + + switch (cmd) { + case LOCK_FREE: + if (lockfd == -1) + return -1; + close(lockfd); + lockfd = -1; + return 0; + + case LOCK_UNLOCK: + if (lockfd == -1) + return -1; + return unlock(lockfd, 0, SEEK_SET, 0); + + case LOCK_EXCL: + case LOCK_SHRD: + if (lockfd == -1) { + if ( (strlen(dbpath) + strlen(LOCKFILENAME+1)) > (PATH_MAX - 1) ) { + LOG(log_error, logtype_cnid, ".AppleDB pathname too long"); + return -1; + } + strncpy(lockpath, dbpath, PATH_MAX - 1); + strcat(lockpath, "/"); + strcat(lockpath, LOCKFILENAME); + + if ((lockfd = open(lockpath, O_RDWR | O_CREAT, 0644)) < 0) { + LOG(log_error, logtype_cnid, "Error opening lockfile: %s", strerror(errno)); + return -1; + } + + if ((stat(dbpath, &st)) != 0) { + LOG(log_error, logtype_cnid, "Error statting lockfile: %s", strerror(errno)); + return -1; + } + + if ((chown(lockpath, st.st_uid, st.st_gid)) != 0) { + LOG(log_error, logtype_cnid, "Error inheriting lockfile permissions: %s", + strerror(errno)); + return -1; + } + } + + if (cmd == LOCK_EXCL) + ret = write_lock(lockfd, 0, SEEK_SET, 0); + else + ret = read_lock(lockfd, 0, SEEK_SET, 0); + + if (ret != 0) { + if (cmd == LOCK_SHRD) + LOG(log_error, logtype_cnid, "Volume CNID db is locked, try again..."); + return 0; + } + + LOG(log_debug, logtype_cnid, "get_lock: got %s lock", + cmd == LOCK_EXCL ? "LOCK_EXCL" : "LOCK_SHRD"); + return cmd; + + default: + return -1; + } /* switch(cmd) */ + + /* deadc0de, never get here */ + return -1; +} + /* --------------- */ DBD *dbif_init(const char *envhome, const char *filename) { @@ -371,6 +476,8 @@ int dbif_env_open(DBD *dbd, struct db_param *dbp, uint32_t dbenv_oflags) return -1; } + dbd->db_param = *dbp; + if ((dbif_openlog(dbd)) != 0) return -1; @@ -612,6 +719,10 @@ int dbif_open(DBD *dbd, struct db_param *dbp, int reindex) if (reindex) LOG(log_info, logtype_cnid, "Reindexing name index..."); + /* + * Upgrading from version 0 to 1 requires adding the name index below which + * must be done by specifying the DB_CREATE flag + */ uint32_t version = CNID_VERSION; if (dbd->db_envhome && !reindex) { if (dbif_getversion(dbd, &version) == -1) @@ -857,7 +968,7 @@ int dbif_del(DBD *dbd, const int dbi, DBT *key, u_int32_t flags) flags); if (ret == DB_NOTFOUND) { - LOG(log_info, logtype_cnid, "key not found"); + LOG(log_debug, logtype_cnid, "key not found"); return 0; } if (ret) { @@ -986,25 +1097,30 @@ int dbif_txn_abort(DBD *dbd) } /* - ret = 1 -> commit txn - ret = 0 -> abort txn -> exit! + ret = 1 -> commit txn if db_param.txn_frequency + ret = 0 -> abort txn db_param.txn_frequency -> exit! anything else -> exit! + + @returns 0 on success (abort or commit), -1 on error */ -void dbif_txn_close(DBD *dbd, int ret) +int dbif_txn_close(DBD *dbd, int ret) { if (ret == 0) { if (dbif_txn_abort(dbd) < 0) { LOG( log_error, logtype_cnid, "Fatal error aborting transaction. Exiting!"); - exit(EXIT_FAILURE); + return -1; } } else if (ret == 1) { ret = dbif_txn_commit(dbd); if ( ret < 0) { LOG( log_error, logtype_cnid, "Fatal error committing transaction. Exiting!"); - exit(EXIT_FAILURE); + return -1; } - } else - exit(EXIT_FAILURE); + } else { + return -1; + } + + return 0; } int dbif_txn_checkpoint(DBD *dbd, u_int32_t kbyte, u_int32_t min, u_int32_t flags)