/*
- * $Id: main.c,v 1.12 2009-10-18 17:50:13 didg Exp $
- *
* Copyright (C) Joerg Lenneis 2003
* Copyright (c) Frank Lahm 2009
* All Rights Reserved. See COPYING.
#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 <arpa/inet.h>
-#include <netatalk/endian.h>
#include <atalk/cnid_dbd_private.h>
#include <atalk/logger.h>
+#include <atalk/errchk.h>
+#include <atalk/bstrlib.h>
+#include <atalk/netatalk_conf.h>
#include "db_param.h"
#include "dbif.h"
#include "dbd.h"
#include "comm.h"
-
-#define LOCKFILENAME "lock"
+#include "pack.h"
/*
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;
-
static int exit_sig = 0;
+static int db_locked;
static void sig_exit(int signo)
{
1: Success, if transactions are used commit.
0: Failure, but we continue to serve requests. If transactions are used abort/rollback.
- -1: Fatal error, either from the database or from the socket. Abort the transaction if applicable
+ -1: Fatal error, either from t
+ he database or from the socket. Abort the transaction if applicable
(which might fail as well) and then exit.
We always try to notify the client process about the outcome, the result field
else
timeout = 1;
- if ((cret = comm_rcv(&rqst, timeout, &set)) < 0)
+ if ((cret = comm_rcv(&rqst, timeout, &set, &now)) < 0)
return -1;
- now = time(NULL);
-
if (cret == 0) {
/* comm_rcv returned from select without receiving anything. */
- if (exit_sig)
+ if (exit_sig) {
/* Received signal (TERM|INT) */
return 0;
- if (dbp->idle_timeout && comm_nbe() <= 0 && (now - time_last_rqst) > dbp->idle_timeout)
+ }
+ if (now - time_last_rqst >= dbp->idle_timeout && comm_nbe() <= 0) {
/* Idle timeout */
return 0;
+ }
+ /* still active connections, reset time_last_rqst */
+ time_last_rqst = now;
} else {
/* We got a request */
time_last_rqst = now;
ret = 1;
break;
case CNID_DBD_OP_ADD:
- ret = dbd_add(dbd, &rqst, &rply);
+ ret = dbd_add(dbd, &rqst, &rply, 0);
break;
case CNID_DBD_OP_GET:
ret = dbd_get(dbd, &rqst, &rply);
ret = dbd_resolve(dbd, &rqst, &rply);
break;
case CNID_DBD_OP_LOOKUP:
- ret = dbd_lookup(dbd, &rqst, &rply);
+ ret = dbd_lookup(dbd, &rqst, &rply, 0);
break;
case CNID_DBD_OP_UPDATE:
ret = dbd_update(dbd, &rqst, &rply);
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;
break;
}
-
+
if ((cret = comm_snd(&rply)) < 0 || ret < 0) {
dbif_txn_abort(dbd);
return -1;
Shall we checkpoint bdb ?
"flush_interval" seconds passed ?
*/
- if (now > time_next_flush) {
+ if (now >= time_next_flush) {
LOG(log_info, logtype_cnid, "Checkpointing BerkeleyDB for volume '%s'", dbp->dir);
if (dbif_txn_checkpoint(dbd, 0, 0, 0) < 0)
return -1;
}
}
-/* ------------------------ */
-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)
}
}
-/* ----------------------- */
-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[])
{
+ EC_INIT;
struct db_param *dbp;
- int err = 0;
- int lockfd, ctrlfd, clntfd;
- char *dir, *logconfig;
+ int delete_bdb = 0;
+ int ctrlfd = -1, clntfd = -1;
+ char *logconfig;
+ AFPObj obj = { 0 };
+ struct vol *vol;
+ char *volpath = NULL;
+ bstring dbpath;
+
+ while (( ret = getopt( argc, argv, "dF:l:p:t:v")) != -1 ) {
+ switch (ret) {
+ case 'd':
+ delete_bdb = 1;
+ break;
+ case 'F':
+ obj.cmdlineconfigfile = strdup(optarg);
+ break;
+ case 'p':
+ volpath = strdup(optarg);
+ break;
+ case 'l':
+ clntfd = atoi(optarg);
+ break;
+ case 't':
+ ctrlfd = atoi(optarg);
+ break;
+ case 'v':
+ printf("cnid_dbd (Netatalk %s)\n", VERSION);
+ return -1;
+ }
+ }
+
+ if (ctrlfd == -1 || clntfd == -1 || !volpath) {
+ LOG(log_error, logtype_cnid, "main: bad IPC fds");
+ exit(EXIT_FAILURE);
+ }
+
+ EC_ZERO( afp_config_parse(&obj) );
set_processname("cnid_dbd");
+ setuplog(obj.options.logconfig, obj.options.logfile);
- /* FIXME: implement -d from cnid_metad */
- if (argc != 5) {
- LOG(log_error, logtype_cnid, "main: not enough arguments");
- exit(1);
- }
+ EC_ZERO( load_volumes(&obj, NULL) );
+ EC_NULL( vol = getvolbypath(volpath) );
- dir = argv[1];
- ctrlfd = atoi(argv[2]);
- clntfd = atoi(argv[3]);
- logconfig = strdup(argv[4]);
- setuplog(logconfig);
+ pack_setvol(vol);
- switch_to_user(dir);
+ EC_NULL( dbpath = bfromcstr(vol->v_dbpath) );
+ EC_ZERO( bcatcstr(dbpath, "/.AppleDB") );
- /* 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_debug, logtype_cnid, "db dir: \"%s\"", bdata(dbpath));
+
+ switch_to_user(bdata(dbpath));
+
+ /* Get db lock */
+ if ((db_locked = get_lock(LOCK_EXCL, bdata(dbpath))) == -1) {
+ LOG(log_error, logtype_cnid, "main: fatal db lock error");
+ EC_FAIL;
+ }
+ if (db_locked != LOCK_EXCL) {
+ /* Couldn't get exclusive lock, try shared lock */
+ if ((db_locked = get_lock(LOCK_SHRD, NULL)) != LOCK_SHRD) {
+ LOG(log_error, logtype_cnid, "main: fatal db lock error");
+ EC_FAIL;
+ }
+ }
- LOG(log_info, logtype_cnid, "Startup, DB dir %s", dir);
+ if (delete_bdb && (db_locked == LOCK_EXCL)) {
+ LOG(log_warning, logtype_cnid, "main: too many CNID db opening attempts, wiping the slate clean");
+ chdir(bdata(dbpath));
+ system("rm -f cnid2.db lock log.* __db.*");
+ if ((db_locked = get_lock(LOCK_EXCL, bdata(dbpath))) != LOCK_EXCL) {
+ LOG(log_error, logtype_cnid, "main: fatal db lock error");
+ EC_FAIL;
+ }
+ }
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)
- exit(1);
+ if ((dbp = db_param_read(bdata(dbpath))) == NULL)
+ EC_FAIL;
LOG(log_maxdebug, logtype_cnid, "Finished parsing db_param config file");
- if (NULL == (dbd = dbif_init(".", "cnid2.db")))
- exit(2);
+ if (NULL == (dbd = dbif_init(bdata(dbpath), "cnid2.db")))
+ EC_FAIL;
- if (dbif_env_open(dbd, dbp, DBOPTIONS) < 0)
- exit(2); /* FIXME: same exit code as failure for dbif_open() */
+ /* Only recover if we got the lock */
+ if (dbif_env_open(dbd,
+ dbp,
+ (db_locked == LOCK_EXCL) ? DBOPTIONS | DB_RECOVER : DBOPTIONS) < 0)
+ EC_FAIL;
LOG(log_debug, logtype_cnid, "Finished initializing BerkeleyDB environment");
if (dbif_open(dbd, dbp, 0) < 0) {
- dbif_close(dbd);
- exit(2);
+ ret = -1;
+ goto close_db;
}
+
LOG(log_debug, logtype_cnid, "Finished opening BerkeleyDB databases");
- if (dbd_stamp(dbd) < 0) {
- dbif_close(dbd);
- exit(5);
+ /* Downgrade db lock */
+ if (db_locked == LOCK_EXCL) {
+ if (get_lock(LOCK_UNLOCK, NULL) != 0) {
+ ret = -1;
+ goto close_db;
+ }
+
+ if (get_lock(LOCK_SHRD, NULL) != LOCK_SHRD) {
+ ret = -1;
+ goto close_db;
+ }
}
- LOG(log_maxdebug, logtype_cnid, "Finished checking database stamp");
+
if (comm_init(dbp, ctrlfd, clntfd) < 0) {
- dbif_close(dbd);
- exit(3);
+ ret = -1;
+ goto close_db;
}
- if (loop(dbp) < 0)
- err++;
+ if (loop(dbp) < 0) {
+ ret = -1;
+ goto close_db;
+ }
+close_db:
if (dbif_close(dbd) < 0)
- err++;
+ ret = -1;
- if (dbif_prep_upgrade(dir) < 0)
- err++;
+ if (dbif_env_remove(bdata(dbpath)) < 0)
+ ret = -1;
- free_lock(lockfd);
+EC_CLEANUP:
+ if (ret != 0)
+ exit(1);
- if (err)
- exit(4);
- else if (exit_sig)
+ if (exit_sig)
LOG(log_info, logtype_cnid, "main: Exiting on signal %i", exit_sig);
else
LOG(log_info, logtype_cnid, "main: Idle timeout, exiting");
- return 0;
+ EC_EXIT;
}