-This is a reimplementation of the netatalk CNID database support that
-attempts to put all current functionality into a separate daemon
-called cnid_dbd. There is one such daemon per netatalk volume. The
-underlying database structure is still based on Berkeley DB and the
-database format is the same as in the current CNID implementation, so
-this can be used as a drop-in replacement.
+This is a implementation of the netatalk CNID database support that
+attempts to put all functionality into a separate daemon called cnid_dbd.
+There is one such daemon per netatalk volume. The underlying database
+structure is based on Berkeley DB and the database format is the same
+as in the cdb CNID backend, so this can be used as a drop-in replacement.
Advantages:
- If an afpd process crashes, the CNID database is unaffected. If the
process was making changes to the database at the time of the crash,
- those changes will either be completed (no transactions) or rolled
- back entirely (transactions). If the process was not using the
- database at the time of the crash, no corrective action is
- necessary. In both cases, database consistency is assured.
+ those changes will be rolled back entirely (transactions).
+ If the process was not using the database at the time of the crash,
+ no corrective action is necessary. In any case, database consistency
+ is assured.
Disadvantages:
Installation and configuration
-cnid_dbd is now part of a new CNID framework whereby various CNID
-backends (including the ones present so far) can be selected for afpd
-as a runtime option for a given volume. The default is to compile
-support for all these backends, so normally there is no need to
-specify other options to configure. The only exception is
-transactional support, which is enabled as the default. If you want to
-turn it off use --with-cnid-dbd-txn=no.
-
-In order to turn on cnid_dbd backend support for a given volume, set
-the option -cnidscheme:dbd in your AppleVolumes.default file or
-equivalent. The default for this parameter is -cnidscheme:cdb.
+cnid_dbd is part of the CNID framework whereby various CNID backends
+can be selected for afpd as a runtime option for a given volume.
+By default only last and dbd backend are built and dbd is the default.
There are two executeables that will be built in etc/cnid_dbd and
installed into the systems binaries directories of netatalk
cnid_metad needs one command line argument, the name of the cnid_dbd
executeable. You can either specify "cnid_dbd" if it is in the path
for cnid_metad or otherwise use the fully qualified pathname to
-cnid_dbd, e.g. /usr/local/netatalk/sbin/cnid_dbd. cnid_metad also uses
-a unix domain socket to receive requests from afpd. The pathname for
-that socket is /tmp/cnid_meta. It should not be deleted while
-cnid_metad runs.
-
+cnid_dbd, e.g. /usr/local/netatalk/sbin/cnid_dbd. cnid_metad listens
+on TCP port 4700 by default for request from afpd processes.
cnid_dbd changes to the Berkeley DB directory on startup and sets
effective UID and GID to owner and group of that directory. Database and
currently recognized:
Name Default
-
-backlog 20
-cachesize 1024
-nosync 0
+==== =======
+cachesize 8192
flush_frequency 100
-flush_interval 30
+flush_interval 1800
usock_file <databasedirectory>/usock
-fd_table_size 16
+fd_table_size 128
idle_timeout 600
-
-"backlog" specifies the maximum number of connection requests that can
-be pending on the unix domain socket cnid_dbd uses. listen(2) has more
-information about this value on your system.
-
"cachesize" determines the size of the Berkeley DB cache in
kilobytes. Each cnid_dbd process grabs that much memory on top of its
normal memory footprint. It can be used to tune database
value. The Berkeley DB Tutorial and Reference Guide has a section
"Selecting a cache size" that gives more detailed information.
-"nosync" is only valid if transactional support is enabled. If it is
-set to 1, transactional changes to the database are not synchronously
-written to disk when the transaction completes. This will increase
-performance considerably at the risk of recent changes getting
-lost in case of a crash. The database will still be consistent,
-though. See "Transaction throughput" in the Berkeley DB Tutorial for
-more information.
-
"flush_frequency" and "flush_interval" control how often changes to
the database are written to the underlying database files if no
transactions are used or how often the transaction system is
checkpointed for transactions. Both of these operations are
performed if either i) more than flush_frequency requests have been
received or ii) more than flush_interval seconds have elapsed since
-the last save/checkpoint. If you use transactions with nosync set to
-zero these parameters only influence how long recovery takes after
-a crash, there should never be any lost data. If nosync is 1, changes
-might be lost, but only since the last checkpoint. Be careful to check
-your harddisk configuration for on disk cache settings. Many IDE disks
-just cache writes as the default behaviour, so even flushing database
-files to disk will not have the desired effect.
+the last save/checkpoint.
+Be careful to check your harddisk configuration for on disk cache
+settings. Many IDE disks just cache writes as the default behaviour,
+so even flushing database files to disk will not have the desired effect.
"usock_file" gives the pathname of the unix domain socket file that
that instance of cnid_dbd will use for receiving requests. You might
eliminated from libatalk/cnid. I do not think it can work relieably in
the current form anyway.
-- It would be more flexible to have transaction support as a run time
-option as well.
-
- mmap for IPC would be nice as an alternative.
- The parameter file parsing of db_param is very simpleminded. It is
filenames for the usock_file parameter.
- There is no protection against a malicious user connecting to the
-cnid_dbd socket and changing the database. I will adress this problem
-soon.
+cnid_dbd socket and changing the database.
Please feel free to grep the source in etc/cnid_dbd and the file
libatalk/cnid/dbd/cnid_dbd.c for the string TODO, which indicates
comments that adress other, less important points.
-Joerg Lenneis, lenneis@wu-wien.ac.at
+The Netatalk Team
/*
- * $Id: cnid_metad.c,v 1.7 2009-03-31 12:13:00 franklahm Exp $
+ * $Id: cnid_metad.c,v 1.8 2009-04-21 08:55:44 franklahm Exp $
*
* Copyright (C) Joerg Lenneis 2003
* All Rights Reserved. See COPYING.
*
*/
-/* cnid_dbd metadaemon to start up cnid_dbd upon request from afpd */
+/*
+ cnid_dbd metadaemon to start up cnid_dbd upon request from afpd.
+ Here is how it works:
+
+ via TCP socket
+ 1. afpd -------> cnid_metad
+
+ via UNIX domain socket
+ 2. cnid_metad -------> cnid_dbd
+
+ passes afpd client fd
+ 3. cnid_metad -------> cnid_dbd
+
+ Result:
+ via TCP socket
+ 4. afpd -------> cnid_dbd
+ */
+
#ifdef HAVE_CONFIG_H
#include "config.h"
#include <stdio.h>
#include <time.h>
#include <sys/ioctl.h>
-
-#ifndef WEXITSTATUS
+
+#ifndef WEXITSTATUS
#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
#endif /* ! WEXITSTATUS */
#ifndef WIFEXITED
#include "usockfd.h"
#define DBHOME ".AppleDB"
-#define DBHOMELEN 8
+#define DBHOMELEN 8
static int srvfd;
static int rqstfd;
volatile sig_atomic_t alarmed = 0;
-#define MAXSRV 512
-
#define MAXSPAWN 3 /* Max times respawned in.. */
-
+#define MAXVOLS 512
#define DEFAULTHOST "localhost"
#define DEFAULTPORT 4700
#define TESTTIME 22 /* this much seconds apfd client tries to
pid_t pid;
time_t tm; /* When respawned last */
int count; /* Times respawned in the last TESTTIME secondes */
- int toofast;
+ int toofast;
int control_fd; /* file descriptor to child cnid_dbd process */
};
-static struct server srv[MAXSRV +1];
+static struct server srv[MAXVOLS];
/* Default logging config: log to syslog with level log_note */
static char *logconfig = "default log_note";
-static struct server *test_usockfn(char *dir, char *fn _U_)
+static struct server *test_usockfn(char *dir)
{
-int i;
- for (i = 1; i <= MAXSRV; i++) {
+ int i;
+ for (i = 0; i < MAXVOLS; i++) {
if (srv[i].name && !strcmp(srv[i].name, dir)) {
return &srv[i];
}
/* -------------------- */
static int send_cred(int socket, int fd)
{
- int ret;
- struct msghdr msgh;
- struct iovec iov[1];
- struct cmsghdr *cmsgp = NULL;
- char *buf;
- size_t size;
- int er=0;
-
- size = CMSG_SPACE(sizeof fd);
- buf = malloc(size);
- if (!buf) {
- LOG(log_error, logtype_cnid, "error in sendmsg: %s", strerror(errno));
- return -1;
- }
-
- memset(&msgh,0,sizeof (msgh));
- memset(buf,0, size);
-
- msgh.msg_name = NULL;
- msgh.msg_namelen = 0;
-
- msgh.msg_iov = iov;
- msgh.msg_iovlen = 1;
-
- iov[0].iov_base = &er;
- iov[0].iov_len = sizeof(er);
-
- msgh.msg_control = buf;
- msgh.msg_controllen = size;
-
- cmsgp = CMSG_FIRSTHDR(&msgh);
- cmsgp->cmsg_level = SOL_SOCKET;
- cmsgp->cmsg_type = SCM_RIGHTS;
- cmsgp->cmsg_len = CMSG_LEN(sizeof(fd));
-
- *((int *)CMSG_DATA(cmsgp)) = fd;
- msgh.msg_controllen = cmsgp->cmsg_len;
-
- do {
- ret = sendmsg(socket,&msgh, 0);
- } while ( ret == -1 && errno == EINTR );
- if (ret == -1) {
- LOG(log_error, logtype_cnid, "error in sendmsg: %s", strerror(errno));
- free(buf);
- return -1;
- }
- free(buf);
- return 0;
+ int ret;
+ struct msghdr msgh;
+ struct iovec iov[1];
+ struct cmsghdr *cmsgp = NULL;
+ char *buf;
+ size_t size;
+ int er=0;
+
+ size = CMSG_SPACE(sizeof fd);
+ buf = malloc(size);
+ if (!buf) {
+ LOG(log_error, logtype_cnid, "error in sendmsg: %s", strerror(errno));
+ return -1;
+ }
+
+ memset(&msgh,0,sizeof (msgh));
+ memset(buf,0, size);
+
+ msgh.msg_name = NULL;
+ msgh.msg_namelen = 0;
+
+ msgh.msg_iov = iov;
+ msgh.msg_iovlen = 1;
+
+ iov[0].iov_base = &er;
+ iov[0].iov_len = sizeof(er);
+
+ msgh.msg_control = buf;
+ msgh.msg_controllen = size;
+
+ cmsgp = CMSG_FIRSTHDR(&msgh);
+ cmsgp->cmsg_level = SOL_SOCKET;
+ cmsgp->cmsg_type = SCM_RIGHTS;
+ cmsgp->cmsg_len = CMSG_LEN(sizeof(fd));
+
+ *((int *)CMSG_DATA(cmsgp)) = fd;
+ msgh.msg_controllen = cmsgp->cmsg_len;
+
+ do {
+ ret = sendmsg(socket,&msgh, 0);
+ } while ( ret == -1 && errno == EINTR );
+ if (ret == -1) {
+ LOG(log_error, logtype_cnid, "error in sendmsg: %s", strerror(errno));
+ free(buf);
+ return -1;
+ }
+ free(buf);
+ return 0;
}
/* -------------------- */
char buf1[8];
char buf2[8];
- up = test_usockfn(dbdir, usockfn);
+ LOG(log_maxdebug, logtype_cnid, "maybe_start_dbd: dbdir: '%s', UNIX socket file: '%s'",
+ dbdir, usockfn);
+
+ up = test_usockfn(dbdir);
if (up && up->pid) {
- /* we already have a process, send our fd */
- if (send_cred(up->control_fd, rqstfd) < 0) {
- /* FIXME */
- return -1;
- }
- return 0;
+ /* we already have a process, send our fd */
+ if (send_cred(up->control_fd, rqstfd) < 0) {
+ /* FIXME */
+ return -1;
+ }
+ return 0;
}
+ LOG(log_maxdebug, logtype_cnid, "maybe_start_dbd: no cnid_dbd for that volume yet. Starting one ...");
+
time(&t);
if (!up) {
/* find an empty slot */
- for (i = 1; i <= MAXSRV; i++) {
- if (!srv[i].pid && srv[i].tm + TESTTIME < t) {
+ for (i = 0; i < MAXVOLS; i++) {
+ if ( !srv[i].pid ) {
up = &srv[i];
- free(up->name);
up->tm = t;
up->count = 0;
up->toofast = 0;
- /* copy name */
up->name = strdup(dbdir);
break;
}
}
if (!up) {
- LOG(log_error, logtype_cnid, "no free slot");
- return -1;
+ LOG(log_error, logtype_cnid, "no free slot for cnid_dbd child. Configured maximum: %d. Do you have so many volumes?", MAXVOLS);
+ return -1;
}
}
else {
/* we have a slot but no process, check for respawn too fast */
- if (up->tm + TESTTIME > t) {
- if (up->toofast) {
- /* silently exit */
- return -1;
- }
- up->count++;
- } else {
- up->count = 0;
- up->toofast = 0;
- up->tm = t;
- }
- if (up->count > MAXSPAWN) {
- up->toofast = 1;
- up->tm = t;
- LOG(log_error, logtype_cnid, "respawn too fast %s", up->name);
- /* FIXME should we sleep a little ? */
- return -1;
+ if ( (t < (up->tm + TESTTIME)) /* We're in the respawn time window */
+ &&
+ (up->count > MAXSPAWN) ) /* ...and already tried to fork too often */
+ return -1; /* just exit, dont sleep, because we might have work to do for another client */
+
+ if ( t >= (up->tm + TESTTIME) ) { /* "reset" timer and count */
+ up->count = 0;
+ up->tm = t;
}
-
+ up->count++;
}
- /* create socketpair for comm between parent and child
- * FIXME Do we really need a permanent pipe between them ?
- */
+
+ /*
+ Create socketpair for comm between parent and child.
+ We use it to pass fds from connecting afpd processes to our
+ cnid_dbd child via fd passing.
+ */
if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) < 0) {
- LOG(log_error, logtype_cnid, "error in socketpair: %s", strerror(errno));
- return -1;
+ LOG(log_error, logtype_cnid, "error in socketpair: %s", strerror(errno));
+ return -1;
}
-
+
if ((pid = fork()) < 0) {
- LOG(log_error, logtype_cnid, "error in fork: %s", strerror(errno));
- return -1;
- }
+ LOG(log_error, logtype_cnid, "error in fork: %s", strerror(errno));
+ return -1;
+ }
if (pid == 0) {
int ret;
- /*
- * Child. Close descriptors and start the daemon. If it fails
- * just log it. The client process will fail connecting
- * afterwards anyway.
- */
-
- close(srvfd);
- close(sv[0]);
-
- for (i = 1; i <= MAXSRV; i++) {
+ /*
+ * Child. Close descriptors and start the daemon. If it fails
+ * just log it. The client process will fail connecting
+ * afterwards anyway.
+ */
+
+ close(srvfd);
+ close(sv[0]);
+
+ for (i = 0; i < MAXVOLS; i++) {
if (srv[i].pid && up != &srv[i]) {
- close(srv[i].control_fd);
+ close(srv[i].control_fd);
}
}
- sprintf(buf1, "%i", sv[1]);
- sprintf(buf2, "%i", rqstfd);
-
- if (up->count == MAXSPAWN) {
- /* there's a pb with the db inform child
- * it will run recover, delete the db whatever
- */
- LOG(log_error, logtype_cnid, "try with -d %s", up->name);
- ret = execlp(dbdpn, dbdpn, "-d", dbdir, buf1, buf2, logconfig, NULL);
- }
- else {
- ret = execlp(dbdpn, dbdpn, dbdir, buf1, buf2, logconfig, NULL);
- }
- if (ret < 0) {
- LOG(log_error, logtype_cnid, "Fatal error in exec: %s", strerror(errno));
- exit(0);
- }
+ sprintf(buf1, "%i", sv[1]);
+ sprintf(buf2, "%i", rqstfd);
+
+ if (up->count == MAXSPAWN) {
+ /* there's a pb with the db inform child
+ * it will run recover, delete the db whatever
+ */
+ LOG(log_error, logtype_cnid, "try with -d %s", up->name);
+ ret = execlp(dbdpn, dbdpn, "-d", dbdir, buf1, buf2, logconfig, NULL);
+ }
+ else {
+ ret = execlp(dbdpn, dbdpn, dbdir, buf1, buf2, logconfig, NULL);
+ }
+ if (ret < 0) {
+ LOG(log_error, logtype_cnid, "Fatal error in exec: %s", strerror(errno));
+ exit(0);
+ }
}
/*
* Parent.
/* ------------------ */
static int set_dbdir(char *dbdir, int len)
{
- struct stat st;
+ struct stat st;
if (!len)
return -1;
}
if (dbdir[len - 1] != '/') {
- strcat(dbdir, "/");
- len++;
+ strcat(dbdir, "/");
+ len++;
}
strcpy(dbdir + len, DBHOME);
if (stat(dbdir, &st) < 0 && mkdir(dbdir, 0755 ) < 0) {
LOG(log_error, logtype_cnid, "set_dbdir: mkdir failed for %s", dbdir);
return -1;
}
- return 0;
+ return 0;
}
/* ------------------ */
uid_t user_to_uid ( username )
-char *username;
+ char *username;
{
struct passwd *this_passwd;
-
+
/* check for anything */
if ( !username || strlen ( username ) < 1 ) return 0;
-
+
/* grab the /etc/passwd record relating to username */
this_passwd = getpwnam ( username );
-
+
/* return false if there is no structure returned */
if (this_passwd == NULL) return 0;
-
+
/* return proper uid */
return this_passwd->pw_uid;
-
-}
+
+}
/* ------------------ */
gid_t group_to_gid ( group )
-char *group;
+ char *group;
{
struct group *this_group;
-
+
/* check for anything */
if ( !group || strlen ( group ) < 1 ) return 0;
-
+
/* grab the /etc/groups record relating to group */
this_group = getgrnam ( group );
-
+
/* return false if there is no structure returned */
if (this_group == NULL) return 0;
-
+
/* return proper gid */
return this_group->gr_gid;
-
+
}
/* ------------------ */
void catch_alarm(int sig) {
- alarmed = 1;
+ alarmed = 1;
}
/* ------------------ */
int ret;
set_processname("cnid_metad");
-
+
while (( cc = getopt( argc, argv, "ds:p:h:u:g:l:")) != -1 ) {
switch (cc) {
case 'd':
debug = 1;
break;
case 'h':
- host = strdup(optarg);
+ host = strdup(optarg);
break;
case 'u':
uid = user_to_uid (optarg);
LOG(log_error, logtype_cnid, "main: bad arguments");
exit(1);
}
-
+
if (!debug) {
-
+
switch (fork()) {
case 0 :
fclose(stdin);
#ifdef TIOCNOTTY
{
- int i;
+ int i;
if (( i = open( "/dev/tty", O_RDWR )) >= 0 ) {
(void)ioctl( i, TIOCNOTTY, 0 );
setpgid( 0, getpid());
#else
setpgid( 0, getpid());
#endif
- break;
+ break;
case -1 : /* error */
LOG(log_error, logtype_cnid, "detach from terminal: %s", strerror(errno));
exit(1);
while (1) {
rqstfd = usockfd_check(srvfd, 10000000);
- /* Collect zombie processes and log what happened to them */
+ /* Collect zombie processes and log what happened to them */
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
- for (i = 1; i <= MAXSRV; i++) {
- if (srv[i].pid == pid) {
- srv[i].pid = 0;
-#if 0
- free(srv[i].name);
-#endif
- close(srv[i].control_fd);
- break;
- }
+ for (i = 0; i < MAXVOLS; i++) {
+ if (srv[i].pid == pid) {
+ srv[i].pid = 0;
+ free(srv[i].name);
+ srv[i].name = NULL;
+ close(srv[i].control_fd);
+ break;
+ }
}
- if (WIFEXITED(status)) {
- LOG(log_info, logtype_cnid, "cnid_dbd pid %i exited with exit code %i",
- pid, WEXITSTATUS(status));
- }
- else if (WIFSIGNALED(status)) {
- LOG(log_info, logtype_cnid, "cnid_dbd pid %i exited with signal %i",
- pid, WTERMSIG(status));
- }
- /* FIXME should */
-
- }
+ if (WIFEXITED(status)) {
+ LOG(log_info, logtype_cnid, "cnid_dbd pid %i exited with exit code %i",
+ pid, WEXITSTATUS(status));
+ }
+ else if (WIFSIGNALED(status)) {
+ LOG(log_info, logtype_cnid, "cnid_dbd pid %i exited with signal %i",
+ pid, WTERMSIG(status));
+ }
+ /* FIXME should */
+
+ }
if (rqstfd <= 0)
continue;
SIGIPE ignored there? Answer: Ignored for dsi, but not for asp ... */
alarm(5); /* to prevent read from getting stuck */
ret = read(rqstfd, &len, sizeof(int));
- alarm(0);
- if (alarmed) {
- alarmed = 0;
- LOG(log_severe, logtype_cnid, "Read(1) bailed with alarm (timeout)");
- goto loop_end;
- }
-
+ alarm(0);
+ if (alarmed) {
+ alarmed = 0;
+ LOG(log_severe, logtype_cnid, "Read(1) bailed with alarm (timeout)");
+ goto loop_end;
+ }
+
if (!ret) {
/* already close */
goto loop_end;
goto loop_end;
}
/*
- * checks for buffer overruns. The client libatalk side does it too
+ * checks for buffer overruns. The client libatalk side does it too
* before handing the dir path over but who trusts clients?
*/
if (!len || len +DBHOMELEN +2 > MAXPATHLEN) {
LOG(log_error, logtype_cnid, "wrong len parameter: %d", len);
goto loop_end;
}
-
+
alarm(5);
- actual_len = read(rqstfd, dbdir, len);
- alarm(0);
- if (alarmed) {
- alarmed = 0;
- LOG(log_severe, logtype_cnid, "Read(2) bailed with alarm (timeout)");
- goto loop_end;
- }
+ actual_len = read(rqstfd, dbdir, len);
+ alarm(0);
+ if (alarmed) {
+ alarmed = 0;
+ LOG(log_severe, logtype_cnid, "Read(2) bailed with alarm (timeout)");
+ goto loop_end;
+ }
if (actual_len != len) {
LOG(log_error, logtype_cnid, "error/short read (dir): %s", strerror(errno));
goto loop_end;
}
dbdir[len] = '\0';
-
+
if (set_dbdir(dbdir, len) < 0) {
goto loop_end;
}
-
- if ((dbp = db_param_read(dbdir)) == NULL) {
+
+ if ((dbp = db_param_read(dbdir, METAD)) == NULL) {
LOG(log_error, logtype_cnid, "Error reading config file");
goto loop_end;
}
- maybe_start_dbd(dbdpn, dbdir, dbp->usock_file);
+ maybe_start_dbd(dbdpn, dbdir, dbp->usock_file);
loop_end:
close(rqstfd);
/*
- * $Id: comm.c,v 1.2 2005-04-28 20:49:47 bfernhomberg Exp $
+ * $Id: comm.c,v 1.3 2009-04-21 08:55:44 franklahm Exp $
*
* Copyright (C) Joerg Lenneis 2003
* All Rights Reserved. See COPYING.
#ifdef HAVE_CONFIG_H
#include "config.h"
-#endif
+#endif
#include <stdio.h>
#include <stdlib.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
-#endif
+#endif
#include <sys/param.h>
#define _XPG4_2 1
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
-#endif
+#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
-#endif
+#endif
#ifdef HAVE_SYS_UIO_H
#include <sys/uio.h>
-#endif
+#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
/* Length of the space taken up by a padded control message of length len */
#ifndef CMSG_SPACE
-#define CMSG_SPACE(len) (__CMSG_ALIGN(sizeof(struct cmsghdr)) + __CMSG_ALIGN(len))
+#define CMSG_SPACE(len) (__CMSG_ALIGN(sizeof(struct cmsghdr)) + __CMSG_ALIGN(len))
#endif
if (fd == control_fd)
return;
- for (i = 0; i != fds_in_use; i++)
- if (fd_table[i].fd == fd)
- break;
-
+ for (i = 0; i != fds_in_use; i++)
+ if (fd_table[i].fd == fd)
+ break;
+
assert(i < fds_in_use);
fds_in_use--;
fd_table[i] = fd_table[fds_in_use];
fd_table[fds_in_use].fd = -1;
- close(fd);
+ close(fd);
return;
}
static int recv_cred(int fd)
{
-int ret;
-struct msghdr msgh;
-struct iovec iov[1];
-struct cmsghdr *cmsgp = NULL;
-char buf[CMSG_SPACE(sizeof(int))];
-char dbuf[80];
+ int ret;
+ struct msghdr msgh;
+ struct iovec iov[1];
+ struct cmsghdr *cmsgp = NULL;
+ char buf[CMSG_SPACE(sizeof(int))];
+ char dbuf[80];
memset(&msgh,0,sizeof(msgh));
memset(buf,0,sizeof(buf));
msgh.msg_controllen = sizeof(buf);
do {
- ret = recvmsg(fd ,&msgh,0);
+ ret = recvmsg(fd ,&msgh,0);
} while ( ret == -1 && errno == EINTR );
if ( ret == -1 ) {
return -1;
}
-
+
for ( cmsgp = CMSG_FIRSTHDR(&msgh); cmsgp != NULL; cmsgp = CMSG_NXTHDR(&msgh,cmsgp) ) {
if ( cmsgp->cmsg_level == SOL_SOCKET && cmsgp->cmsg_type == SCM_RIGHTS ) {
- return *(int *) CMSG_DATA(cmsgp);
+ return *(int *) CMSG_DATA(cmsgp);
}
}
if ( ret == sizeof (int) )
- errno = *(int *)dbuf; /* Rcvd errno */
+ errno = *(int *)dbuf; /* Rcvd errno */
else
- errno = ENOENT; /* Default errno */
-
+ errno = ENOENT; /* Default errno */
+
return -1;
}
int i;
int maxfd = control_fd;
time_t t;
-
+
FD_ZERO(&readfds);
FD_SET(control_fd, &readfds);
-
+
for (i = 0; i != fds_in_use; i++) {
- FD_SET(fd_table[i].fd, &readfds);
- if (maxfd < fd_table[i].fd)
- maxfd = fd_table[i].fd;
+ FD_SET(fd_table[i].fd, &readfds);
+ if (maxfd < fd_table[i].fd)
+ maxfd = fd_table[i].fd;
}
tv.tv_usec = 0;
}
if (!ret)
- return 0;
+ return 0;
time(&t);
if (FD_ISSET(control_fd, &readfds)) {
- int l = 0;
-
+ int l = 0;
+
fd = recv_cred(control_fd);
if (fd < 0) {
return -1;
}
- if (fds_in_use < fd_table_size) {
- fd_table[fds_in_use].fd = fd;
- fd_table[fds_in_use].tm = t;
- fds_in_use++;
- } else {
- time_t older = t;
-
- for (i = 0; i != fds_in_use; i++) {
- if (older <= fd_table[i].tm) {
- older = fd_table[i].tm;
- l = i;
- }
- }
- close(fd_table[l].fd);
- fd_table[l].fd = fd;
- fd_table[l].tm = t;
- }
- return 0;
+ if (fds_in_use < fd_table_size) {
+ fd_table[fds_in_use].fd = fd;
+ fd_table[fds_in_use].tm = t;
+ fds_in_use++;
+ } else {
+ time_t older = t;
+
+ for (i = 0; i != fds_in_use; i++) {
+ if (older <= fd_table[i].tm) {
+ older = fd_table[i].tm;
+ l = i;
+ }
+ }
+ close(fd_table[l].fd);
+ fd_table[l].fd = fd;
+ fd_table[l].tm = t;
+ }
+ return 0;
}
for (i = 0; i != fds_in_use; i++) {
- if (FD_ISSET(fd_table[i].fd, &readfds)) {
- fd_table[i].tm = t;
- return fd_table[i].fd;
- }
- }
+ if (FD_ISSET(fd_table[i].fd, &readfds)) {
+ fd_table[i].tm = t;
+ return fd_table[i].fd;
+ }
+ }
/* We should never get here */
return 0;
}
fds_in_use = 0;
fd_table_size = dbp->fd_table_size;
-
+
if ((fd_table = malloc(fd_table_size * sizeof(struct connection))) == NULL) {
LOG(log_error, logtype_cnid, "Out of memory");
- return -1;
+ return -1;
}
for (i = 0; i != fd_table_size; i++)
- fd_table[i].fd = -1;
+ fd_table[i].fd = -1;
/* from dup2 */
control_fd = ctrlfd;
#if 0
/* this one dump core in recvmsg, great */
if ( setsockopt(control_fd, SOL_SOCKET, SO_PASSCRED, &b, sizeof (b)) < 0) {
LOG(log_error, logtype_cnid, "setsockopt SO_PASSCRED %s", strerror(errno));
- return -1;
+ return -1;
}
#endif
/* push the first client fd */
fd_table[fds_in_use].fd = clntfd;
fds_in_use++;
-
+
return 0;
}
-/* ------------
+/* ------------
nbe of clients
*/
int comm_nbe(void)
return 0;
nametmp = rqst->name;
if ((b = read(cur_fd, rqst, sizeof(struct cnid_dbd_rqst))) != sizeof(struct cnid_dbd_rqst)) {
- if (b)
- LOG(log_error, logtype_cnid, "error reading message header: %s", strerror(errno));
+ if (b)
+ LOG(log_error, logtype_cnid, "error reading message header: %s", strerror(errno));
invalidate_fd(cur_fd);
rqst->name = nametmp;
return 0;
/* We set this to make life easier for logging. None of the other stuff
needs zero terminated strings. */
rqst->name[rqst->namelen] = '\0';
-
+
return 1;
}
#define USE_WRITEV
int comm_snd(struct cnid_dbd_rply *rply)
{
-#ifdef USE_WRITEV
- struct iovec iov[2];
- size_t towrite;
+#ifdef USE_WRITEV
+ struct iovec iov[2];
+ size_t towrite;
#endif
if (!rply->namelen) {
}
return 1;
}
-#ifdef USE_WRITEV
+#ifdef USE_WRITEV
iov[0].iov_base = rply;
iov[0].iov_len = sizeof(struct cnid_dbd_rply);
invalidate_fd(cur_fd);
return 0;
}
-#endif
+#endif
return 1;
}
/*
- * $Id: db_param.c,v 1.3 2009-02-04 20:28:01 didg Exp $
+ * $Id: db_param.c,v 1.4 2009-04-21 08:55:44 franklahm Exp $
*
* Copyright (C) Joerg Lenneis 2003
+ * Copyright (c) Frank Lahm 2009
* All Rights Reserved. See COPYING.
*/
#include <errno.h>
#include <sys/param.h>
#include <sys/un.h>
-
-
#include <atalk/logger.h>
#include "db_param.h"
-
#define DB_PARAM_FN "db_param"
#define MAXKEYLEN 64
-#define DEFAULT_LOGFILE_AUTOREMOVE 0
-#define DEFAULT_CACHESIZE 1024 * 4
-#define DEFAULT_NOSYNC 0
-#define DEFAULT_FLUSH_FREQUENCY 100
-#define DEFAULT_FLUSH_INTERVAL 30
+#define DEFAULT_LOGFILE_AUTOREMOVE 1
+#define DEFAULT_CACHESIZE 8 * 1024
+#define DEFAULT_FLUSH_FREQUENCY 100
+#define DEFAULT_FLUSH_INTERVAL 1800
#define DEFAULT_USOCK_FILE "usock"
-#define DEFAULT_FD_TABLE_SIZE 64
-#define DEFAULT_IDLE_TIMEOUT 600
-#define DEFAULT_CHECK 0
+#define DEFAULT_FD_TABLE_SIZE 128
+#define DEFAULT_IDLE_TIMEOUT 10 * 60
static struct db_param params;
static int parse_err;
static size_t usock_maxlen()
{
struct sockaddr_un addr;
-
return sizeof(addr.sun_path) - 1;
}
static void default_params(struct db_param *dbp, char *dir)
{
- dbp->check = DEFAULT_CHECK;
dbp->logfile_autoremove = DEFAULT_LOGFILE_AUTOREMOVE;
dbp->cachesize = DEFAULT_CACHESIZE;
- dbp->nosync = DEFAULT_NOSYNC;
dbp->flush_frequency = DEFAULT_FLUSH_FREQUENCY;
dbp->flush_interval = DEFAULT_FLUSH_INTERVAL;
if (make_pathname(dbp->usock_file, dir, DEFAULT_USOCK_FILE, usock_maxlen()) < 0) {
}
dbp->fd_table_size = DEFAULT_FD_TABLE_SIZE;
dbp->idle_timeout = DEFAULT_IDLE_TIMEOUT;
+
return;
}
buffer overflow) nor elegant, we need to add support for whitespace in
filenames as well. */
-struct db_param *db_param_read(char *dir)
+struct db_param *db_param_read(char *dir, enum identity id)
{
FILE *fp;
static char key[MAXKEYLEN + 1];
int items;
default_params(¶ms, dir);
+ params.dir = dir;
if (make_pathname(pfn, dir, DB_PARAM_FN, MAXPATHLEN) < 0) {
LOG(log_error, logtype_cnid, "Parameter filename too long");
parse_err++;
break;
}
-
- if (! strcmp(key, "logfile_autoremove"))
- params.logfile_autoremove = parse_int(val);
- else if (! strcmp(key, "cachesize"))
- params.cachesize = parse_int(val);
- else if (! strcmp(key, "nosync"))
- params.nosync = parse_int(val);
- else if (! strcmp(key, "check"))
- params.check = parse_int(val);
- else if (! strcmp(key, "flush_frequency"))
- params.flush_frequency = parse_int(val);
- else if (! strcmp(key, "flush_interval"))
- params.flush_interval = parse_int(val);
- else if (! strcmp(key, "usock_file")) {
+
+ /* Config for both cnid_meta and dbd */
+ if (! strcmp(key, "usock_file")) {
if (make_pathname(params.usock_file, dir, val, usock_maxlen()) < 0) {
LOG(log_error, logtype_cnid, "usock filename %s too long", val);
parse_err++;
+ } else
+ LOG(log_info, logtype_cnid, "db_param: setting UNIX domain socket filename to %s", params.usock_file);
+ }
+
+ /* Config for cnid_metad only */
+ if ( id == METAD ) {
+ /* Currently empty */
+ }
+
+ /* Config for dbd only */
+ else if (id == DBD ) {
+ if (! strcmp(key, "fd_table_size")) {
+ params.fd_table_size = parse_int(val);
+ LOG(log_info, logtype_cnid, "db_param: setting max number of concurrent afpd connections per volume (fd_table_size) to %d", params.fd_table_size);
+ } else if (! strcmp(key, "logfile_autoremove")) {
+ params.logfile_autoremove = parse_int(val);
+ LOG(log_info, logtype_cnid, "db_param: setting logfile_autoremove to %d", params.logfile_autoremove);
+ } else if (! strcmp(key, "cachesize")) {
+ params.cachesize = parse_int(val);
+ LOG(log_info, logtype_cnid, "db_param: setting cachesize to %d", params.cachesize);
+ } else if (! strcmp(key, "flush_frequency")) {
+ params.flush_frequency = parse_int(val);
+ LOG(log_info, logtype_cnid, "db_param: setting flush_frequency to %d", params.flush_frequency);
+ } else if (! strcmp(key, "flush_interval")) {
+ params.flush_interval = parse_int(val);
+ LOG(log_info, logtype_cnid, "db_param: setting flush_interval to %d", params.flush_interval);
+ } else if (! strcmp(key, "idle_timeout")) {
+ params.idle_timeout = parse_int(val);
+ LOG(log_info, logtype_cnid, "db_param: setting idle timeout to %d", params.idle_timeout);
}
- } else if (! strcmp(key, "fd_table_size"))
- params.fd_table_size = parse_int(val);
- else if (! strcmp(key, "idle_timeout"))
- params.idle_timeout = parse_int(val);
- else {
- LOG(log_error, logtype_cnid, "error parsing %s -> %s in config file", key, val);
- parse_err++;
}
- if(parse_err)
+ if (parse_err)
break;
}
/*
- * $Id: db_param.h,v 1.2 2005-04-28 20:49:47 bfernhomberg Exp $
+ * $Id: db_param.h,v 1.3 2009-04-21 08:55:44 franklahm Exp $
*
* Copyright (C) Joerg Lenneis 2003
* All Rights Reserved. See COPYING.
#include <sys/param.h>
#include <sys/cdefs.h>
+enum identity {
+ METAD,
+ DBD
+};
struct db_param {
- int check;
+ char *dir;
int logfile_autoremove;
int cachesize;
- int nosync;
- int flush_frequency;
int flush_interval;
+ int flush_frequency;
char usock_file[MAXPATHLEN + 1];
int fd_table_size;
int idle_timeout;
+ int max_vols;
};
-extern struct db_param * db_param_read __P((char *));
+extern struct db_param * db_param_read __P((char *, enum identity));
#endif /* CNID_DBD_DB_PARAM_H */
/*
- * $Id: dbd.h,v 1.2 2005-04-28 20:49:47 bfernhomberg Exp $
+ * $Id: dbd.h,v 1.3 2009-04-21 08:55:44 franklahm Exp $
*
* Copyright (C) Joerg Lenneis 2003
* All Rights Reserved. See COPYING.
#ifndef CNID_DBD_DBD_H
#define CNID_DBD_DBD_H 1
-
#include <atalk/cnid_dbd_private.h>
extern int dbd_stamp __P((void));
extern int dbd_delete __P((struct cnid_dbd_rqst *, struct cnid_dbd_rply *));
extern int dbd_getstamp __P((struct cnid_dbd_rqst *, struct cnid_dbd_rply *));
extern int dbd_rebuild_add __P((struct cnid_dbd_rqst *, struct cnid_dbd_rply *));
-extern int dbd_check __P((char *));
-
+extern int dbd_check_indexes __P((char *));
#endif /* CNID_DBD_DBD_H */
/*
- * $Id: dbd_add.c,v 1.2 2005-04-28 20:49:47 bfernhomberg Exp $
+ * $Id: dbd_add.c,v 1.3 2009-04-21 08:55:44 franklahm Exp $
*
* Copyright (C) Joerg Lenneis 2003
* All Rights Reserved. See COPYING.
cnid_t hint;
char buf[ROOTINFO_DATALEN];
char stamp[CNID_DEV_LEN];
-
+
memset(&rootinfo_key, 0, sizeof(rootinfo_key));
memset(&rootinfo_data, 0, sizeof(rootinfo_data));
rootinfo_key.data = ROOTINFO_KEY;
/*
- * $Id: dbd_dbcheck.c,v 1.2 2005-04-28 20:49:48 bfernhomberg Exp $
+ * $Id: dbd_dbcheck.c,v 1.3 2009-04-21 08:55:44 franklahm Exp $
*
* Copyright (C) Joerg Lenneis 2003
* All Rights Reserved. See COPYING.
#include "dbif.h"
#include "dbd.h"
-#ifndef CNID_BACKEND_DBD_TXN
-int dbd_check(char *dbdir)
+int dbd_check_indexes(char *dbdir)
{
u_int32_t c_didname = 0, c_devino = 0, c_cnid = 0;
-#if 0
- char dbdir[MAXPATHLEN];
- if (NULL == getcwd(dbdir, sizeof(dbdir)) )
- return -1;
-#endif
-
- LOG(log_debug, logtype_cnid, "CNID database at `%s' is being checked (quick)", dbdir);
+ LOG(log_note, logtype_cnid, "CNID database at `%s' is being checked (quick)", dbdir);
if (dbif_count(DBIF_IDX_CNID, &c_cnid))
return -1;
return 1;
}
- LOG(log_debug, logtype_cnid, "CNID database at `%s' seems ok, %u entries.", dbdir, c_cnid);
+ LOG(log_note, logtype_cnid, "CNID database at `%s' seems ok, %u entries.", dbdir, c_cnid);
return 0;
}
-#endif
/*
- * $Id: dbd_getstamp.c,v 1.2 2005-04-28 20:49:48 bfernhomberg Exp $
+ * $Id: dbd_getstamp.c,v 1.3 2009-04-21 08:55:44 franklahm Exp $
*
* Copyright (C) Joerg Lenneis 2003
* All Rights Reserved. See COPYING.
rply->namelen = CNID_DEV_LEN;
rply->name = (char *)data.data + CNID_DEV_OFS;
-#ifdef DEBUG
- LOG(log_info, logtype_cnid, "cnid_getstamp: Returning stamp");
-#endif
+
+ LOG(log_debug, logtype_cnid, "cnid_getstamp: Returning stamp '%08x'", *(uint32_t *)rply->name);
+
rply->result = CNID_DBD_RES_OK;
return 1;
}
/*
- * $Id: dbd_lookup.c,v 1.3 2005-05-03 14:55:11 didg Exp $
+ * $Id: dbd_lookup.c,v 1.4 2009-04-21 08:55:44 franklahm Exp $
*
* Copyright (C) Joerg Lenneis 2003
* All Rights Reserved. See COPYING.
unsigned char *buf;
DBT key, devdata, diddata;
char dev[CNID_DEV_LEN];
+#if 0
char ino[CNID_INO_LEN];
+#endif
int devino = 1, didname = 1;
int rc;
cnid_t id_devino, id_didname;
buf = pack_cnid_data(rqst);
memcpy(dev, buf + CNID_DEV_OFS, CNID_DEV_LEN);
+#if 0
/* FIXME: ino is not needed later on, remove? */
memcpy(ino, buf + CNID_INO_OFS, CNID_INO_LEN);
+#endif
/* Look for a CNID. We have two options: dev/ino or did/name. If we
only get a match in one of them, that means a file has moved. */
- key.data = buf +CNID_DEVINO_OFS;
+ key.data = buf + CNID_DEVINO_OFS;
key.size = CNID_DEVINO_LEN;
if ((rc = dbif_get(DBIF_IDX_DEVINO, &key, &devdata, 0)) < 0) {
memcpy(&type_devino, (char *)devdata.data +CNID_TYPE_OFS, sizeof(type_devino));
type_devino = ntohl(type_devino);
}
-
- /* FIXME: This second call to pack_cnid_data() is redundant, any reason it is here? */
- buf = pack_cnid_data(rqst);
- key.data = buf +CNID_DID_OFS;
+
+ key.data = buf + CNID_DID_OFS;
key.size = CNID_DID_LEN + rqst->namelen + 1;
if ((rc = dbif_get(DBIF_IDX_DIDNAME, &key, &diddata, 0)) < 0) {
if (!devino && !didname) {
/* not found */
-#ifdef DEBUG
- LOG(log_info, logtype_cnid, "cnid_lookup: dev/ino %s did %u name %s neither in devino nor didname",
- stringify_devino(rqst->dev, rqst->ino), ntohl(rqst->did), rqst->name);
-#endif
+
+ LOG(log_debug, logtype_cnid, "cnid_lookup: dev/ino %s did %u name %s neither in devino nor didname",
+ stringify_devino(rqst->dev, rqst->ino), ntohl(rqst->did), rqst->name);
+
rply->result = CNID_DBD_RES_NOTFOUND;
return 1;
}
if (devino && didname && id_devino == id_didname && type_devino == rqst->type) {
/* the same */
-#ifdef DEBUG
- LOG(log_info, logtype_cnid, "cnid_lookup: Looked up dev/ino %s did %u name %s as %u",
- stringify_devino(rqst->dev, rqst->ino), ntohl(rqst->did), rqst->name, ntohl(id_didname));
-#endif
+
+ LOG(log_debug, logtype_cnid, "cnid_lookup: Looked up dev/ino %s did %u name %s as %u",
+ stringify_devino(rqst->dev, rqst->ino), ntohl(rqst->did), rqst->name, ntohl(id_didname));
+
rply->cnid = id_didname;
rply->result = CNID_DBD_RES_OK;
return 1;
if (rc >0) {
rply->cnid = rqst->cnid;
}
-#ifdef DEBUG
- LOG(log_info, logtype_cnid, "cnid_lookup: Looked up dev/ino %s did %u name %s as %u (needed update)",
- stringify_devino(rqst->dev, rqst->ino), ntohl(rqst->did), rqst->name, ntohl(rply->cnid));
-#endif
+
+ LOG(log_debug, logtype_cnid, "cnid_lookup: Looked up dev/ino %s did %u name %s as %u (needed update)",
+ stringify_devino(rqst->dev, rqst->ino), ntohl(rqst->did), rqst->name, ntohl(rply->cnid));
+
return rc;
}
/*
- * $Id: dbif.c,v 1.4 2008-08-07 07:39:14 didg Exp $
+ * $Id: dbif.c,v 1.5 2009-04-21 08:55:44 franklahm Exp $
*
* Copyright (C) Joerg Lenneis 2003
* All Rights Reserved. See COPYING.
#define DB_ERRLOGFILE "db_errlog"
-
static DB_ENV *db_env = NULL;
static DB_TXN *db_txn = NULL;
static FILE *db_errlog = NULL;
-#ifdef CNID_BACKEND_DBD_TXN
-#define DBOPTIONS (DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN)
-#else
-#define DBOPTIONS (DB_CREATE | DB_INIT_CDB | DB_INIT_MPOOL | DB_PRIVATE)
-#endif
+/*
+ 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)
static struct db_table {
- char *name;
- DB *db;
- u_int32_t general_flags;
- DBTYPE type;
+ char *name;
+ DB *db;
+ u_int32_t general_flags;
+ DBTYPE type;
} db_table[] =
{
- { "cnid2.db", NULL, 0, DB_BTREE},
- { "devino.db", NULL, 0, DB_BTREE},
- { "didname.db", NULL, 0, DB_BTREE},
+ { "cnid2.db", NULL, 0, DB_BTREE},
+ { "devino.db", NULL, 0, DB_BTREE},
+ { "didname.db", NULL, 0, DB_BTREE},
};
static char *old_dbfiles[] = {"cnid.db", NULL};
/* --------------- */
static int db_compat_associate (DB *p, DB *s,
- int (*callback)(DB *, const DBT *,const DBT *, DBT *),
- u_int32_t flags)
+ int (*callback)(DB *, const DBT *,const DBT *, DBT *),
+ u_int32_t flags)
{
-#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
- return p->associate(p, db_txn, s, callback, flags);
-#else
-#if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 0)
- return p->associate(p, s, callback, flags);
-#else
- return 0;
-#endif
-#endif
+ return p->associate(p, NULL, s, callback, flags);
}
/* --------------- */
{
int ret;
-#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
- ret = db->open(db, db_txn, file, name, type, DB_CREATE, mode);
-#else
- ret = db->open(db, file, name, type, DB_CREATE, mode);
-#endif
+ ret = db->open(db, NULL, file, name, type, DB_CREATE, mode);
if (ret) {
LOG(log_error, logtype_cnid, "error opening database %s: %s", name, db_strerror(ret));
int i;
int found = 0;
struct stat st;
-
+
for (i = 0; old_dbfiles[i] != NULL; i++) {
- if ( !(stat(old_dbfiles[i], &st) < 0) ) {
- found++;
- continue;
- }
- if (errno != ENOENT) {
- LOG(log_error, logtype_cnid, "cnid_open: Checking %s gave %s", old_dbfiles[i], strerror(errno));
- found++;
- }
+ if ( !(stat(old_dbfiles[i], &st) < 0) ) {
+ found++;
+ continue;
+ }
+ if (errno != ENOENT) {
+ LOG(log_error, logtype_cnid, "cnid_open: Checking %s gave %s", old_dbfiles[i], strerror(errno));
+ found++;
+ }
}
return found;
}
/* --------------- */
/*
* We assume our current directory is already the BDB homedir. Otherwise
- * opening the databases will not work as expected. If we use transactions,
- * dbif_env_init(), dbif_close() and dbif_stamp() are the only interface
- * functions that can be called without a valid transaction handle in db_txn.
+ * opening the databases will not work as expected.
*/
int dbif_env_init(struct db_param *dbp)
{
int ret;
-#ifdef CNID_BACKEND_DBD_TXN
char **logfiles = NULL;
char **file;
-#endif
/* Refuse to do anything if this is an old version of the CNID database */
if (upgrade_required()) {
- LOG(log_error, logtype_cnid, "Found version 1 of the CNID database. Please upgrade to version 2");
- return -1;
+ LOG(log_error, logtype_cnid, "Found version 1 of the CNID database. Please upgrade to version 2");
+ return -1;
}
if ((db_errlog = fopen(DB_ERRLOGFILE, "a")) == NULL)
LOG(log_warning, logtype_cnid, "error creating/opening DB errlogfile: %s", strerror(errno));
-#ifdef CNID_BACKEND_DBD_TXN
if ((ret = db_env_create(&db_env, 0))) {
- LOG(log_error, logtype_cnid, "error creating DB environment: %s",
+ LOG(log_error, logtype_cnid, "error creating DB environment: %s",
db_strerror(ret));
db_env = NULL;
return -1;
- }
- if (db_errlog != NULL)
- db_env->set_errfile(db_env, db_errlog);
+ }
+
+ if (db_errlog != NULL) {
+ db_env->set_errfile(db_env, db_errlog);
+ db_env->set_msgfile(db_env, db_errlog);
+ }
+
db_env->set_verbose(db_env, DB_VERB_RECOVERY, 1);
+
+ /* Open the database for recovery using DB_PRIVATE option which is faster */
if ((ret = db_env->open(db_env, ".", DBOPTIONS | DB_PRIVATE | DB_RECOVER, 0))) {
- LOG(log_error, logtype_cnid, "error opening DB environment: %s",
+ LOG(log_error, logtype_cnid, "error opening DB environment: %s",
db_strerror(ret));
db_env->close(db_env, 0);
db_env = NULL;
fflush(db_errlog);
if ((ret = db_env->close(db_env, 0))) {
- LOG(log_error, logtype_cnid, "error closing DB environment after recovery: %s",
+ LOG(log_error, logtype_cnid, "error closing DB environment after recovery: %s",
db_strerror(ret));
db_env = NULL;
return -1;
}
-#endif
+
if ((ret = db_env_create(&db_env, 0))) {
LOG(log_error, logtype_cnid, "error creating DB environment after recovery: %s",
db_strerror(ret));
db_env = NULL;
return -1;
}
+
if ((ret = db_env->set_cachesize(db_env, 0, 1024 * dbp->cachesize, 0))) {
LOG(log_error, logtype_cnid, "error setting DB environment cachesize to %i: %s",
dbp->cachesize, db_strerror(ret));
db_env = NULL;
return -1;
}
-
- if (db_errlog != NULL)
+
+ if (db_errlog != NULL) {
db_env->set_errfile(db_env, db_errlog);
+ db_env->set_msgfile(db_env, db_errlog);
+ }
if ((ret = db_env->open(db_env, ".", DBOPTIONS , 0))) {
LOG(log_error, logtype_cnid, "error opening DB environment after recovery: %s",
db_strerror(ret));
db_env->close(db_env, 0);
db_env = NULL;
- return -1;
+ return -1;
}
-#ifdef CNID_BACKEND_DBD_TXN
- if (dbp->nosync && (ret = db_env->set_flags(db_env, DB_TXN_NOSYNC, 1))) {
- LOG(log_error, logtype_cnid, "error setting TXN_NOSYNC flag: %s",
+ if ((ret = db_env->set_flags(db_env, DB_AUTO_COMMIT, 1))) {
+ LOG(log_error, logtype_cnid, "error setting DB_AUTO_COMMIT flag: %s",
db_strerror(ret));
db_env->close(db_env, 0);
db_env = NULL;
return -1;
}
+
if (dbp->logfile_autoremove && db_env->log_archive(db_env, &logfiles, 0)) {
- LOG(log_error, logtype_cnid, "error getting list of stale logfiles: %s",
+ LOG(log_error, logtype_cnid, "error getting list of stale logfiles: %s",
db_strerror(ret));
db_env->close(db_env, 0);
db_env = NULL;
return -1;
}
if (logfiles != NULL) {
- for (file = logfiles; *file != NULL; file++) {
- if (unlink(*file) < 0)
- LOG(log_warning, logtype_cnid, "Error removing stale logfile %s: %s", *file, strerror(errno));
- }
- free(logfiles);
+ for (file = logfiles; *file != NULL; file++) {
+ if (unlink(*file) < 0)
+ LOG(log_warning, logtype_cnid, "Error removing stale logfile %s: %s", *file, strerror(errno));
+ }
+ free(logfiles);
}
-#endif
+
return 0;
}
for (i = 0; i != DBIF_DB_CNT; i++) {
if ((ret = db_create(&(db_table[i].db), db_env, 0))) {
- LOG(log_error, logtype_cnid, "error creating handle for database %s: %s",
+ LOG(log_error, logtype_cnid, "error creating handle for database %s: %s",
db_table[i].name, db_strerror(ret));
return -1;
}
- if (db_table[i].general_flags) {
+ if (db_table[i].general_flags) {
if ((ret = db_table[i].db->set_flags(db_table[i].db, db_table[i].general_flags))) {
- LOG(log_error, logtype_cnid, "error setting flags for database %s: %s",
+ LOG(log_error, logtype_cnid, "error setting flags for database %s: %s",
db_table[i].name, db_strerror(ret));
return -1;
}
}
-#if 0
-#ifndef CNID_BACKEND_DBD_TXN
- if ((ret = db_table[i].db->set_cachesize(db_table[i].db, 0, 1024 * dbp->cachesize, 0))) {
- LOG(log_error, logtype_cnid, "error setting DB cachesize to %i for database %s: %s",
- dbp->cachesize, db_table[i].name, db_strerror(ret));
- return -1;
- }
-#endif /* CNID_BACKEND_DBD_TXN */
-#endif
if (db_compat_open(db_table[i].db, db_table[0].name, db_table[i].name, db_table[i].type, 0664) < 0)
return -1;
if (db_errlog != NULL)
db_table[i].db->set_errfile(db_table[i].db, db_errlog);
if (do_truncate && i > 0) {
- if ((ret = db_table[i].db->truncate(db_table[i].db, db_txn, &count, 0))) {
- LOG(log_error, logtype_cnid, "error truncating database %s: %s",
+ if ((ret = db_table[i].db->truncate(db_table[i].db, NULL, &count, 0))) {
+ LOG(log_error, logtype_cnid, "error truncating database %s: %s",
db_table[i].name, db_strerror(ret));
return -1;
}
}
/* TODO: Implement CNID DB versioning info on new databases. */
- /* TODO: Make transaction support a runtime option. */
+
/* Associate the secondary with the primary. */
if ((ret = db_compat_associate(db_table[0].db, db_table[DBIF_IDX_DIDNAME].db, didname, (do_truncate)?DB_CREATE:0)) != 0) {
LOG(log_error, logtype_cnid, "Failed to associate didname database: %s",db_strerror(ret));
return -1;
}
-
+
if ((ret = db_compat_associate(db_table[0].db, db_table[DBIF_IDX_DEVINO].db, devino, (do_truncate)?DB_CREATE:0)) != 0) {
LOG(log_error, logtype_cnid, "Failed to associate devino database: %s",db_strerror(ret));
- return -1;
+ return -1;
}
return 0;
{
int ret;
int err = 0;
-
- if (dbif_closedb())
- err++;
-
- if (db_env != NULL && (ret = db_env->close(db_env, 0))) {
+
+ if (dbif_closedb())
+ err++;
+
+ if (db_env != NULL && (ret = db_env->close(db_env, 0))) {
LOG(log_error, logtype_cnid, "error closing DB environment: %s", db_strerror(ret));
err++;
}
}
/*
- * The following three functions are wrappers for DB->get(), DB->put() and
- * DB->del(). We define them here because we want access to the db_txn
- * transaction handle and the database handles limited to the functions in this
- * file. A consequence is that there is always only one transaction in
- * progress. For nontransactional access db_txn is NULL. All three return -1 on
- * error. dbif_get()/dbif_del return 1 if the key was found and 0
+ * The following three functions are wrappers for DB->get(), DB->put() and DB->del().
+ * All three return -1 on error. dbif_get()/dbif_del return 1 if the key was found and 0
* otherwise. dbif_put() returns 0 if key/val was successfully updated and 1 if
* the DB_NOOVERWRITE flag was specified and the key already exists.
- *
+ *
* All return codes other than DB_NOTFOUND and DB_KEYEXIST from the DB->()
* functions are not expected and therefore error conditions.
*/
DB *db = db_table[dbi].db;
ret = db->get(db, db_txn, key, val, flags);
-
+
if (ret == DB_NOTFOUND)
return 0;
if (ret) {
LOG(log_error, logtype_cnid, "error retrieving value from %s: %s", db_table[dbi].name, db_strerror(errno));
return -1;
- } else
+ } else
return 1;
}
ret = db->pget(db, db_txn, key, pkey, val, flags);
-#if DB_VERSION_MAJOR >= 4
if (ret == DB_NOTFOUND || ret == DB_SECONDARY_BAD) {
-#else
- if (ret == DB_NOTFOUND) {
-#endif
return 0;
}
if (ret) {
LOG(log_error, logtype_cnid, "error retrieving value from %s: %s", db_table[dbi].name, db_strerror(errno));
return -1;
- } else
+ } else
return 1;
}
int ret;
DB *db = db_table[dbi].db;
+ if (dbif_txn_begin() < 0) {
+ LOG(log_error, logtype_cnid, "error setting key/value in %s: %s", db_table[dbi].name, db_strerror(errno));
+ return -1;
+ }
+
ret = db->put(db, db_txn, key, val, flags);
-
+
if (ret) {
if ((flags & DB_NOOVERWRITE) && ret == DB_KEYEXIST) {
return 1;
int ret;
DB *db = db_table[dbi].db;
+ if (dbif_txn_begin() < 0) {
+ LOG(log_error, logtype_cnid, "error deleting key/value from %s: %s", db_table[dbi].name, db_strerror(errno));
+ return -1;
+ }
+
ret = db->del(db, db_txn, key, flags);
-#if DB_VERSION_MAJOR > 3
if (ret == DB_NOTFOUND || ret == DB_SECONDARY_BAD)
-#else
- if (ret == DB_NOTFOUND)
-#endif
return 0;
if (ret) {
LOG(log_error, logtype_cnid, "error deleting key/value from %s: %s", db_table[dbi].name, db_strerror(errno));
return 1;
}
-#ifdef CNID_BACKEND_DBD_TXN
-
int dbif_txn_begin()
{
int ret;
-#if DB_VERSION_MAJOR >= 4
+
+ /* If we already have a acitve txn, just return */
+ if (db_txn)
+ return 0;
+
ret = db_env->txn_begin(db_env, NULL, &db_txn, 0);
-#else
- ret = txn_begin(db_env, NULL, &db_txn, 0);
-#endif
+
if (ret) {
LOG(log_error, logtype_cnid, "error starting transaction: %s", db_strerror(errno));
return -1;
- } else
+ } else
return 0;
}
int dbif_txn_commit()
{
int ret;
-#if DB_VERSION_MAJOR >= 4
+
+ if (!db_txn)
+ return 0;
+
ret = db_txn->commit(db_txn, 0);
-#else
- ret = txn_commit(db_txn, 0);
-#endif
+ db_txn = NULL;
+
if (ret) {
LOG(log_error, logtype_cnid, "error committing transaction: %s", db_strerror(errno));
return -1;
- } else
- return 0;
+ } else
+ return 1;
}
int dbif_txn_abort()
{
int ret;
-#if DB_VERSION_MAJOR >= 4
+
+ if (!db_txn)
+ return 0;
+
ret = db_txn->abort(db_txn);
-#else
- ret = txn_abort(db_txn);
-#endif
+ db_txn = NULL;
+
if (ret) {
LOG(log_error, logtype_cnid, "error aborting transaction: %s", db_strerror(errno));
return -1;
int dbif_txn_checkpoint(u_int32_t kbyte, u_int32_t min, u_int32_t flags)
{
int ret;
-#if DB_VERSION_MAJOR >= 4
ret = db_env->txn_checkpoint(db_env, kbyte, min, flags);
-#else
- ret = txn_checkpoint(db_env, kbyte, min, flags);
-#endif
if (ret) {
LOG(log_error, logtype_cnid, "error checkpointing transaction susystem: %s", db_strerror(errno));
return -1;
- } else
- return 0;
-}
-
-#else
-
-int dbif_sync()
-{
- int i;
- int ret;
- int err = 0;
-
- for (i = 0; i != /* DBIF_DB_CNT*/ 1; i++) {
- if ((ret = db_table[i].db->sync(db_table[i].db, 0))) {
- LOG(log_error, logtype_cnid, "error syncing database %s: %s", db_table[i].name, db_strerror(ret));
- err++;
- }
- }
-
- if (err)
- return -1;
- else
+ } else
return 0;
}
-
-int dbif_count(const int dbi, u_int32_t *count)
+int dbif_count(const int dbi, u_int32_t *count)
{
int ret;
DB_BTREE_STAT *sp;
DB *db = db_table[dbi].db;
-#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3)
- ret = db->stat(db, db_txn, &sp, 0);
-#else
- ret = db->stat(db, &sp, 0);
-#endif
+ ret = db->stat(db, NULL, &sp, 0);
if (ret) {
LOG(log_error, logtype_cnid, "error getting stat infotmation on database: %s", db_strerror(errno));
return 0;
}
-#endif /* CNID_BACKEND_DBD_TXN */
+
/*
- * $Id: dbif.h,v 1.2 2005-04-28 20:49:48 bfernhomberg Exp $
+ * $Id: dbif.h,v 1.3 2009-04-21 08:55:44 franklahm Exp $
*
* Copyright (C) Joerg Lenneis 2003
* All Rights Reserved. See COPYING.
extern int dbif_count __P((const int, u_int32_t *));
-
-#ifdef CNID_BACKEND_DBD_TXN
extern int dbif_txn_begin __P((void));
extern int dbif_txn_commit __P((void));
extern int dbif_txn_abort __P((void));
extern int dbif_txn_checkpoint __P((u_int32_t, u_int32_t, u_int32_t));
-#else
-extern int dbif_sync __P((void));
-#endif /* CNID_BACKEND_DBD_TXN */
#endif
/*
- * $Id: main.c,v 1.3 2009-03-31 11:40:26 franklahm Exp $
+ * $Id: main.c,v 1.4 2009-04-21 08:55:44 franklahm Exp $
*
* Copyright (C) Joerg Lenneis 2003
+ * Copyright (c) Frank Lahm 2009
* All Rights Reserved. See COPYING.
*/
+/*
+ dbd and transactions
+ ====================
+
+ We use AUTO_COMMIT for our BerkeleyDB environment. This avoids explicit transactions
+ for every bdb access which speeds up reads. But in order to be able to rollback
+ in case of errors we start a transaction once we encounter the first write.
+ The logic to do this is stuffed two levels lower into the dbif.c file and functions
+ dbif_put and dbif_del.
+ */
+
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
struct cnid_dbd_rqst rqst;
struct cnid_dbd_rply rply;
int ret, cret;
- time_t now, time_next_flush, time_last_rqst;
int count;
+ time_t now, time_next_flush, time_last_rqst;
+ char timebuf[64];
static char namebuf[MAXPATHLEN + 1];
- u_int32_t checkp_flags;
count = 0;
now = time(NULL);
time_next_flush = now + dbp->flush_interval;
time_last_rqst = now;
- if (dbp->nosync)
- checkp_flags = DB_FORCE;
- else
- checkp_flags = 0;
rqst.name = namebuf;
+ strftime(timebuf, 63, "%b %d %H:%M:%S.",localtime(&time_next_flush));
+ LOG(log_debug, logtype_cnid, "Checkpoint interval: %d seconds. Next checkpoint: %s",
+ dbp->flush_interval, timebuf);
+
while (1) {
if ((cret = comm_rcv(&rqst)) < 0)
return -1;
now = time(NULL);
- if (count > dbp->flush_frequency || now > time_next_flush) {
-#ifdef CNID_BACKEND_DBD_TXN
- if (dbif_txn_checkpoint(0, 0, checkp_flags) < 0)
- return -1;
-#else
- if (dbif_sync() < 0)
- return -1;
-#endif
- count = 0;
- time_next_flush = now + dbp->flush_interval;
- }
-
if (cret == 0) {
+ /* comm_rcv returned from select without receiving anything. */
+
+ /* Give signals a chance... */
block_sigs_onoff(0);
block_sigs_onoff(1);
if (exit_sig)
+ /* Received signal (TERM|INT) */
return 0;
if (dbp->idle_timeout && comm_nbe() <= 0 && (now - time_last_rqst) > dbp->idle_timeout)
+ /* Idle timeout */
return 0;
- continue;
- }
- /* We got a request */
- time_last_rqst = now;
- count++;
+ } else {
+ /* We got a request */
+ time_last_rqst = now;
+
+ memset(&rply, 0, sizeof(rply));
+ switch(rqst.op) {
+ /* ret gets set here */
+ case CNID_DBD_OP_OPEN:
+ case CNID_DBD_OP_CLOSE:
+ /* open/close are noops for now. */
+ rply.namelen = 0;
+ ret = 1;
+ break;
+ case CNID_DBD_OP_ADD:
+ ret = dbd_add(&rqst, &rply);
+ break;
+ case CNID_DBD_OP_GET:
+ ret = dbd_get(&rqst, &rply);
+ break;
+ case CNID_DBD_OP_RESOLVE:
+ ret = dbd_resolve(&rqst, &rply);
+ break;
+ case CNID_DBD_OP_LOOKUP:
+ ret = dbd_lookup(&rqst, &rply);
+ break;
+ case CNID_DBD_OP_UPDATE:
+ ret = dbd_update(&rqst, &rply);
+ break;
+ case CNID_DBD_OP_DELETE:
+ ret = dbd_delete(&rqst, &rply);
+ break;
+ case CNID_DBD_OP_GETSTAMP:
+ ret = dbd_getstamp(&rqst, &rply);
+ break;
+ case CNID_DBD_OP_REBUILD_ADD:
+ ret = dbd_rebuild_add(&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();
+ return -1;
+ }
+
+ if (ret == 0 || cret == 0) {
+ if (dbif_txn_abort() < 0)
+ return -1;
+ } else {
+ ret = dbif_txn_commit();
+ if ( ret < 0)
+ return -1;
+ else if ( ret > 0 )
+ /* We had a designated txn because we wrote to the db */
+ count++;
+ }
+ } /* got a request */
+
+ /*
+ Shall we checkpoint bdb ?
+ "flush_interval" seconds passed ?
+ */
+ if (now > time_next_flush) {
+ LOG(log_info, logtype_cnid, "Checkpointing BerkeleyDB for volume '%s'", dbp->dir);
+ if (dbif_txn_checkpoint(0, 0, 0) < 0)
+ return -1;
+ count = 0;
+ time_next_flush = now + dbp->flush_interval;
-#ifdef CNID_BACKEND_DBD_TXN
- if (dbif_txn_begin() < 0)
- return -1;
-#endif /* CNID_BACKEND_DBD_TXN */
-
- memset(&rply, 0, sizeof(rply));
- switch(rqst.op) {
- /* ret gets set here */
- case CNID_DBD_OP_OPEN:
- case CNID_DBD_OP_CLOSE:
- /* open/close are noops for now. */
- rply.namelen = 0;
- ret = 1;
- break;
- case CNID_DBD_OP_ADD:
- ret = dbd_add(&rqst, &rply);
- break;
- case CNID_DBD_OP_GET:
- ret = dbd_get(&rqst, &rply);
- break;
- case CNID_DBD_OP_RESOLVE:
- ret = dbd_resolve(&rqst, &rply);
- break;
- case CNID_DBD_OP_LOOKUP:
- ret = dbd_lookup(&rqst, &rply);
- break;
- case CNID_DBD_OP_UPDATE:
- ret = dbd_update(&rqst, &rply);
- break;
- case CNID_DBD_OP_DELETE:
- ret = dbd_delete(&rqst, &rply);
- break;
- case CNID_DBD_OP_GETSTAMP:
- ret = dbd_getstamp(&rqst, &rply);
- break;
- case CNID_DBD_OP_REBUILD_ADD:
- ret = dbd_rebuild_add(&rqst, &rply);
- break;
- default:
- LOG(log_error, logtype_cnid, "loop: unknown op %d", rqst.op);
- ret = -1;
- break;
+ strftime(timebuf, 63, "%b %d %H:%M:%S.",localtime(&time_next_flush));
+ LOG(log_debug, logtype_cnid, "Checkpoint interval: %d seconds. Next checkpoint: %s",
+ dbp->flush_interval, timebuf);
}
- if ((cret = comm_snd(&rply)) < 0 || ret < 0) {
-#ifdef CNID_BACKEND_DBD_TXN
- dbif_txn_abort();
-#endif /* CNID_BACKEND_DBD_TXN */
- return -1;
- }
-#ifdef CNID_BACKEND_DBD_TXN
- if (ret == 0 || cret == 0) {
- if (dbif_txn_abort() < 0)
- return -1;
- } else {
- if (dbif_txn_commit() < 0)
+ /*
+ Shall we checkpoint bdb ?
+ Have we commited "count" more changes than "flush_frequency" ?
+ */
+ if (count > dbp->flush_frequency) {
+ LOG(log_info, logtype_cnid, "Checkpointing BerkeleyDB after %d writes for volume '%s'", count, dbp->dir);
+ if (dbif_txn_checkpoint(0, 0, 0) < 0)
return -1;
+ count = 0;
}
-#endif /* CNID_BACKEND_DBD_TXN */
- }
+ } /* while(1) */
}
/* ------------------------ */
{
struct db_param *dbp;
int err = 0;
- int ret;
int lockfd, ctrlfd, clntfd;
char *dir, *logconfig;
only shut down after one second of inactivity. */
block_sigs_onoff(1);
- if ((dbp = db_param_read(dir)) == NULL)
+ if ((dbp = db_param_read(dir, DBD)) == NULL)
exit(1);
+ LOG(log_maxdebug, logtype_cnid, "Finished parsing db_param config file");
if (dbif_env_init(dbp) < 0)
exit(2); /* FIXME: same exit code as failure for dbif_open() */
-
-#ifdef CNID_BACKEND_DBD_TXN
- if (dbif_txn_begin() < 0)
- exit(6);
-#endif
+ LOG(log_debug, logtype_cnid, "Finished initializing BerkeleyDB environment");
if (dbif_open(dbp, 0) < 0) {
-#ifdef CNID_BACKEND_DBD_TXN
- dbif_txn_abort();
-#endif
dbif_close();
exit(2);
}
-
-#ifndef CNID_BACKEND_DBD_TXN
- if (dbp->check && (ret = dbd_check(dir))) {
- if (ret < 0) {
- dbif_close();
- exit(2);
- }
- dbif_closedb();
- LOG(log_info, logtype_cnid, "main: re-opening, secondaries will be rebuilt. This may take some time");
- if (dbif_open(dbp, 1) < 0) {
- LOG(log_info, logtype_cnid, "main: re-opening databases failed");
- dbif_close();
- exit(2);
- }
- LOG(log_info, logtype_cnid, "main: rebuilt done");
- }
-#endif
+ LOG(log_debug, logtype_cnid, "Finished opening BerkeleyDB databases");
if (dbd_stamp() < 0) {
-#ifdef CNID_BACKEND_DBD_TXN
- dbif_txn_abort();
-#endif
dbif_close();
exit(5);
}
-#ifdef CNID_BACKEND_DBD_TXN
- if (dbif_txn_commit() < 0)
- exit(6);
-#endif
+ LOG(log_maxdebug, logtype_cnid, "Finished checking database stamp");
if (comm_init(dbp, ctrlfd, clntfd) < 0) {
dbif_close();
if (loop(dbp) < 0)
err++;
-#ifndef CNID_BACKEND_DBD_TXN
- /* FIXME: Do we really need to sync before closing the DB? Just closing it
- should be enough. */
- if (dbif_sync() < 0)
- err++;
-#endif
-
if (dbif_close() < 0)
err++;
#define ROOTINFO_KEY "\0\0\0\0"
#define ROOTINFO_KEYLEN 4
-/* cnid - dev - inode - type - did - name */
-#define ROOTINFO_DATA "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0RootInfo"
-#define ROOTINFO_DATALEN (3*4 +2*8 +9)
-
-
-
+/*
+ Rootinfo data:
+ 4 unused bytes (cnid)
+ 8 bytes, in first 4 bytes db stamp: struct stat.st_ctime of database file (dev)
+ 8 unused bytes (inode)
+ 4 bytes: last used cnid (type)
+ 4 unused bytes (did)
+ 9 bytes name "RootInfo"
+*/
+#define ROOTINFO_DATA "\0\0\0\0" \
+ "\0\0\0\0\0\0\0\0" \
+ "\0\0\0\0\0\0\0\0" \
+ "\0\0\0\0" \
+ "\0\0\0\0" \
+ "RootInfo"
+#define ROOTINFO_DATALEN (3*4 + 2*8 + 9)
struct cnid_dbd_rqst {
int op;
/*
- * $Id: cnid_dbd.c,v 1.6 2009-04-01 09:57:38 franklahm Exp $
+ * $Id: cnid_dbd.c,v 1.7 2009-04-21 08:55:44 franklahm Exp $
*
* Copyright (C) Joerg Lenneis 2003
* All Rights Reserved. See COPYING.
#include <arpa/inet.h>
#include <errno.h>
#include <netdb.h>
-#include <time.h>
-
+#include <time.h>
+
#include <netatalk/endian.h>
#include <atalk/logger.h>
#include <atalk/adouble.h>
#define SOL_TCP IPPROTO_TCP
#endif /* ! SOL_TCP */
-static void RQST_RESET(struct cnid_dbd_rqst *r)
-{
- memset(r, 0, sizeof(struct cnid_dbd_rqst ));
+static void RQST_RESET(struct cnid_dbd_rqst *r)
+{
+ memset(r, 0, sizeof(struct cnid_dbd_rqst ));
}
/* ----------- */
static int tsock_getfd(char *host, int port)
{
-int sock;
-struct sockaddr_in server;
-struct hostent* hp;
-int attr;
-int err;
+ int sock;
+ struct sockaddr_in server;
+ struct hostent* hp;
+ int attr;
+ int err;
server.sin_family=AF_INET;
server.sin_port=htons((unsigned short)port);
LOG(log_error, logtype_cnid, "getfd: -cnidserver not defined");
return -1;
}
-
+
hp=gethostbyname(host);
if (!hp) {
- unsigned long int addr=inet_addr(host);
- LOG(log_warning, logtype_cnid, "getfd: Could not resolve host %s, trying numeric address instead", host);
+ unsigned long int addr=inet_addr(host);
+ LOG(log_warning, logtype_cnid, "getfd: Could not resolve host %s, trying numeric address instead", host);
if (addr!= (unsigned)-1)
hp=gethostbyaddr((char*)addr,sizeof(addr),AF_INET);
-
- if (!hp) {
- LOG(log_error, logtype_cnid, "getfd: Could not resolve host %s", host);
- return(-1);
- }
+
+ if (!hp) {
+ LOG(log_error, logtype_cnid, "getfd: Could not resolve host %s", host);
+ return(-1);
+ }
}
memcpy((char*)&server.sin_addr,(char*)hp->h_addr,sizeof(server.sin_addr));
sock=socket(PF_INET,SOCK_STREAM,0);
if (sock==-1) {
- LOG(log_error, logtype_cnid, "getfd: socket %s: %s", host, strerror(errno));
- return(-1);
+ LOG(log_error, logtype_cnid, "getfd: socket %s: %s", host, strerror(errno));
+ return(-1);
}
attr = 1;
if (setsockopt(sock, SOL_TCP, TCP_NODELAY, &attr, sizeof(attr)) == -1) {
- LOG(log_error, logtype_cnid, "getfd: set TCP_NODELAY %s: %s", host, strerror(errno));
- close(sock);
- return(-1);
+ LOG(log_error, logtype_cnid, "getfd: set TCP_NODELAY %s: %s", host, strerror(errno));
+ close(sock);
+ return(-1);
}
if(connect(sock ,(struct sockaddr*)&server,sizeof(server))==-1) {
struct timeval tv;
err = errno;
- close(sock);
- sock=-1;
- LOG(log_error, logtype_cnid, "getfd: connect %s: %s", host, strerror(err));
+ close(sock);
+ sock=-1;
+ LOG(log_error, logtype_cnid, "getfd: connect %s: %s", host, strerror(err));
switch (err) {
case ENETUNREACH:
- case ECONNREFUSED:
-
+ case ECONNREFUSED:
+
tv.tv_usec = 0;
tv.tv_sec = 5;
select(0, NULL, NULL, NULL, &tv);
break;
}
}
+
+ LOG(log_debug7, logtype_cnid, "tsock_getfd: using sockfd %d for cnid server '%s:%d'", sock, host, port);
+
return(sock);
}
{
ssize_t len;
size_t len1;
-
+
+ LOG(log_maxdebug, logtype_cnid, "write_vec: request to write %d bytes", towrite);
+
len1 = iov[1].iov_len;
while (towrite > 0) {
if (((len = writev(fd, iov, 2)) == -1 && errno == EINTR) || !len)
continue;
-
+
if ((size_t)len == towrite) /* wrote everything out */
break;
else if (len < 0) { /* error */
return -1;
}
-
+
towrite -= len;
if (towrite > len1) { /* skip part of header */
iov[0].iov_base = (char *) iov[0].iov_base + len;
iov[1].iov_len -= len;
}
}
+
+ LOG(log_maxdebug, logtype_cnid, "write_vec: wrote %d bytes", towrite);
+
return 0;
}
int fd;
int len;
struct iovec iov[2];
-
- if ((fd = tsock_getfd(Cnid_srv, Cnid_port)) < 0)
+
+ LOG(log_debug, logtype_cnid, "init_tsock: BEGIN. Opening volume '%s'", db->db_dir);
+
+ if ((fd = tsock_getfd(Cnid_srv, Cnid_port)) < 0)
return -1;
len = strlen(db->db_dir);
close(fd);
return -1;
}
+
+ LOG(log_debug, logtype_cnid, "init_tsock: ok");
+
return fd;
}
/* --------------------- */
-static int send_packet(CNID_private *db, struct cnid_dbd_rqst *rqst, int silent)
+static int send_packet(CNID_private *db, struct cnid_dbd_rqst *rqst)
{
struct iovec iov[2];
size_t towrite;
-
-
+
+ LOG(log_maxdebug, logtype_cnid, "send_packet: BEGIN");
+
if (!rqst->namelen) {
if (write(db->fd, rqst, sizeof(struct cnid_dbd_rqst)) != sizeof(struct cnid_dbd_rqst)) {
- if (!silent)
- LOG(log_warning, logtype_cnid, "send_packet: Error/short write rqst (db_dir %s): %s",
- db->db_dir, strerror(errno));
+ LOG(log_warning, logtype_cnid, "send_packet: Error/short write rqst (db_dir %s): %s",
+ db->db_dir, strerror(errno));
return -1;
}
+ LOG(log_maxdebug, logtype_cnid, "send_packet: OK");
return 0;
}
towrite = sizeof(struct cnid_dbd_rqst) +rqst->namelen;
if (write_vec(db->fd, iov, towrite) < 0) {
- if (!silent)
- LOG(log_warning, logtype_cnid, "send_packet: Error writev rqst (db_dir %s): %s",
- db->db_dir, strerror(errno));
- return -1;
+ LOG(log_warning, logtype_cnid, "send_packet: Error writev rqst (db_dir %s): %s",
+ db->db_dir, strerror(errno));
+ return -1;
}
-
+
+ LOG(log_maxdebug, logtype_cnid, "send_packet: OK");
return 0;
}
return 0;
}
-/* ---------------------
+/* ---------------------
* send a request and get reply
* assume send is non blocking
* if no answer after sometime (at least MAX_DELAY secondes) return an error
-*/
+ */
#define MAX_DELAY 40
-static int dbd_rpc(CNID_private *db, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply, int silent)
+static int dbd_rpc(CNID_private *db, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
{
ssize_t ret;
char *nametmp;
int maxfd;
size_t len;
- if (send_packet(db, rqst, silent) < 0) {
+ LOG(log_maxdebug, logtype_cnid, "dbd_rpc: BEGIN");
+
+ if (send_packet(db, rqst) < 0) {
return -1;
}
FD_ZERO(&readfds);
FD_SET(db->fd, &readfds);
maxfd = db->fd +1;
-
+
tv.tv_usec = 0;
tv.tv_sec = MAX_DELAY;
while ((ret = select(maxfd + 1, &readfds, NULL, NULL, &tv)) < 0 && errno == EINTR);
if (ret < 0) {
- if (!silent)
- LOG(log_error, logtype_cnid, "dbd_rpc: Error in select (db_dir %s): %s",
- db->db_dir, strerror(errno));
+ LOG(log_error, logtype_cnid, "dbd_rpc: Error in select (db_dir %s): %s",
+ db->db_dir, strerror(errno));
return ret;
}
/* signal ? */
if (!ret) {
/* no answer */
- if (!silent)
- LOG(log_error, logtype_cnid, "dbd_rpc: select timed out (db_dir %s)",
- db->db_dir);
+ LOG(log_error, logtype_cnid, "dbd_rpc: select timed out (db_dir %s)",
+ db->db_dir);
return -1;
}
-
len = rply->namelen;
nametmp = rply->name;
- /* assume that if we have something then everything is there (doesn't sleep) */
+ /* assume that if we have something then everything is there (doesn't sleep) */
if ((ret = read(db->fd, rply, sizeof(struct cnid_dbd_rply))) != sizeof(struct cnid_dbd_rply)) {
- if (!silent)
- LOG(log_error, logtype_cnid, "dbd_rpc: Error reading header from fd (db_dir %s): %s",
- db->db_dir, ret == -1?strerror(errno):"closed");
+ LOG(log_error, logtype_cnid, "dbd_rpc: Error reading header from fd (db_dir %s): %s",
+ db->db_dir, ret == -1?strerror(errno):"closed");
rply->name = nametmp;
return -1;
}
rply->name = nametmp;
if (rply->namelen && rply->namelen > len) {
- if (!silent)
- LOG(log_error, logtype_cnid,
- "dbd_rpc: Error reading name (db_dir %s): %s name too long wanted %d only %d, garbage?",
- db->db_dir, rply->namelen, len);
+ LOG(log_error, logtype_cnid,
+ "dbd_rpc: Error reading name (db_dir %s): %s name too long: %d. only wanted %d, garbage?",
+ db->db_dir, rply->name, rply->namelen, len);
return -1;
}
if (rply->namelen && (ret = read(db->fd, rply->name, rply->namelen)) != (ssize_t)rply->namelen) {
- if (!silent)
- LOG(log_error, logtype_cnid, "dbd_rpc: Error reading name from fd (db_dir %s): %s",
- db->db_dir, ret == -1?strerror(errno):"closed");
+ LOG(log_error, logtype_cnid, "dbd_rpc: Error reading name from fd (db_dir %s): %s",
+ db->db_dir, ret == -1?strerror(errno):"closed");
return -1;
}
+
+ LOG(log_maxdebug, logtype_cnid, "dbd_rpc: END");
+
return 0;
}
{
struct timeval tv;
time_t orig, t;
- int silent = 1;
int clean = 1; /* no errors so far - to prevent sleep on first try */
-
+
+ LOG(log_debug7, logtype_cnid, "transmit: BEGIN");
+
if (db->changed) {
/* volume and db don't have the same timestamp
- */
+ */
return -1;
}
time(&orig);
while (1) {
-
if (db->fd == -1) {
+ LOG(log_debug, logtype_cnid, "transmit: connecting to cnid_dbd ...");
struct cnid_dbd_rqst rqst_stamp;
struct cnid_dbd_rply rply_stamp;
char stamp[ADEDLEN_PRIVSYN];
-
+
if ((db->fd = init_tsock(db)) < 0) {
time(&t);
if (t - orig > MAX_DELAY)
return -1;
- continue;
+ continue;
}
dbd_initstamp(&rqst_stamp);
memset(stamp, 0, ADEDLEN_PRIVSYN);
rply_stamp.name = stamp;
rply_stamp.namelen = ADEDLEN_PRIVSYN;
- if (dbd_rpc(db, &rqst_stamp, &rply_stamp, silent) < 0)
+ if (dbd_rpc(db, &rqst_stamp, &rply_stamp) < 0)
goto transmit_fail;
if (dbd_reply_stamp(&rply_stamp ) < 0)
goto transmit_fail;
-
+
if (db->notfirst) {
- if (memcmp(stamp, db->stamp, ADEDLEN_PRIVSYN)) {
- LOG(log_error, logtype_cnid, "transmit: not the same db!");
- db->changed = 1;
- return -1;
- }
+ LOG(log_debug7, logtype_cnid, "transmit: reconnected to cnid_dbd, comparing database stamps...");
+ if (memcmp(stamp, db->stamp, ADEDLEN_PRIVSYN)) {
+ LOG(log_error, logtype_cnid, "transmit: ... not the same db!");
+ db->changed = 1;
+ return -1;
+ }
+ LOG(log_debug7, logtype_cnid, "transmit: ... OK.");
}
else {
db->notfirst = 1;
- if (db->client_stamp) {
- memcpy(db->client_stamp, stamp, ADEDLEN_PRIVSYN);
- }
- memcpy(db->stamp, stamp, ADEDLEN_PRIVSYN);
+ if (db->client_stamp)
+ memcpy(db->client_stamp, stamp, ADEDLEN_PRIVSYN);
+ memcpy(db->stamp, stamp, ADEDLEN_PRIVSYN);
}
+ LOG(log_debug, logtype_cnid, "transmit: succesfully attached to cnid_dbd for volume '%s' with stamp '%08lx'.",
+ db->db_dir, *(uint64_t *)stamp);
}
- if (!dbd_rpc(db, rqst, rply, silent)) {
+ if (!dbd_rpc(db, rqst, rply)) {
+ LOG(log_debug7, logtype_cnid, "transmit: END OK");
return 0;
- }
-transmit_fail:
- silent = 0; /* From now on dbd_rpc and subroutines called from there
- will log messages if something goes wrong again */
+ }
+ transmit_fail:
+ LOG(log_error, logtype_cnid, "transmit: something went wrong");
if (db->fd != -1) {
close(db->fd);
db->fd = -1; /* FD not valid... will need to reconnect */
}
time(&t);
if (t - orig > MAX_DELAY) {
- LOG(log_error, logtype_cnid, "transmit: Request to dbd daemon (db_dir %s) timed out.", db->db_dir);
+ LOG(log_error, logtype_cnid, "transmit: Request to dbd daemon (db_dir %s) timed out.", db->db_dir);
return -1;
- }
+ }
- if (!clean) { /* don't sleep if just got disconnected by cnid server */
+ if (!clean) { /* don't sleep if just got disconnected by cnid server */
/* sleep a little before retry */
tv.tv_usec = 0;
tv.tv_sec = 5;
select(0, NULL, NULL, NULL, &tv); /* sleep for 5 seconds */
- } else {
+ } else {
clean = 0; /* false... next time sleep */
}
}
static struct _cnid_db *cnid_dbd_new(const char *volpath)
{
struct _cnid_db *cdb;
-
+
if ((cdb = (struct _cnid_db *)calloc(1, sizeof(struct _cnid_db))) == NULL)
- return NULL;
-
+ return NULL;
+
if ((cdb->volpath = strdup(volpath)) == NULL) {
free(cdb);
- return NULL;
+ return NULL;
}
-
+
cdb->flags = CNID_FLAG_PERSISTENT | CNID_FLAG_LAZY_INIT;
-
+
cdb->cnid_add = cnid_dbd_add;
cdb->cnid_delete = cnid_dbd_delete;
cdb->cnid_get = cnid_dbd_get;
cdb->cnid_update = cnid_dbd_update;
cdb->cnid_rebuild_add = cnid_dbd_rebuild_add;
cdb->cnid_close = cnid_dbd_close;
-
+
return cdb;
}
struct _cnid_db *cdb = NULL;
if (!dir) {
- return NULL;
+ return NULL;
}
-
+
if ((cdb = cnid_dbd_new(dir)) == NULL) {
LOG(log_error, logtype_cnid, "cnid_open: Unable to allocate memory for database");
- return NULL;
+ return NULL;
}
-
+
if ((db = (CNID_private *)calloc(1, sizeof(CNID_private))) == NULL) {
LOG(log_error, logtype_cnid, "cnid_open: Unable to allocate memory for database");
goto cnid_dbd_open_fail;
}
-
+
cdb->_private = db;
/* We keep a copy of the directory in the db structure so that we can
strcpy(db->db_dir, dir);
db->magic = CNID_DB_MAGIC;
db->fd = -1;
-#ifdef DEBUG
- LOG(log_info, logtype_cnid, "opening database connection to %s", db->db_dir);
-#endif
+
+ LOG(log_debug, logtype_cnid, "cnid_dbd_open: Finished initializing cnid dbd module for volume '%s'", db->db_dir);
+
return cdb;
cnid_dbd_open_fail:
if (cdb != NULL) {
- if (cdb->volpath != NULL) {
- free(cdb->volpath);
- }
- free(cdb);
+ if (cdb->volpath != NULL) {
+ free(cdb->volpath);
+ }
+ free(cdb);
}
if (db != NULL)
- free(db);
-
+ free(db);
+
return NULL;
}
if (!cdb) {
LOG(log_error, logtype_cnid, "cnid_close called with NULL argument !");
- return;
+ return;
}
if ((db = cdb->_private) != NULL) {
-#ifdef DEBUG
- LOG(log_info, logtype_cnid, "closing database connection to %s", db->db_dir);
-#endif
- if (db->fd >= 0)
- close(db->fd);
+ LOG(log_info, logtype_cnid, "closing database connection for volume '%s'", db->db_dir);
+
+ if (db->fd >= 0)
+ close(db->fd);
free(db);
}
-
+
free(cdb->volpath);
free(cdb);
-
+
return;
}
/* ---------------------- */
cnid_t cnid_dbd_add(struct _cnid_db *cdb, const struct stat *st,
- const cnid_t did, char *name, const size_t len,
- cnid_t hint _U_)
+ const cnid_t did, char *name, const size_t len,
+ cnid_t hint _U_)
{
CNID_private *db;
struct cnid_dbd_rqst rqst;
rqst.name = name;
rqst.namelen = len;
+ LOG(log_debug, logtype_cnid, "cnid_dbd_add: CNID: %u, name: '%s', inode: 0x%llx, type: %d (0=file, 1=dir)",
+ ntohl(did), name, (long long)st->st_ino, rqst.type);
+
rply.namelen = 0;
if (transmit(db, &rqst, &rply) < 0) {
errno = CNID_ERR_DB;
return CNID_INVALID;
}
-
+
switch(rply.result) {
case CNID_DBD_RES_OK:
id = rply.cnid;
+ LOG(log_debug, logtype_cnid, "cnid_dbd_add: got CNID: %u", ntohl(id));
break;
case CNID_DBD_RES_ERR_MAX:
errno = CNID_ERR_MAX;
default:
abort();
}
+
return id;
}
struct cnid_dbd_rply rply;
cnid_t id;
-
if (!cdb || !(db = cdb->_private) || !name) {
- LOG(log_error, logtype_cnid, "cnid_get: Parameter error");
- errno = CNID_ERR_PARAM;
+ LOG(log_error, logtype_cnid, "cnid_dbd_get: Parameter error");
+ errno = CNID_ERR_PARAM;
return CNID_INVALID;
}
if (len > MAXPATHLEN) {
- LOG(log_error, logtype_cnid, "cnid_add: Path name is too long");
+ LOG(log_error, logtype_cnid, "cnid_dbd_get: Path name is too long");
errno = CNID_ERR_PATH;
return CNID_INVALID;
}
+ LOG(log_debug, logtype_cnid, "cnid_dbd_get: DID: %u, name: '%s'", ntohl(did), name);
+
RQST_RESET(&rqst);
rqst.op = CNID_DBD_OP_GET;
rqst.did = did;
errno = CNID_ERR_DB;
return CNID_INVALID;
}
-
+
switch(rply.result) {
case CNID_DBD_RES_OK:
id = rply.cnid;
+ LOG(log_debug, logtype_cnid, "cnid_dbd_get: got CNID: %u", ntohl(id));
break;
case CNID_DBD_RES_NOTFOUND:
id = CNID_INVALID;
id = CNID_INVALID;
errno = CNID_ERR_DB;
break;
- default:
+ default:
abort();
}
if (!cdb || !(db = cdb->_private) || !id || !(*id)) {
LOG(log_error, logtype_cnid, "cnid_resolve: Parameter error");
- errno = CNID_ERR_PARAM;
+ errno = CNID_ERR_PARAM;
return NULL;
}
+ LOG(log_debug, logtype_cnid, "cnid_dbd_resolve: resolving CNID: %u", ntohl(*id));
+
/* TODO: We should maybe also check len. At the moment we rely on the caller
to provide a buffer that is large enough for MAXPATHLEN plus
CNID_HEADER_LEN plus 1 byte, which is large enough for the maximum that
case CNID_DBD_RES_OK:
*id = rply.did;
name = rply.name;
+ LOG(log_debug, logtype_cnid, "cnid_dbd_resolve: resolved CNID: %u to '%s'", ntohl(*id), name);
break;
case CNID_DBD_RES_NOTFOUND:
*id = CNID_INVALID;
if (!cdb || !(db = cdb->_private) || len != ADEDLEN_PRIVSYN) {
LOG(log_error, logtype_cnid, "cnid_getstamp: Parameter error");
- errno = CNID_ERR_PARAM;
+ errno = CNID_ERR_PARAM;
return -1;
}
db->client_stamp = buffer;
/* ---------------------- */
cnid_t cnid_dbd_lookup(struct _cnid_db *cdb, const struct stat *st, const cnid_t did,
- char *name, const size_t len)
+ char *name, const size_t len)
{
CNID_private *db;
struct cnid_dbd_rqst rqst;
if (!cdb || !(db = cdb->_private) || !st || !name) {
LOG(log_error, logtype_cnid, "cnid_lookup: Parameter error");
- errno = CNID_ERR_PARAM;
+ errno = CNID_ERR_PARAM;
return CNID_INVALID;
}
rqst.name = name;
rqst.namelen = len;
+ LOG(log_debug, logtype_cnid, "cnid_dbd_lookup: CNID: %u, name: '%s', inode: 0x%llx, type: %d (0=file, 1=dir)",
+ ntohl(did), name, (long long)st->st_ino, rqst.type);
+
rply.namelen = 0;
if (transmit(db, &rqst, &rply) < 0) {
errno = CNID_ERR_DB;
switch (rply.result) {
case CNID_DBD_RES_OK:
id = rply.cnid;
+ LOG(log_debug, logtype_cnid, "cnid_dbd_lookup: got CNID: %u", ntohl(id));
break;
case CNID_DBD_RES_NOTFOUND:
id = CNID_INVALID;
/* ---------------------- */
int cnid_dbd_update(struct _cnid_db *cdb, const cnid_t id, const struct stat *st,
- const cnid_t did, char *name, const size_t len)
+ const cnid_t did, char *name, const size_t len)
{
CNID_private *db;
struct cnid_dbd_rqst rqst;
struct cnid_dbd_rply rply;
-
if (!cdb || !(db = cdb->_private) || !id || !st || !name) {
LOG(log_error, logtype_cnid, "cnid_update: Parameter error");
- errno = CNID_ERR_PARAM;
+ errno = CNID_ERR_PARAM;
return -1;
}
rqst.name = name;
rqst.namelen = len;
+ LOG(log_debug, logtype_cnid, "cnid_dbd_update: CNID: %u, name: '%s', inode: 0x%llx, type: %d (0=file, 1=dir)",
+ ntohl(id), name, (long long)st->st_ino, rqst.type);
+
rply.namelen = 0;
if (transmit(db, &rqst, &rply) < 0) {
errno = CNID_ERR_DB;
switch (rply.result) {
case CNID_DBD_RES_OK:
+ LOG(log_debug, logtype_cnid, "cnid_dbd_update: updated");
case CNID_DBD_RES_NOTFOUND:
return 0;
case CNID_DBD_RES_ERR_DB:
}
/* ---------------------- */
-cnid_t cnid_dbd_rebuild_add(struct _cnid_db *cdb, const struct stat *st,
- const cnid_t did, char *name, const size_t len,
- cnid_t hint)
+cnid_t cnid_dbd_rebuild_add(struct _cnid_db *cdb, const struct stat *st,
+ const cnid_t did, char *name, const size_t len,
+ cnid_t hint)
{
CNID_private *db;
struct cnid_dbd_rqst rqst;
struct cnid_dbd_rply rply;
cnid_t id;
-
+
if (!cdb || !(db = cdb->_private) || !st || !name || hint == CNID_INVALID) {
LOG(log_error, logtype_cnid, "cnid_rebuild_add: Parameter error");
errno = CNID_ERR_PARAM;
rqst.namelen = len;
rqst.cnid = hint;
+ LOG(log_debug, logtype_cnid, "cnid_dbd_rebuild_add: CNID: %u, name: '%s', inode: 0x%llx, type: %d (0=file, 1=dir), hint: %u",
+ ntohl(did), name, (long long)st->st_ino, rqst.type, hint);
+
if (transmit(db, &rqst, &rply) < 0) {
errno = CNID_ERR_DB;
return CNID_INVALID;
switch(rply.result) {
case CNID_DBD_RES_OK:
id = rply.cnid;
+ LOG(log_debug, logtype_cnid, "cnid_dbd_rebuild_add: got CNID: %u", ntohl(id));
break;
case CNID_DBD_RES_ERR_MAX:
errno = CNID_ERR_MAX;
}
/* ---------------------- */
-int cnid_dbd_delete(struct _cnid_db *cdb, const cnid_t id)
+int cnid_dbd_delete(struct _cnid_db *cdb, const cnid_t id)
{
CNID_private *db;
struct cnid_dbd_rqst rqst;
struct cnid_dbd_rply rply;
-
if (!cdb || !(db = cdb->_private) || !id) {
LOG(log_error, logtype_cnid, "cnid_delete: Parameter error");
- errno = CNID_ERR_PARAM;
+ errno = CNID_ERR_PARAM;
return -1;
}
+ LOG(log_debug, logtype_cnid, "cnid_dbd_delete: delete CNID: %u", ntohl(id));
+
RQST_RESET(&rqst);
rqst.op = CNID_DBD_OP_DELETE;
rqst.cnid = id;
switch (rply.result) {
case CNID_DBD_RES_OK:
+ LOG(log_debug, logtype_cnid, "cnid_dbd_delete: deleted CNID: %u", ntohl(id));
case CNID_DBD_RES_NOTFOUND:
return 0;
case CNID_DBD_RES_ERR_DB:
else
use_cdb_backend=yes
fi
- ],[use_cdb_backend=yes]
+ ],[use_cdb_backend=no]
)
if test $use_cdb_backend = yes; then
AC_MSG_RESULT([yes])
])
- dnl Determine whether or not to use with transaction support in Database Daemon
- AC_MSG_CHECKING([whether or not to use Database Daemon with transaction support])
- AC_ARG_WITH(cnid-dbd-txn,
- [ --with-cnid-dbd-txn build transaction support for dbd backend],
- [ if test x"$withval" = x"no"; then
- AC_MSG_RESULT([no])
- use_dbd_txn=no
- else
- use_dbd_txn=yes
- AC_MSG_RESULT([yes])
- fi
- ],[
- use_dbd_txn=no
- AC_MSG_RESULT([no])
- ])
-
- if test $use_dbd_txn = yes; then
- use_dbd_backend=yes
- AC_DEFINE(CNID_BACKEND_DBD_TXN, 1, [Define if CNID Database Daemon backend has transaction support])
- else
- if test x"$use_dbd_backend" = x; then
- use_dbd_backend=no
- fi
- fi
-
if test $use_dbd_backend = yes; then
compiled_backends="$compiled_backends dbd"
AC_DEFINE(CNID_BACKEND_DBD, 1, [Define if CNID Database Daemon backend should be compiled.])
-dnl $Id: db3-check.m4,v 1.17 2009-03-25 15:53:03 franklahm Exp $
+dnl $Id: db3-check.m4,v 1.18 2009-04-21 08:55:44 franklahm Exp $
dnl Autoconf macros to check for the Berkeley DB library
dnl -- check header for minimum version and return version in
trybdbdir=""
dobdbsearch=yes
bdb_search_dirs="/usr/local /usr"
- search_subdirs="/ /db4.7 /db47 /db4.6 /db46 /db4.5 /db45 /db4.4 /db44 /db4.3 /db43 /db4.2 /db42 /db4.1 /db41 /db4"
+ search_subdirs="/ /db4.7 /db47 /db4.6 /db46 /db4.5 /db45 /db4.4 /db44 /db4"
- dnl required BDB version
+ dnl required BDB version: 4.4, because of DB_AUTO_COMMIT
DB_MAJOR_REQ=4
- DB_MINOR_REQ=1
+ DB_MINOR_REQ=4
DB_PATCH_REQ=0
dnl make sure atalk_libname is defined beforehand