X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=etc%2Fcnid_dbd%2Fmain.c;h=9b9d963134c4a02b5feee5bc0f248ef2e689c1bc;hb=1a6013c7ecd313e03eee1192d54bee624d4a9293;hp=a715c19a4cea5e1ad2b1cc048c0218cf96507413;hpb=ba288e1499eb7106d6372ec019256b7d3ea1d2e7;p=netatalk.git diff --git a/etc/cnid_dbd/main.c b/etc/cnid_dbd/main.c index a715c19a..9b9d9631 100644 --- a/etc/cnid_dbd/main.c +++ b/etc/cnid_dbd/main.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "db_param.h" #include "dbif.h" @@ -44,11 +45,14 @@ Note: DB_INIT_LOCK is here so we can run the db_* utilities while netatalk is running. It's a likey performance hit, but it might we worth it. */ -#define DBOPTIONS (DB_CREATE | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_LOCK | DB_INIT_TXN | DB_RECOVER) +#define DBOPTIONS (DB_CREATE | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_LOCK | DB_INIT_TXN) -static DBD *dbd; +/* Global, needed by pack.c:idxname() */ +struct volinfo volinfo; +static DBD *dbd; static int exit_sig = 0; +static int db_locked; static void sig_exit(int signo) { @@ -70,6 +74,57 @@ static void block_sigs_onoff(int block) return; } +/*! + * Get lock on db lock file + * + * @args cmd (r) !=0: lock, 0: unlock + * @returns 1 if lock was acquired, 0 if file is already locked, -1 on error + */ +static int get_lock(int cmd) +{ + static int lockfd = -1; + struct flock lock; + + if (cmd == 0) { + if (lockfd == -1) + return -1; + + 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); + lockfd = -1; + return 0; + } + + if (lockfd == -1) { + if ((lockfd = open(LOCKFILENAME, O_RDWR | O_CREAT, 0644)) < 0) { + LOG(log_error, logtype_cnid, "get_lock: error opening lockfile: %s", strerror(errno)); + return -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) { + LOG(log_debug, logtype_cnid, "get_lock: couldn't lock"); + return 0; + } else { + LOG(log_error, logtype_cnid, "get_lock: fcntl F_WRLCK lockfile: %s", strerror(errno)); + return -1; + } + } + + LOG(log_debug, logtype_cnid, "get_lock: got lock"); + return 1; +} + /* The dbd_XXX and comm_XXX functions all obey the same protocol for return values: @@ -116,6 +171,20 @@ static int loop(struct db_param *dbp) dbp->flush_interval, timebuf); while (1) { + /* + * If we haven't got the lock yet, get it now. + * Prevents a race with dbd: + * 1. no cnid_dbd running + * 2. dbd -r starts, gets the lock + * 3. cnid_dbd starts, doesn't get lock, doesn't run recovery, all is fine + * 4. dbd from (2) finishes, drops lock + * 5. anothet dbd but this time with -re is started which + * - succeeds getting the lock + * - runs recovery => this kills (3) + */ + if (!db_locked) + if ((db_locked = get_lock(1)) == -1) + return -1; timeout = min(time_next_flush, time_last_rqst +dbp->idle_timeout); if (timeout > now) timeout -= now; @@ -174,6 +243,9 @@ static int loop(struct db_param *dbp) case CNID_DBD_OP_REBUILD_ADD: ret = dbd_rebuild_add(dbd, &rqst, &rply); break; + case CNID_DBD_OP_SEARCH: + ret = dbd_search(dbd, &rqst, &rply); + break; default: LOG(log_error, logtype_cnid, "loop: unknown op %d", rqst.op); ret = -1; @@ -250,33 +322,6 @@ static void switch_to_user(char *dir) } } -/* ------------------------ */ -static 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; -} /* ----------------------- */ static void set_signal(void) @@ -300,26 +345,13 @@ static void set_signal(void) } } -/* ----------------------- */ -static 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[]) { struct db_param *dbp; int err = 0; - int lockfd, ctrlfd, clntfd; - char *dir, *logconfig; + int ctrlfd, clntfd; + char *logconfig; set_processname("cnid_dbd"); @@ -329,33 +361,55 @@ int main(int argc, char *argv[]) exit(1); } - dir = argv[1]; ctrlfd = atoi(argv[2]); clntfd = atoi(argv[3]); logconfig = strdup(argv[4]); setuplog(logconfig); - switch_to_user(dir); + /* Load .volinfo file */ + if (loadvolinfo(argv[1], &volinfo) == -1) { + LOG(log_error, logtype_cnid, "Cant load volinfo for \"%s\"", argv[1]); + exit(EXIT_FAILURE); + } + /* Put "/.AppleDB" at end of volpath, get path from volinfo file */ + char dbpath[MAXPATHLEN+1]; + if ((strlen(volinfo.v_dbpath) + strlen("/.AppleDB")) > MAXPATHLEN ) { + LOG(log_error, logtype_cnid, "CNID db pathname too long: \"%s\"", volinfo.v_dbpath); + exit(EXIT_FAILURE); + } + strncpy(dbpath, volinfo.v_dbpath, MAXPATHLEN - strlen("/.AppleDB")); + strcat(dbpath, "/.AppleDB"); + + if (vol_load_charsets(&volinfo) == -1) { + LOG(log_error, logtype_cnid, "Error loading charsets!"); + exit(EXIT_FAILURE); + } + LOG(log_debug, logtype_cnid, "db dir: \"%s\"", dbpath); + + switch_to_user(dbpath); /* 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); + if ((db_locked = get_lock(1)) == -1) { + exit(1); + } set_signal(); /* SIGINT and SIGTERM are always off, unless we are in pselect */ block_sigs_onoff(1); - if ((dbp = db_param_read(dir, CNID_DBD)) == NULL) + if ((dbp = db_param_read(dbpath)) == NULL) exit(1); LOG(log_maxdebug, logtype_cnid, "Finished parsing db_param config file"); - if (NULL == (dbd = dbif_init(".", "cnid2.db"))) + if (NULL == (dbd = dbif_init(dbpath, "cnid2.db"))) exit(2); - if (dbif_env_open(dbd, dbp, DBOPTIONS) < 0) + /* Only recover if we got the lock */ + if (dbif_env_open(dbd, + dbp, + db_locked ? DBOPTIONS | DB_RECOVER : DBOPTIONS) < 0) exit(2); /* FIXME: same exit code as failure for dbif_open() */ LOG(log_debug, logtype_cnid, "Finished initializing BerkeleyDB environment"); @@ -365,12 +419,6 @@ int main(int argc, char *argv[]) } LOG(log_debug, logtype_cnid, "Finished opening BerkeleyDB databases"); - if (dbd_stamp(dbd) < 0) { - dbif_close(dbd); - exit(5); - } - LOG(log_maxdebug, logtype_cnid, "Finished checking database stamp"); - if (comm_init(dbp, ctrlfd, clntfd) < 0) { dbif_close(dbd); exit(3); @@ -382,10 +430,10 @@ int main(int argc, char *argv[]) if (dbif_close(dbd) < 0) err++; - if (dbif_prep_upgrade(dir) < 0) + if (dbif_env_remove(dbpath) < 0) err++; - free_lock(lockfd); + (void)get_lock(0); if (err) exit(4);