* FIX: put the Solaris share reservation after our locking stuff, bug #560.
* UPD: Improve Linux quota behaviour
* FIX: xattrs on *BSD, bug #562
+* NEW: afpd: support for using $u username variable in AFP volume
+ definitions. FR#90.
Changes in 3.1.1
================
# Makefile.am for bin/
-SUBDIRS = afppasswd cnid megatron uniconv misc
+SUBDIRS = afppasswd cnid megatron misc
if HAVE_ATFUNCS
SUBDIRS += ad
if ((vol->vol->v_flags & AFPVOL_NODEV))
flags |= CNID_FLAG_NODEV;
- if ((vol->vol->v_cdb = cnid_open(vol->vol->v_path,
- 0000,
+ if ((vol->vol->v_cdb = cnid_open(vol->vol,
"dbd",
- flags,
- vol->vol->v_cnidserver,
- vol->vol->v_cnidport,
- NULL, NULL)) == NULL)
+ flags)) == NULL)
ERROR("Cant initialize CNID database connection for %s", vol->vol->v_path);
cnid_getstamp(vol->vol->v_cdb,
<primary>dbd</primary>
</indexterm></command>
- <arg choice="opt">-fsv</arg>
+ <arg choice="opt">-cfFstuvV</arg>
<arg choice="plain"><replaceable>volumepath</replaceable></arg>
</cmdsynopsis>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>-u</term>
+
+ <listitem>
+ <para>username for use with AFP volumes using user variable $u</para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term>-v</term>
<title>VARIABLE SUBSTITUTIONS</title>
<para>You can use variables in volume names. The use of variables in paths
- is not supported for now.</para>
+ is limited to $u.</para>
<orderedlist>
<listitem>
}
LOG(log_error, logtype_afpd, "Reopen volume %s using in memory temporary CNID DB.",
vol->v_path);
- vol->v_cdb = cnid_open(vol->v_path, vol->v_umask, "tdb", flags, NULL, NULL, NULL, NULL);
+ vol->v_cdb = cnid_open(vol, "tdb", flags);
if (vol->v_cdb) {
if (!(vol->v_flags & AFPVOL_TM)) {
vol->v_flags |= AFPVOL_RO;
return( AFPERR_PARAM);
}
- if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
+ if (vol->v_cdb == NULL || !(vol->v_cdb->cnid_db_flags & CNID_FLAG_PERSISTENT)) {
return AFPERR_NOOP;
}
return( AFPERR_PARAM);
}
- if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
+ if (vol->v_cdb == NULL || !(vol->v_cdb->cnid_db_flags & CNID_FLAG_PERSISTENT)) {
return AFPERR_NOOP;
}
return( AFPERR_PARAM);
}
- if (vol->v_cdb == NULL || !(vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
+ if (vol->v_cdb == NULL || !(vol->v_cdb->cnid_db_flags & CNID_FLAG_PERSISTENT)) {
return AFPERR_NOOP;
}
}
/* prior 2.1 only VOLPBIT_ATTR_RO is defined */
if (obj->afp_version > 20) {
- if (vol->v_cdb != NULL && (vol->v_cdb->flags & CNID_FLAG_PERSISTENT))
+ if (vol->v_cdb != NULL && (vol->v_cdb->cnid_db_flags & CNID_FLAG_PERSISTENT))
ashort |= VOLPBIT_ATTR_FILEID;
ashort |= VOLPBIT_ATTR_CATSEARCH;
flags |= CNID_FLAG_NODEV;
}
- LOG(log_debug, logtype_afpd, "CNID server: %s:%s", volume->v_cnidserver, volume->v_cnidport);
-
- volume->v_cdb = cnid_open(volume->v_path,
- volume->v_umask,
- volume->v_cnidscheme,
- flags,
- volume->v_cnidserver,
- volume->v_cnidport,
- (const void *)obj,
- volume->v_uuid);
+ volume->v_cdb = cnid_open(volume, volume->v_cnidscheme, flags);
if ( ! volume->v_cdb && ! (flags & CNID_FLAG_MEMORY)) {
/* The first attempt failed and it wasn't yet an attempt to open in-memory */
LOG(log_error, logtype_afpd, "Reopen volume %s using in memory temporary CNID DB.",
volume->v_path);
flags |= CNID_FLAG_MEMORY;
- volume->v_cdb = cnid_open (volume->v_path, volume->v_umask, "tdb", flags, NULL, NULL, NULL, NULL);
+ volume->v_cdb = cnid_open(volume, "tdb", flags);
#ifdef SERVERTEXT
/* kill ourself with SIGUSR2 aka msg pending */
if (volume->v_cdb) {
* fixing the trash at DID 17.
* FIXME (RL): should it be done inside a CNID backend ? (always returning Trash DID when asked) ?
*/
- if ((volume->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
+ if ((volume->v_cdb->cnid_db_flags & CNID_FLAG_PERSISTENT)) {
/* FIXME find db time stamp */
if (cnid_getstamp(volume->v_cdb, volume->v_stamp, sizeof(volume->v_stamp)) < 0) {
#include <signal.h>
#include <string.h>
#include <errno.h>
+#include <pwd.h>
#include <atalk/logger.h>
#include <atalk/globals.h>
" -F location of the afp.conf config file\n"
" -f delete and recreate CNID database\n"
" -t show statistics while running\n"
+ " -u username for use with AFP volumes using user variable $u\n"
" -v verbose\n"
" -V show version info\n\n"
);
AFPObj obj = { 0 };
struct vol *vol = NULL;
const char *volpath = NULL;
-
+ char *username;
int c;
- while ((c = getopt(argc, argv, ":cfF:rstvV")) != -1) {
+ while ((c = getopt(argc, argv, ":cfF:rstu:vV")) != -1) {
switch(c) {
case 'c':
flags |= DBD_FLAGS_V2TOEA;
case 't':
flags |= DBD_FLAGS_STATS;
break;
+ case 'u':
+ username = strdup(optarg);
+ break;
case 'v':
flags |= DBD_FLAGS_VERBOSE;
break;
exit(EXIT_FAILURE);
}
+
/* Initialize CNID subsystem */
cnid_init();
else
setuplog("default:note", "/dev/tty");
+ /* Set username */
+ if (username) {
+ strncpy(obj.username, username, MAXUSERLEN);
+ struct passwd *pwd;
+ pwd = getpwnam(obj.username);
+ if (!pwd) {
+ dbd_log( LOGSTD, "unknown user");
+ exit(EXIT_FAILURE);
+ }
+ obj.uid = pwd->pw_uid;
+ }
+
if (load_volumes(&obj, lv_all) != 0) {
dbd_log( LOGSTD, "Couldn't load volumes");
exit(EXIT_FAILURE);
dbd_log(LOGSTD, "\"%s\" isn't a \"dbd\" CNID volume", vol->v_path);
exit(EXIT_FAILURE);
}
- if ((vol->v_cdb = cnid_open(vol->v_path,
- 0000,
- vol->v_cnidscheme,
- vol->v_flags & AFPVOL_NODEV ? CNID_FLAG_NODEV : 0,
- vol->v_cnidserver,
- vol->v_cnidport,
- &obj,
- vol->v_uuid)) == NULL) {
+ vol->v_cdb = cnid_open(vol, vol->v_cnidscheme,
+ vol->v_flags & AFPVOL_NODEV ? CNID_FLAG_NODEV : 0);
+ if (vol->v_cdb == NULL) {
dbd_log(LOGSTD, "Cant initialize CNID database connection for %s", vol->v_path);
exit(EXIT_FAILURE);
}
return NULL;
}
-/* -------------------- */
-static int maybe_start_dbd(const AFPObj *obj, char *dbdpn, const char *volpath)
+/**
+ * Pass connection request to existing cnid_dbd process or start a new one
+ *
+ * @param[in] obj handle
+ * @param[in] dbdpn Path to cnid_dbd binary
+ * @param[in] volpath Path of AFP volume
+ * @param[in] username Optional username, may be NULL
+ *
+ * @return 0 on success, -1 on error
+ **/
+ int maybe_start_dbd(const AFPObj *obj, char *dbdpn, const char *volpath, const char *username)
{
pid_t pid;
struct server *up;
LOG(log_warning, logtype_cnid,
"Multiple attempts to start CNID db daemon for \"%s\" failed, wiping the slate clean...",
up->v_path);
- ret = execlp(dbdpn, dbdpn, "-F", obj->options.configfile, "-p", volpath, "-t", buf1, "-l", buf2, "-d", NULL);
+ ret = execlp(dbdpn, dbdpn,
+ "-F", obj->options.configfile,
+ "-p", volpath,
+ "-t", buf1,
+ "-l", buf2,
+ "-u", username,
+ NULL);
} else {
- ret = execlp(dbdpn, dbdpn, "-F", obj->options.configfile, "-p", volpath, "-t", buf1, "-l", buf2, NULL);
+ ret = execlp(dbdpn, dbdpn,
+ "-F", obj->options.configfile,
+ "-p", volpath,
+ "-t", buf1,
+ "-l", buf2,
+ "-u", username,
+ NULL);
}
/* Yikes! We're still here, so exec failed... */
LOG(log_error, logtype_cnid, "Fatal error in exec: %s", strerror(errno));
return 0;
}
+static uid_t uid_from_name(const char *name)
+{
+ struct passwd *pwd;
+
+ pwd = getpwnam(name);
+ if (pwd == NULL)
+ return 0;
+ return pwd->pw_uid;
+}
+
/* ------------------ */
int main(int argc, char *argv[])
{
- char volpath[MAXPATHLEN + 1];
- int len, actual_len;
+ char *volname = NULL;
+ char *volpath = NULL;
+ char *username = NULL;
+ int len[DBD_NUM_OPEN_ARGS], actual_len;
pid_t pid;
int status;
char *dbdpn = _PATH_CNID_DBD;
if (afp_config_parse(&obj, "cnid_metad") != 0)
daemon_exit(1);
- if (load_volumes(&obj, lv_all) != 0)
- daemon_exit(1);
-
(void)setlimits();
host = atalk_iniparser_getstrdup(obj.iniconfig, INISEC_GLOBAL, "cnid listen", "localhost:4700");
if (rqstfd <= 0)
continue;
- ret = readt(rqstfd, &len, sizeof(int), 1, 4);
+ ret = readt(rqstfd, &len[0], sizeof(int) * DBD_NUM_OPEN_ARGS, 1, 4);
if (!ret) {
/* already close */
LOG(log_severe, logtype_cnid, "error read: %s", strerror(errno));
goto loop_end;
}
- else if (ret != sizeof(int)) {
+ else if (ret != DBD_NUM_OPEN_ARGS * sizeof(int)) {
LOG(log_error, logtype_cnid, "short read: got %d", ret);
goto loop_end;
}
+
/*
* 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);
+ if (!len[0] || !len[1]) {
+ LOG(log_error, logtype_cnid, "wrong len parameter: len[0]: %d, len[1]: %d", len[0], len[1]);
goto loop_end;
}
- actual_len = readt(rqstfd, volpath, len, 1, 5);
- if (actual_len < 0) {
- LOG(log_severe, logtype_cnid, "Read(2) error : %s", strerror(errno));
+ volname = malloc(len[0]);
+ volpath = malloc(len[1]);
+ if (len[2]) {
+ username = malloc(len[2]);
+ }
+ if (!volname || !volpath || (len[2] && !username)) {
+ LOG(log_severe, logtype_cnid, "malloc: %s", strerror(errno));
goto loop_end;
}
- if (actual_len != len) {
- LOG(log_error, logtype_cnid, "error/short read (dir): %s", strerror(errno));
+
+ actual_len = readt(rqstfd, volname, len[0], 1, 5);
+ if (actual_len != len[0]) {
+ LOG(log_severe, logtype_cnid, "readt: %s", strerror(errno));
+ goto loop_end;
+ }
+
+ actual_len = readt(rqstfd, volpath, len[1], 1, 5);
+ if (actual_len != len[1]) {
+ LOG(log_severe, logtype_cnid, "readt: %s", strerror(errno));
goto loop_end;
}
- volpath[len] = '\0';
- LOG(log_debug, logtype_cnid, "main: request for volume: %s", volpath);
+ if (len[2]) {
+ actual_len = readt(rqstfd, username, len[2], 1, 5);
+ if (actual_len != len[2]) {
+ LOG(log_severe, logtype_cnid, "readt: %s", strerror(errno));
+ goto loop_end;
+ }
+ strlcpy(obj.username, username, MAXUSERLEN);
+ obj.uid = uid_from_name(username);
+ if (!obj.uid)
+ goto loop_end;
+ } else {
+ obj.username[0] = 0;
+ }
+
+ LOG(log_debug, logtype_cnid, "user: %s, volume %s, path %s",
+ username ? username : "-", volname, volpath);
if (load_volumes(&obj, lv_all) != 0) {
LOG(log_severe, logtype_cnid, "main: error reloading config");
LOG(log_maxdebug, logtype_cnid, "main: dbpath: %s", vol->v_dbpath);
- if (set_dbdir(vol->v_dbpath, volpath) < 0) {
+ if (set_dbdir(vol->v_dbpath, vol->v_path) < 0) {
goto loop_end;
}
- maybe_start_dbd(&obj, dbdpn, vol->v_path);
+ maybe_start_dbd(&obj, dbdpn, vol->v_path, username);
+
loop_end:
close(rqstfd);
+ unload_volumes(&obj);
+ SAFE_FREE(volname);
+ SAFE_FREE(volpath);
+ SAFE_FREE(username);
}
}
}
}
+static uid_t uid_from_name(const char *name)
+{
+ struct passwd *pwd;
+
+ pwd = getpwnam(name);
+ if (pwd == NULL)
+ return 0;
+ return pwd->pw_uid;
+}
+
/* ------------------------ */
int main(int argc, char *argv[])
{
int ctrlfd = -1, clntfd = -1;
AFPObj obj = { 0 };
char *volpath = NULL;
+ char *username = NULL;
- while (( ret = getopt( argc, argv, "dF:l:p:t:vV")) != -1 ) {
+ while (( ret = getopt( argc, argv, ":dF:l:p:t:u:vV")) != -1 ) {
switch (ret) {
case 'd':
/* this is now just ignored, as we do it automatically anyway */
case 't':
ctrlfd = atoi(optarg);
break;
+ case 'u':
+ username = strdup(optarg);
+ break;
case 'v':
case 'V':
printf("cnid_dbd (Netatalk %s)\n", VERSION);
return -1;
+ case ':':
+ break;
}
}
EC_ZERO( afp_config_parse(&obj, "cnid_dbd") );
+ if (username) {
+ strlcpy(obj.username, username, MAXUSERLEN);
+ obj.uid = uid_from_name(username);
+ if (!obj.uid) {
+ EC_FAIL_LOG("unknown user: '%s'", username);
+ }
+ }
+
+ LOG(log_debug, logtype_cnid, "user: %s, path %s",
+ username ? username : "-", volpath);
+
EC_ZERO( load_volumes(&obj, lv_all) );
EC_NULL( vol = getvolbypath(&obj, volpath) );
EC_ZERO( load_charset(vol) );
/*
* This is instance of CNID database object.
*/
-struct _cnid_db {
- uint32_t flags; /* Flags describing some CNID backend aspects. */
- char *volpath; /* Volume path this particular CNID db refers to. */
- void *_private; /* back-end speficic data */
+typedef struct _cnid_db {
+ uint32_t cnid_db_flags; /* Flags describing some CNID backend aspects. */
+ struct vol *cnid_db_vol;
+ void *cnid_db_private; /* back-end speficic data */
cnid_t (*cnid_add) (struct _cnid_db *cdb, const struct stat *st, cnid_t did,
const char *name, size_t, cnid_t hint);
int (*cnid_find) (struct _cnid_db *cdb, const char *name, size_t namelen,
void *buffer, size_t buflen);
int (*cnid_wipe) (struct _cnid_db *cdb);
-};
-typedef struct _cnid_db cnid_db;
+} cnid_db;
/*
* Consolidation of args passedn from main cnid_open to modules cnid_XXX_open, so
* that it's easier to add aditional args as required.
*/
struct cnid_open_args {
- const char *dir;
- mode_t mask;
- uint32_t flags;
-
- /* for dbd */
- const char *cnidserver;
- const char *cnidport;
-
- /* for MySQL */
- const void *obj;
- char *voluuid;
+ uint32_t cnid_args_flags;
+ struct vol *cnid_args_vol;
};
/*
void cnid_register(struct _cnid_module *module);
/* This function opens a CNID database for selected volume. */
-struct _cnid_db *cnid_open(const char *volpath,
- mode_t mask,
- char *type,
- int flags,
- const char *cnidsrv,
- const char *cnidport,
- const void *obj,
- char *uuid);
+struct _cnid_db *cnid_open(struct vol *vol, char *type, int flags);
cnid_t cnid_add (struct _cnid_db *cdb, const struct stat *st, const cnid_t did,
const char *name, const size_t len, cnid_t hint);
int cnid_delete (struct _cnid_db *cdb, cnid_t id);
#define CNID_DBD_RES_SRCH_DONE 0x06
#define DBD_MAX_SRCH_RSLTS 100
+#define DBD_NUM_OPEN_ARGS 3
struct cnid_dbd_rqst {
int op;
};
typedef struct CNID_bdb_private {
- uint32_t magic;
- char db_dir[MAXPATHLEN + 1]; /* Database directory without /.AppleDB appended */
- char *cnidserver;
- char *cnidport;
+ struct vol *vol;
int fd; /* File descriptor to cnid_dbd */
char stamp[ADEDLEN_PRIVSYN]; /* db timestamp */
char *client_stamp;
#define CNID_MYSQL_FLAG_DEPLETED (1 << 0) /* CNID set overflowed */
typedef struct CNID_mysql_private {
+ struct vol *vol;
uint32_t cnid_mysql_flags;
- uint32_t cnid_mysql_magic;
- char *cnid_mysql_volname;
- const void *cnid_mysql_obj;
MYSQL *cnid_mysql_con;
- atalk_uuid_t cnid_mysql_voluuid;
char *cnid_mysql_voluuid_str;
cnid_t cnid_mysql_hint;
MYSQL_STMT *cnid_lookup_stmt;
#ifndef _ATALK_CNID_PRIVATE_H
#define _ATALK_CNID_PRIVATE_H 1
-#define CNID_DB_MAGIC 0x434E4944U /* CNID */
-#define CNID_DATA_MAGIC 0x434E4945U /* CNIE */
-
#define CNID_OFS 0
#define CNID_LEN 4
#define ntoh64(x) (hton64(x))
#endif
+#ifndef SAFE_FREE
+#define SAFE_FREE(x) do { if ((x) != NULL) {free(x); x=NULL;} } while(0)
+#endif
+
#ifdef WITH_SENDFILE
extern ssize_t sys_sendfile (int __out_fd, int __in_fd, off_t *__offset,size_t __count);
#endif
cnid_t id;
int rc;
- if (!cdb || !(db = cdb->_private) || !st || !name) {
+ if (!cdb || !(db = cdb->cnid_db_private) || !st || !name) {
errno = CNID_ERR_PARAM;
return CNID_INVALID;
}
memset(&key, 0, sizeof(key));
memset(&data, 0, sizeof(data));
- if ((data.data = make_cnid_data(cdb->flags, st, did, name, len)) == NULL) {
+ if ((data.data = make_cnid_data(cdb->cnid_db_flags, st, did, name, len)) == NULL) {
LOG(log_error, logtype_default, "cnid_add: Path name is too long");
errno = CNID_ERR_PATH;
return CNID_INVALID;
int rc;
CNID_private *db;
- if (!cdb || !(db = cdb->_private) || !buffer || !len) {
+ if (!cdb || !(db = cdb->cnid_db_private) || !buffer || !len) {
errno = CNID_ERR_PARAM;
return -1;
}
return;
}
- if (!(db = cdb->_private)) {
+ if (!(db = cdb->cnid_db_private)) {
return;
}
db->db_didname->sync(db->db_didname, 0);
db->dbenv->close(db->dbenv, 0);
free(db);
- free(cdb->volpath);
free(cdb);
}
DBT key;
int rc;
- if (!cdb || !(db = cdb->_private) || !id || (db->flags & CNIDFLAG_DB_RO)) {
+ if (!cdb || !(db = cdb->cnid_db_private) || !id || (db->flags & CNIDFLAG_DB_RO)) {
return -1;
}
cnid_t id;
int rc;
- if (!cdb || !(db = cdb->_private) || (len > MAXPATHLEN)) {
+ if (!cdb || !(db = cdb->cnid_db_private) || (len > MAXPATHLEN)) {
return 0;
}
cnid_t id_devino, id_didname,id = 0;
int rc;
- if (!cdb || !(db = cdb->_private) || !st || !name) {
+ if (!cdb || !(db = cdb->cnid_db_private) || !st || !name) {
return 0;
}
- if ((buf = make_cnid_data(cdb->flags, st, did, name, len)) == NULL) {
+ if ((buf = make_cnid_data(cdb->cnid_db_flags, st, did, name, len)) == NULL) {
LOG(log_error, logtype_default, "cnid_lookup: Pathname is too long");
return 0;
}
type_devino = ntohl(type_devino);
}
- buf = make_cnid_data(cdb->flags, st, did, name, len);
+ buf = make_cnid_data(cdb->cnid_db_flags, st, did, name, len);
key.data = buf +CNID_DID_OFS;
key.size = CNID_DID_LEN + len + 1;
#ifdef CNID_BACKEND_CDB
+#include <atalk/volume.h>
#include <atalk/cnid_private.h>
#include "cnid_cdb_private.h"
}
/* --------------- */
-static struct _cnid_db *cnid_cdb_new(const char *volpath)
+static struct _cnid_db *cnid_cdb_new(struct vol *vol)
{
struct _cnid_db *cdb;
int major, minor, patch;
if ((cdb = (struct _cnid_db *) calloc(1, sizeof(struct _cnid_db))) == NULL)
return NULL;
- if ((cdb->volpath = strdup(volpath)) == NULL) {
- free(cdb);
- return NULL;
- }
-
- cdb->flags = CNID_FLAG_PERSISTENT;
-
+ cdb->cnid_db_vol = vol;
+ cdb->cnid_db_flags = CNID_FLAG_PERSISTENT;
cdb->cnid_add = cnid_cdb_add;
cdb->cnid_delete = cnid_cdb_delete;
cdb->cnid_get = cnid_cdb_get;
int open_flag, len;
static int first = 0;
int rc;
-
- if (!args->dir || *args->dir == 0) {
- return NULL;
- }
+ struct vol *vol = args->cnid_args_vol;
/* this checks .AppleDB.
We need space for dir + '/' + DBHOMELEN + '/' + DBLEN */
- if ((len = strlen(args->dir)) > (MAXPATHLEN - DBHOMELEN - DBLEN - 2)) {
- LOG(log_error, logtype_default, "cnid_open: Pathname too large: %s", args->dir);
+ if ((len = strlen(vol->v_path)) > (MAXPATHLEN - DBHOMELEN - DBLEN - 2)) {
+ LOG(log_error, logtype_default, "cnid_open: Pathname too large: %s", vol->v_path);
return NULL;
}
- if ((cdb = cnid_cdb_new(args->dir)) == NULL) {
+ if ((cdb = cnid_cdb_new(vol)) == NULL) {
LOG(log_error, logtype_default, "cnid_open: Unable to allocate memory for database");
return NULL;
}
goto fail_cdb;
}
- cdb->_private = (void *) db;
- db->magic = CNID_DB_MAGIC;
+ cdb->cnid_db_private = (void *) db;
- strcpy(path, args->dir);
+ strcpy(path, vol->v_path);
if (path[len - 1] != '/') {
strcat(path, "/");
len++;
}
strcpy(path + len, DBHOME);
- if ((stat(path, &st) < 0) && (ad_mkdir(path, 0777 & ~args->mask) < 0)) {
+ if ((stat(path, &st) < 0) && (ad_mkdir(path, 0777 & ~vol->v_umask) < 0)) {
LOG(log_error, logtype_default, "cnid_open: DBHOME mkdir failed for %s", path);
goto fail_adouble;
}
}
/* Open the database environment. */
- if ((rc = db->dbenv->open(db->dbenv, path, DBOPTIONS, 0666 & ~args->mask)) != 0) {
+ if ((rc = db->dbenv->open(db->dbenv, path, DBOPTIONS, 0666 & ~vol->v_umask)) != 0) {
LOG(log_error, logtype_default, "cnid_open: dbenv->open (rw) of %s failed: %s", path, db_strerror(rc));
/* FIXME: This should probably go. Even if it worked, any use for a read-only DB? Didier? */
if (rc == DB_RUNRECOVERY) {
/* We can't get a full transactional environment, so multi-access
* is out of the question. Let's assume a read-only environment,
* and try to at least get a shared memory pool. */
- if ((rc = db->dbenv->open(db->dbenv, path, DB_INIT_MPOOL, 0666 & ~args->mask)) != 0) {
+ if ((rc = db->dbenv->open(db->dbenv, path, DB_INIT_MPOOL, 0666 & ~vol->v_umask)) != 0) {
/* Nope, not a MPOOL, either. Last-ditch effort: we'll try to
* open the environment with no flags. */
- if ((rc = db->dbenv->open(db->dbenv, path, 0, 0666 & ~args->mask)) != 0) {
+ if ((rc = db->dbenv->open(db->dbenv, path, 0, 0666 & ~vol->v_umask)) != 0) {
LOG(log_error, logtype_default, "cnid_open: dbenv->open of %s failed: %s", path, db_strerror(rc));
goto fail_lock;
}
goto fail_appinit;
}
- if ((rc = my_open(db->db_cnid, DBCNID, DBCNID, DB_BTREE, open_flag, 0666 & ~args->mask)) != 0) {
+ if ((rc = my_open(db->db_cnid, DBCNID, DBCNID, DB_BTREE, open_flag, 0666 & ~vol->v_umask)) != 0) {
LOG(log_error, logtype_default, "cnid_open: Failed to open dev/ino database: %s",
db_strerror(rc));
goto fail_appinit;
goto fail_appinit;
}
- if ((rc = my_open(db->db_didname, DBCNID, DBDIDNAME, DB_BTREE, open_flag, 0666 & ~args->mask))) {
+ if ((rc = my_open(db->db_didname, DBCNID, DBDIDNAME, DB_BTREE, open_flag, 0666 & ~vol->v_umask))) {
LOG(log_error, logtype_default, "cnid_open: Failed to open did/name database: %s",
db_strerror(rc));
goto fail_appinit;
goto fail_appinit;
}
- if ((rc = my_open(db->db_devino, DBCNID, DBDEVINO, DB_BTREE, open_flag, 0666 & ~args->mask)) != 0) {
+ if ((rc = my_open(db->db_devino, DBCNID, DBDEVINO, DB_BTREE, open_flag, 0666 & ~vol->v_umask)) != 0) {
LOG(log_error, logtype_default, "cnid_open: Failed to open devino database: %s",
db_strerror(rc));
goto fail_appinit;
free(db);
fail_cdb:
- if (cdb->volpath != NULL)
- free(cdb->volpath);
free(cdb);
return NULL;
DBT key, data;
int rc;
- if (!cdb || !(db = cdb->_private) || !st || !name || hint == CNID_INVALID || hint < CNID_START) {
+ if (!cdb || !(db = cdb->cnid_db_private) || !st || !name || hint == CNID_INVALID || hint < CNID_START) {
errno = CNID_ERR_PARAM;
return CNID_INVALID;
}
memset(&key, 0, sizeof(key));
memset(&data, 0, sizeof(data));
- if ((data.data = make_cnid_data(cdb->flags, st, did, name, len)) == NULL) {
+ if ((data.data = make_cnid_data(cdb->cnid_db_flags, st, did, name, len)) == NULL) {
LOG(log_error, logtype_default, "cnid_add: Path name is too long");
errno = CNID_ERR_PATH;
return CNID_INVALID;
DBT key, data;
int rc;
- if (!cdb || !(db = cdb->_private) || !id || !(*id)) {
+ if (!cdb || !(db = cdb->cnid_db_private) || !id || !(*id)) {
return NULL;
}
int notfound = 0;
char getbuf[CNID_HEADER_LEN + MAXPATHLEN +1];
- if (!cdb || !(db = cdb->_private) || !id || !st || !name || (db->flags & CNIDFLAG_DB_RO)) {
+ if (!cdb || !(db = cdb->cnid_db_private) || !id || !st || !name || (db->flags & CNIDFLAG_DB_RO)) {
return -1;
}
memset(&pkey, 0, sizeof(pkey));
memset(&data, 0, sizeof(data));
- buf = make_cnid_data(cdb->flags, st, did, name, len);
+ buf = make_cnid_data(cdb->cnid_db_flags, st, did, name, len);
key.data = buf +CNID_DEVINO_OFS;
key.size = CNID_DEVINO_LEN;
}
memset(&pkey, 0, sizeof(pkey));
- buf = make_cnid_data(cdb->flags, st, did, name, len);
+ buf = make_cnid_data(cdb->cnid_db_flags, st, did, name, len);
key.data = buf + CNID_DID_OFS;
key.size = CNID_DID_LEN + len + 1;
memset(&data, 0, sizeof(data));
/* Make a new entry. */
- buf = make_cnid_data(cdb->flags, st, did, name, len);
+ buf = make_cnid_data(cdb->cnid_db_flags, st, did, name, len);
data.data = buf;
memcpy(data.data, &id, sizeof(id));
data.size = CNID_HEADER_LEN + len + 1;
#include <atalk/logger.h>
#include <atalk/util.h>
#include <atalk/compat.h>
+#include <atalk/volume.h>
/* List of all registered modules. */
static struct list_head modules = ATALK_LIST_HEAD_INIT(modules);
}
/* Opens CNID database using particular back-end */
-struct _cnid_db *cnid_open(const char *volpath, mode_t mask, char *type, int flags,
- const char *cnidsrv, const char *cnidport, const void *obj, char *uuid)
+struct _cnid_db *cnid_open(struct vol *vol, char *type, int flags)
{
struct _cnid_db *db;
cnid_module *mod = NULL;
LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
return NULL;
}
- if (cnid_dir(volpath, mask) < 0) {
+ if (cnid_dir(vol->v_path, vol->v_umask) < 0) {
if ( setegid(gid) < 0 || seteuid(uid) < 0) {
LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
exit(EXITERR_SYS);
}
}
- struct cnid_open_args args = {volpath, mask, flags, cnidsrv, cnidport, obj, uuid};
+ struct cnid_open_args args = {
+ .cnid_args_flags = flags,
+ .cnid_args_vol = vol
+ };
+
db = mod->cnid_open(&args);
if ((mod->flags & CNID_FLAG_SETUID) && !(flags & CNID_FLAG_MEMORY)) {
}
if (NULL == db) {
- LOG(log_error, logtype_afpd, "Cannot open CNID db at [%s].", volpath);
+ LOG(log_error, logtype_afpd, "Cannot open CNID db at [%s].", vol->v_path);
return NULL;
}
- /* FIXME should module know about it ? */
- if ((flags & CNID_FLAG_NODEV)) {
- db->flags |= CNID_FLAG_NODEV;
- }
- db->flags |= mod->flags;
- if ((db->flags & CNID_FLAG_BLOCK)) {
+ db->cnid_db_flags |= mod->flags;
+ if (flags & CNID_FLAG_NODEV)
+ db->cnid_db_flags |= CNID_FLAG_NODEV;
+
+ if (db->cnid_db_flags & CNID_FLAG_BLOCK) {
sigemptyset(&sigblockset);
sigaddset(&sigblockset, SIGTERM);
sigaddset(&sigblockset, SIGHUP);
return;
}
/* cnid_close free db */
- flags = db->flags;
+ flags = db->cnid_db_flags;
block_signal(flags);
db->cnid_close(db);
unblock_signal(flags);
if (len == 0)
return CNID_INVALID;
- block_signal(cdb->flags);
+ block_signal(cdb->cnid_db_flags);
ret = valide(cdb->cnid_add(cdb, st, did, name, len, hint));
- unblock_signal(cdb->flags);
+ unblock_signal(cdb->cnid_db_flags);
return ret;
}
{
int ret;
- block_signal(cdb->flags);
+ block_signal(cdb->cnid_db_flags);
ret = cdb->cnid_delete(cdb, id);
- unblock_signal(cdb->flags);
+ unblock_signal(cdb->cnid_db_flags);
return ret;
}
{
cnid_t ret;
- block_signal(cdb->flags);
+ block_signal(cdb->cnid_db_flags);
ret = valide(cdb->cnid_get(cdb, did, name, len));
- unblock_signal(cdb->flags);
+ unblock_signal(cdb->cnid_db_flags);
return ret;
}
memcpy(buffer, &t, sizeof(time_t));
return 0;
}
- block_signal(cdb->flags);
+ block_signal(cdb->cnid_db_flags);
ret = cdb->cnid_getstamp(cdb, buffer, len);
- unblock_signal(cdb->flags);
+ unblock_signal(cdb->cnid_db_flags);
return ret;
}
{
cnid_t ret;
- block_signal(cdb->flags);
+ block_signal(cdb->cnid_db_flags);
ret = valide(cdb->cnid_lookup(cdb, st, did, name, len));
- unblock_signal(cdb->flags);
+ unblock_signal(cdb->cnid_db_flags);
return ret;
}
return -1;
}
- block_signal(cdb->flags);
+ block_signal(cdb->cnid_db_flags);
ret = cdb->cnid_find(cdb, name, namelen, buffer, buflen);
- unblock_signal(cdb->flags);
+ unblock_signal(cdb->cnid_db_flags);
return ret;
}
{
char *ret;
- block_signal(cdb->flags);
+ block_signal(cdb->cnid_db_flags);
ret = cdb->cnid_resolve(cdb, id, buffer, len);
- unblock_signal(cdb->flags);
+ unblock_signal(cdb->cnid_db_flags);
if (ret && !strcmp(ret, "..")) {
LOG(log_error, logtype_afpd, "cnid_resolve: name is '..', corrupted db? ");
ret = NULL;
{
int ret;
- block_signal(cdb->flags);
+ block_signal(cdb->cnid_db_flags);
ret = cdb->cnid_update(cdb, id, st, did, name, len);
- unblock_signal(cdb->flags);
+ unblock_signal(cdb->cnid_db_flags);
return ret;
}
{
cnid_t ret;
- block_signal(cdb->flags);
+ block_signal(cdb->cnid_db_flags);
ret = cdb->cnid_rebuild_add(cdb, st, did, name, len, hint);
- unblock_signal(cdb->flags);
+ unblock_signal(cdb->cnid_db_flags);
return ret;
}
{
int ret = 0;
- block_signal(cdb->flags);
+ block_signal(cdb->cnid_db_flags);
if (cdb->cnid_wipe)
ret = cdb->cnid_wipe(cdb);
- unblock_signal(cdb->flags);
+ unblock_signal(cdb->cnid_db_flags);
return ret;
}
#include <atalk/cnid.h>
#include <atalk/cnid_bdb_private.h>
#include <atalk/util.h>
+#include <atalk/volume.h>
#include "cnid_dbd.h"
static int init_tsock(CNID_bdb_private *db)
{
int fd;
- int len;
- struct iovec iov[2];
+ int len[DBD_NUM_OPEN_ARGS];
+ int iovecs;
+ struct iovec iov[DBD_NUM_OPEN_ARGS + 1] = {{0}};
+ struct vol *vol = db->vol;
+ ssize_t iovlen;
- LOG(log_debug, logtype_cnid, "init_tsock: BEGIN. Opening volume '%s', CNID Server: %s/%s",
- db->db_dir, db->cnidserver, db->cnidport);
+ LOG(log_debug, logtype_cnid, "connecting to CNID server: %s:%s",
+ vol->v_cnidserver, vol->v_cnidport);
- if ((fd = tsock_getfd(db->cnidserver, db->cnidport)) < 0)
+ if ((fd = tsock_getfd(vol->v_cnidserver, vol->v_cnidport)) < 0)
return -1;
- len = strlen(db->db_dir);
+ LOG(log_debug, logtype_cnid, "connecting volume '%s', path: %s, user: %s",
+ vol->v_configname, vol->v_path, vol->v_obj->username[0] ? vol->v_obj->username : "-");
+
+ iovecs = 1 + DBD_NUM_OPEN_ARGS - 1;
+
+ len[0] = strlen(vol->v_configname) + 1;
+ len[1] = strlen(vol->v_path) + 1;
+ len[2] = strlen(vol->v_obj->username);
- iov[0].iov_base = &len;
- iov[0].iov_len = sizeof(int);
+ iov[0].iov_base = &len[0];
+ iov[0].iov_len = DBD_NUM_OPEN_ARGS * sizeof(int);
- iov[1].iov_base = db->db_dir;
- iov[1].iov_len = len;
+ iov[1].iov_base = vol->v_configname;
+ iov[1].iov_len = len[0];
- if (write_vec(fd, iov, len + sizeof(int), 2) != len + sizeof(int)) {
+ iov[2].iov_base = vol->v_path;
+ iov[2].iov_len = len[1];
+
+ if (len[2] > 0) {
+ len[2] += 1;
+ iovecs++;
+ iov[3].iov_base = vol->v_obj->username;
+ iov[3].iov_len = len[2];
+ }
+
+ iovlen = iov[0].iov_len + iov[1].iov_len + iov[2].iov_len + iov[3].iov_len;
+
+ if (write_vec(fd, iov, iovlen, iovecs) != iovlen) {
LOG(log_error, logtype_cnid, "init_tsock: Error/short write: %s", strerror(errno));
close(fd);
return -1;
}
if (write_vec(db->fd, iov, towrite, vecs) != towrite) {
- LOG(log_warning, logtype_cnid, "send_packet: Error writev rqst (db_dir %s): %s",
- db->db_dir, strerror(errno));
+ LOG(log_warning, logtype_cnid, "send_packet: Error writev rqst (volume %s): %s",
+ db->vol->v_localname, strerror(errno));
return -1;
}
ret = readt(db->fd, rply, sizeof(struct cnid_dbd_rply), 0, ONE_DELAY);
if (ret != sizeof(struct cnid_dbd_rply)) {
- LOG(log_debug, logtype_cnid, "dbd_rpc: Error reading header from fd (db_dir %s): %s",
- db->db_dir, ret == -1 ? strerror(errno) : "closed");
+ LOG(log_debug, logtype_cnid, "dbd_rpc: Error reading header from fd (volume %s): %s",
+ db->vol->v_localname, ret == -1 ? strerror(errno) : "closed");
rply->name = nametmp;
return -1;
}
rply->name = nametmp;
if (rply->namelen && 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);
+ "dbd_rpc: Error reading name (volume %s): %s name too long: %d. only wanted %d, garbage?",
+ db->vol->v_localname, rply->name, rply->namelen, len);
return -1;
}
if (rply->namelen && (ret = readt(db->fd, rply->name, rply->namelen, 0, ONE_DELAY)) != (ssize_t)rply->namelen) {
- 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 (volume %s): %s",
+ db->vol->v_localname, ret == -1?strerror(errno):"closed");
return -1;
}
} else { /* db->notfirst == 0 */
db->notfirst = 1;
}
- LOG(log_debug, logtype_cnid, "transmit: attached to '%s'", db->db_dir);
+ LOG(log_debug, logtype_cnid, "transmit: attached to '%s'", db->vol->v_localname);
}
if (!dbd_rpc(db, rqst, rply)) {
LOG(log_maxdebug, logtype_cnid, "transmit: {done}");
if (errno == ECONNREFUSED) { /* errno carefully injected in tsock_getfd */
/* give up */
- LOG(log_error, logtype_cnid, "transmit: connection refused (db_dir %s)", db->db_dir);
+ LOG(log_error, logtype_cnid, "transmit: connection refused (volume %s)", db->vol->v_localname);
return -1;
}
if (!clean) { /* don't sleep if just got disconnected by cnid server */
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 (volume %s) timed out.", db->vol->v_localname);
return -1;
}
/* sleep a little before retry */
}
/* ---------------------- */
-static struct _cnid_db *cnid_dbd_new(const char *volpath)
+static struct _cnid_db *cnid_dbd_new(struct vol *vol)
{
struct _cnid_db *cdb;
if ((cdb = (struct _cnid_db *)calloc(1, sizeof(struct _cnid_db))) == NULL)
return NULL;
- if ((cdb->volpath = strdup(volpath)) == NULL) {
- free(cdb);
- return NULL;
- }
-
- cdb->flags = CNID_FLAG_PERSISTENT | CNID_FLAG_LAZY_INIT;
-
+ cdb->cnid_db_vol = vol;
+ cdb->cnid_db_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;
CNID_bdb_private *db = NULL;
struct _cnid_db *cdb = NULL;
- if (!args->dir) {
- return NULL;
- }
-
- if ((cdb = cnid_dbd_new(args->dir)) == NULL) {
+ if ((cdb = cnid_dbd_new(args->cnid_args_vol)) == NULL) {
LOG(log_error, logtype_cnid, "cnid_open: Unable to allocate memory for database");
return NULL;
}
goto cnid_dbd_open_fail;
}
- cdb->_private = db;
+ cdb->cnid_db_private = db;
- /* We keep a copy of the directory in the db structure so that we can
- transparently reconnect later. */
- strcpy(db->db_dir, args->dir);
- db->magic = CNID_DB_MAGIC;
db->fd = -1;
- db->cnidserver = strdup(args->cnidserver);
- db->cnidport = strdup(args->cnidport);
+ db->vol = args->cnid_args_vol;
- LOG(log_debug, logtype_cnid, "cnid_dbd_open: Finished initializing cnid dbd module for volume '%s'", db->db_dir);
+ LOG(log_debug, logtype_cnid, "Finished initializing CNID dbd module for volume '%s'",
+ args->cnid_args_vol->v_localname);
return cdb;
cnid_dbd_open_fail:
- if (cdb != NULL) {
- if (cdb->volpath != NULL) {
- free(cdb->volpath);
- }
+ if (cdb != NULL)
free(cdb);
- }
if (db != NULL)
free(db);
return;
}
- if ((db = cdb->_private) != NULL) {
- LOG(log_debug, logtype_cnid, "closing database connection for volume '%s'", db->db_dir);
+ if ((db = cdb->cnid_db_private) != NULL) {
+ LOG(log_debug, logtype_cnid, "closing database connection for volume '%s'", db->vol->v_localname);
if (db->fd >= 0)
close(db->fd);
free(db);
}
- free(cdb->volpath);
free(cdb);
return;
struct cnid_dbd_rply rply;
cnid_t id;
- if (!cdb || !(db = cdb->_private) || !st || !name) {
+ if (!cdb || !(db = cdb->cnid_db_private) || !st || !name) {
LOG(log_error, logtype_cnid, "cnid_add: Parameter error");
errno = CNID_ERR_PARAM;
return CNID_INVALID;
RQST_RESET(&rqst);
rqst.op = CNID_DBD_OP_ADD;
- if (!(cdb->flags & CNID_FLAG_NODEV)) {
+ if (!(cdb->cnid_db_flags & CNID_FLAG_NODEV)) {
rqst.dev = st->st_dev;
}
struct cnid_dbd_rply rply;
cnid_t id;
- if (!cdb || !(db = cdb->_private) || !name) {
+ if (!cdb || !(db = cdb->cnid_db_private) || !name) {
LOG(log_error, logtype_cnid, "cnid_dbd_get: Parameter error");
errno = CNID_ERR_PARAM;
return CNID_INVALID;
struct cnid_dbd_rply rply;
char *name;
- if (!cdb || !(db = cdb->_private) || !id || !(*id)) {
+ if (!cdb || !(db = cdb->cnid_db_private) || !id || !(*id)) {
LOG(log_error, logtype_cnid, "cnid_resolve: Parameter error");
errno = CNID_ERR_PARAM;
return NULL;
{
CNID_bdb_private *db;
- if (!cdb || !(db = cdb->_private) || len != ADEDLEN_PRIVSYN) {
+ if (!cdb || !(db = cdb->cnid_db_private) || len != ADEDLEN_PRIVSYN) {
LOG(log_error, logtype_cnid, "cnid_getstamp: Parameter error");
errno = CNID_ERR_PARAM;
return -1;
struct cnid_dbd_rply rply;
cnid_t id;
- if (!cdb || !(db = cdb->_private) || !st || !name) {
+ if (!cdb || !(db = cdb->cnid_db_private) || !st || !name) {
LOG(log_error, logtype_cnid, "cnid_lookup: Parameter error");
errno = CNID_ERR_PARAM;
return CNID_INVALID;
RQST_RESET(&rqst);
rqst.op = CNID_DBD_OP_LOOKUP;
- if (!(cdb->flags & CNID_FLAG_NODEV)) {
+ if (!(cdb->cnid_db_flags & CNID_FLAG_NODEV)) {
rqst.dev = st->st_dev;
}
struct cnid_dbd_rply rply;
int count;
- if (!cdb || !(db = cdb->_private) || !name) {
+ if (!cdb || !(db = cdb->cnid_db_private) || !name) {
LOG(log_error, logtype_cnid, "cnid_find: Parameter error");
errno = CNID_ERR_PARAM;
return CNID_INVALID;
struct cnid_dbd_rqst rqst;
struct cnid_dbd_rply rply;
- if (!cdb || !(db = cdb->_private) || !id || !st || !name) {
+ if (!cdb || !(db = cdb->cnid_db_private) || !id || !st || !name) {
LOG(log_error, logtype_cnid, "cnid_update: Parameter error");
errno = CNID_ERR_PARAM;
return -1;
RQST_RESET(&rqst);
rqst.op = CNID_DBD_OP_UPDATE;
rqst.cnid = id;
- if (!(cdb->flags & CNID_FLAG_NODEV)) {
+ if (!(cdb->cnid_db_flags & CNID_FLAG_NODEV)) {
rqst.dev = st->st_dev;
}
rqst.ino = st->st_ino;
struct cnid_dbd_rply rply;
cnid_t id;
- if (!cdb || !(db = cdb->_private) || !st || !name || hint == CNID_INVALID) {
+ if (!cdb || !(db = cdb->cnid_db_private) || !st || !name || hint == CNID_INVALID) {
LOG(log_error, logtype_cnid, "cnid_rebuild_add: Parameter error");
errno = CNID_ERR_PARAM;
return CNID_INVALID;
RQST_RESET(&rqst);
rqst.op = CNID_DBD_OP_REBUILD_ADD;
- if (!(cdb->flags & CNID_FLAG_NODEV)) {
+ if (!(cdb->cnid_db_flags & CNID_FLAG_NODEV)) {
rqst.dev = st->st_dev;
}
struct cnid_dbd_rqst rqst;
struct cnid_dbd_rply rply;
- if (!cdb || !(db = cdb->_private) || !id) {
+ if (!cdb || !(db = cdb->cnid_db_private) || !id) {
LOG(log_error, logtype_cnid, "cnid_delete: Parameter error");
errno = CNID_ERR_PARAM;
return -1;
struct cnid_dbd_rqst rqst;
struct cnid_dbd_rply rply;
- if (!cdb || !(db = cdb->_private)) {
+ if (!cdb || !(db = cdb->cnid_db_private)) {
LOG(log_error, logtype_cnid, "cnid_wipe: Parameter error");
errno = CNID_ERR_PARAM;
return -1;
struct _cnid_last_private *priv;
- if (!cdb || !(cdb->_private))
+ if (!cdb || !(cdb->cnid_db_private))
return CNID_INVALID;
- priv = (struct _cnid_last_private *) (cdb->_private);
+ priv = (struct _cnid_last_private *) (cdb->cnid_db_private);
if (S_ISDIR(st->st_mode))
return htonl(priv->last_did++);
void cnid_last_close(struct _cnid_db *cdb)
{
- free(cdb->volpath);
- free(cdb->_private);
+ free(cdb->cnid_db_private);
free(cdb);
}
}
-static struct _cnid_db *cnid_last_new(const char *volpath)
+static struct _cnid_db *cnid_last_new(struct vol *vol)
{
struct _cnid_db *cdb;
struct _cnid_last_private *priv;
if ((cdb = (struct _cnid_db *) calloc(1, sizeof(struct _cnid_db))) == NULL)
return NULL;
- if ((cdb->volpath = strdup(volpath)) == NULL) {
- free(cdb);
- return NULL;
- }
-
- if ((cdb->_private = calloc(1, sizeof(struct _cnid_last_private))) == NULL) {
- free(cdb->volpath);
+ if ((cdb->cnid_db_private = calloc(1, sizeof(struct _cnid_last_private))) == NULL) {
free(cdb);
return NULL;
}
/* Set up private state */
- priv = (struct _cnid_last_private *) (cdb->_private);
+ priv = (struct _cnid_last_private *) (cdb->cnid_db_private);
priv->last_did = 17;
/* Set up standard fields */
- cdb->flags = 0;
+ cdb->cnid_db_flags = 0;
cdb->cnid_add = cnid_last_add;
cdb->cnid_delete = cnid_last_delete;
cdb->cnid_get = cnid_last_get;
{
struct _cnid_db *cdb;
- if (!args->dir) {
- return NULL;
- }
-
- if ((cdb = cnid_last_new(args->dir)) == NULL) {
+ if ((cdb = cnid_last_new(args->cnid_args_vol)) == NULL) {
LOG(log_error, logtype_default, "cnid_open: Unable to allocate memory for database");
return NULL;
}
#include "config.h"
#endif /* HAVE_CONFIG_H */
+#undef _FORTIFY_SOURCE
+
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <atalk/cnid_bdb_private.h>
#include <atalk/errchk.h>
#include <atalk/globals.h>
+#include <atalk/volume.h>
+
static MYSQL_BIND lookup_param[4], lookup_result[5];
static MYSQL_BIND add_param[4], put_param[5];
EC_INIT;
CNID_mysql_private *db;
- if (!cdb || !(db = cdb->_private) || !id) {
+ if (!cdb || !(db = cdb->cnid_db_private) || !id) {
LOG(log_error, logtype_cnid, "cnid_mysql_delete: Parameter error");
errno = CNID_ERR_PARAM;
EC_FAIL;
return;
}
- if ((db = cdb->_private) != NULL) {
- LOG(log_debug, logtype_cnid, "closing database connection for volume '%s'", db->cnid_mysql_volname);
+ if ((db = cdb->cnid_db_private) != NULL) {
+ LOG(log_debug, logtype_cnid, "closing database connection for volume '%s'",
+ cdb->cnid_db_vol->v_localname);
free(db->cnid_mysql_voluuid_str);
free(db);
}
- free(cdb->volpath);
free(cdb);
return;
CNID_mysql_private *db;
cnid_t update_id;
- if (!cdb || !(db = cdb->_private) || !id || !st || !name) {
+ if (!cdb || !(db = cdb->cnid_db_private) || !id || !st || !name) {
LOG(log_error, logtype_cnid, "cnid_update: Parameter error");
errno = CNID_ERR_PARAM;
EC_FAIL;
cnid_t id = CNID_INVALID;
bool have_result = false;
- if (!cdb || !(db = cdb->_private) || !st || !name) {
+ if (!cdb || !(db = cdb->cnid_db_private) || !st || !name) {
LOG(log_error, logtype_cnid, "cnid_mysql_lookup: Parameter error");
errno = CNID_ERR_PARAM;
EC_FAIL;
MYSQL_STMT *stmt;
my_ulonglong lastid;
- if (!cdb || !(db = cdb->_private) || !st || !name) {
+ if (!cdb || !(db = cdb->cnid_db_private) || !st || !name) {
LOG(log_error, logtype_cnid, "cnid_mysql_add: Parameter error");
errno = CNID_ERR_PARAM;
EC_FAIL;
MYSQL_RES *result = NULL;
MYSQL_ROW row;
- if (!cdb || !(db = cdb->_private) || !name) {
+ if (!cdb || !(db = cdb->cnid_db_private) || !name) {
LOG(log_error, logtype_cnid, "cnid_mysql_get: Parameter error");
errno = CNID_ERR_PARAM;
EC_FAIL;
MYSQL_RES *result = NULL;
MYSQL_ROW row;
- if (!cdb || !(db = cdb->_private)) {
+ if (!cdb || !(db = cdb->cnid_db_private)) {
LOG(log_error, logtype_cnid, "cnid_mysql_get: Parameter error");
errno = CNID_ERR_PARAM;
EC_FAIL;
MYSQL_RES *result = NULL;
MYSQL_ROW row;
- if (!cdb || !(db = cdb->_private)) {
+ if (!cdb || !(db = cdb->cnid_db_private)) {
LOG(log_error, logtype_cnid, "cnid_find: Parameter error");
errno = CNID_ERR_PARAM;
return CNID_INVALID;
if (cnid_mysql_execute(db->cnid_mysql_con,
"SELECT Stamp FROM volumes WHERE VolPath='%s'",
- db->cnid_mysql_volname)) {
+ cdb->cnid_db_vol->v_path)) {
if (mysql_errno(db->cnid_mysql_con) != ER_DUP_ENTRY) {
LOG(log_error, logtype_cnid, "MySQL query error: %s", mysql_error(db->cnid_mysql_con));
EC_FAIL;
EC_FAIL;
}
if (!mysql_num_rows(result)) {
- LOG(log_error, logtype_cnid, "Can't get DB stamp for volumes \"%s\"", db->cnid_mysql_volname);
+ LOG(log_error, logtype_cnid, "Can't get DB stamp for volumes \"%s\"", cdb->cnid_db_vol->v_path);
EC_FAIL;
}
row = mysql_fetch_row(result);
CNID_mysql_private *db;
MYSQL_RES *result = NULL;
- if (!cdb || !(db = cdb->_private)) {
+ if (!cdb || !(db = cdb->cnid_db_private)) {
LOG(log_error, logtype_cnid, "cnid_wipe: Parameter error");
errno = CNID_ERR_PARAM;
return -1;
EC_EXIT;
}
-static struct _cnid_db *cnid_mysql_new(const char *volpath)
+static struct _cnid_db *cnid_mysql_new(struct vol *vol)
{
struct _cnid_db *cdb;
if ((cdb = (struct _cnid_db *)calloc(1, sizeof(struct _cnid_db))) == NULL)
return NULL;
- if ((cdb->volpath = strdup(volpath)) == NULL) {
- free(cdb);
- return NULL;
- }
-
- cdb->flags = CNID_FLAG_PERSISTENT | CNID_FLAG_LAZY_INIT;
+ cdb->cnid_db_vol = vol;
+ cdb->cnid_db_flags = CNID_FLAG_PERSISTENT | CNID_FLAG_LAZY_INIT;
cdb->cnid_add = cnid_mysql_add;
cdb->cnid_delete = cnid_mysql_delete;
cdb->cnid_get = cnid_mysql_get;
static const char *printuuid(const unsigned char *uuid) {
static char uuidstring[64];
- const char *uuidmask;
int i = 0;
unsigned char c;
struct _cnid_db *cdb = NULL;
MYSQL_RES *result = NULL;
MYSQL_ROW row;
+ struct vol *vol = args->cnid_args_vol;
- EC_NULL( cdb = cnid_mysql_new(args->dir) );
+ EC_NULL( cdb = cnid_mysql_new(vol) );
EC_NULL( db = (CNID_mysql_private *)calloc(1, sizeof(CNID_mysql_private)) );
- cdb->_private = db;
+ cdb->cnid_db_private = db;
- db->cnid_mysql_volname = strdup(args->dir); /* db_dir contains the volume name */
- db->cnid_mysql_magic = CNID_DB_MAGIC;
- db->cnid_mysql_obj = args->obj;
- memcpy(db->cnid_mysql_voluuid, args->voluuid, sizeof(atalk_uuid_t));
- db->cnid_mysql_voluuid_str = strdup(printuuid(db->cnid_mysql_voluuid));
+ db->cnid_mysql_voluuid_str = strdup(printuuid(vol->v_uuid));
/* Initialize and connect to MySQL server */
EC_NULL( db->cnid_mysql_con = mysql_init(NULL) );
int my_timeout = 600;
EC_ZERO( mysql_options(db->cnid_mysql_con, MYSQL_OPT_CONNECT_TIMEOUT, &my_timeout) );
- const AFPObj *obj = db->cnid_mysql_obj;
+ const AFPObj *obj = vol->v_obj;
EC_NULL( mysql_real_connect(db->cnid_mysql_con,
obj->options.cnid_mysql_host,
"INSERT INTO volumes (VolUUID,Volpath,Stamp,Depleted) "
"VALUES('%s','%s','%s',0)",
db->cnid_mysql_voluuid_str,
- db->cnid_mysql_volname,
+ vol->v_path,
blob)) {
if (mysql_errno(db->cnid_mysql_con) != ER_DUP_ENTRY) {
LOG(log_error, logtype_cnid, "MySQL query error: %s", mysql_error(db->cnid_mysql_con));
EC_ZERO( init_prepared_stmt(db) );
LOG(log_debug, logtype_cnid, "Finished initializing MySQL CNID module for volume '%s'",
- db->cnid_mysql_volname);
+ vol->v_path);
EC_CLEANUP:
if (result)
mysql_free_result(result);
if (ret != 0) {
- if (cdb) {
- if (cdb->volpath != NULL) {
- free(cdb->volpath);
- }
+ if (cdb)
free(cdb);
- }
cdb = NULL;
if (db)
free(db);
TDB_DATA key, data;
int rc;
- if (!cdb || !(priv = cdb->_private) || !st || !name) {
+ if (!cdb || !(priv = cdb->cnid_db_private) || !st || !name) {
errno = CNID_ERR_PARAM;
return CNID_INVALID;
}
key.dptr = (unsigned char *)&hint;
key.dsize = sizeof(cnid_t);
- if ((data.dptr = make_tdb_data(cdb->flags, lstp, did, name, len)) == NULL) {
+ if ((data.dptr = make_tdb_data(cdb->cnid_db_flags, lstp, did, name, len)) == NULL) {
LOG(log_error, logtype_default, "tdb_add: Path name is too long");
errno = CNID_ERR_PATH;
return CNID_INVALID;
{
struct _cnid_tdb_private *db;
- free(cdb->volpath);
- db = (struct _cnid_tdb_private *)cdb->_private;
+ db = (struct _cnid_tdb_private *)cdb->cnid_db_private;
tdb_close(db->tdb_cnid);
- free(cdb->_private);
+ free(cdb->cnid_db_private);
free(cdb);
}
struct _cnid_tdb_private *db;
TDB_DATA key, data;
- if (!cdb || !(db = cdb->_private) || !id) {
+ if (!cdb || !(db = cdb->cnid_db_private) || !id) {
return -1;
}
memset(&key, 0, sizeof(key));
TDB_DATA key, data;
cnid_t id;
- if (!cdb || !(db = cdb->_private) || (len > MAXPATHLEN)) {
+ if (!cdb || !(db = cdb->cnid_db_private) || (len > MAXPATHLEN)) {
return 0;
}
int update = 0;
cnid_t id_devino = 0, id_didname = 0,id = 0;
- if (!cdb || !(db = cdb->_private) || !st || !name) {
+ if (!cdb || !(db = cdb->cnid_db_private) || !st || !name) {
return 0;
}
- if ((buf = (char *)make_tdb_data(cdb->flags, st, did, name, len)) == NULL) {
+ if ((buf = (char *)make_tdb_data(cdb->cnid_db_flags, st, did, name, len)) == NULL) {
LOG(log_error, logtype_default, "tdb_lookup: Pathname is too long");
return 0;
}
#include "cnid_tdb.h"
#include <atalk/logger.h>
+#include <atalk/volume.h>
+
#include <stdlib.h>
#define DBHOME ".AppleDB"
#define DBHOMELEN 9 /* strlen(DBHOME) +1 for / */
#define DBVERSION2 0x00000002U
#define DBVERSION DBVERSION2
-static struct _cnid_db *cnid_tdb_new(const char *volpath)
+static struct _cnid_db *cnid_tdb_new(struct vol *vol)
{
struct _cnid_db *cdb;
- struct _cnid_tdb_private *priv;
if ((cdb = (struct _cnid_db *) calloc(1, sizeof(struct _cnid_db))) == NULL)
return NULL;
- if ((cdb->volpath = strdup(volpath)) == NULL) {
- free(cdb);
- return NULL;
- }
+ cdb->cnid_db_vol = vol;
- if ((cdb->_private = calloc(1, sizeof(struct _cnid_tdb_private))) == NULL) {
- free(cdb->volpath);
+ if ((cdb->cnid_db_private = calloc(1, sizeof(struct _cnid_tdb_private))) == NULL) {
free(cdb);
return NULL;
}
- /* Set up private state */
- priv = (struct _cnid_tdb_private *) (cdb->_private);
-
/* Set up standard fields */
- cdb->flags = CNID_FLAG_PERSISTENT;
+ cdb->cnid_db_flags = CNID_FLAG_PERSISTENT;
cdb->cnid_add = cnid_tdb_add;
cdb->cnid_delete = cnid_tdb_delete;
TDB_DATA key, data;
int hash_size = 131071;
int tdb_flags = 0;
+ struct vol *vol = args->cnid_args_vol;
- if (!args->dir) {
- /* note: dir and path are not used for in memory db */
+ if ((cdb = cnid_tdb_new(vol)) == NULL) {
+ LOG(log_error, logtype_default, "tdb_open: Unable to allocate memory for tdb");
return NULL;
}
- if ((len = strlen(args->dir)) > (MAXPATHLEN - DBLEN - 1)) {
- LOG(log_error, logtype_default, "tdb_open: Pathname too large: %s", args->dir);
- return NULL;
- }
-
- if ((cdb = cnid_tdb_new(args->dir)) == NULL) {
- LOG(log_error, logtype_default, "tdb_open: Unable to allocate memory for tdb");
+ if ((len = strlen(vol->v_path)) > (MAXPATHLEN - DBLEN - 1)) {
+ LOG(log_error, logtype_default, "tdb_open: Pathname too large: %s", vol->v_path);
return NULL;
}
- strcpy(path, args->dir);
+ strcpy(path, vol->v_path);
if (path[len - 1] != '/') {
strcat(path, "/");
len++;
}
strcpy(path + len, DBHOME);
- if (!(args->flags & CNID_FLAG_MEMORY)) {
- if ((stat(path, &st) < 0) && (ad_mkdir(path, 0777 & ~args->mask) < 0)) {
+ if (!(args->cnid_args_flags & CNID_FLAG_MEMORY)) {
+ if ((stat(path, &st) < 0) && (ad_mkdir(path, 0777 & ~vol->v_umask) < 0)) {
LOG(log_error, logtype_default, "tdb_open: DBHOME mkdir failed for %s", path);
goto fail;
}
}
strcat(path, "/");
- db = (struct _cnid_tdb_private *)cdb->_private;
+ db = (struct _cnid_tdb_private *)cdb->cnid_db_private;
path[len + DBHOMELEN] = '\0';
strcat(path, DBCNID);
- db->tdb_cnid = tdb_open(path, hash_size, tdb_flags , O_RDWR | O_CREAT, 0666 & ~args->mask);
+ db->tdb_cnid = tdb_open(path, hash_size, tdb_flags , O_RDWR | O_CREAT, 0666 & ~vol->v_umask);
if (!db->tdb_cnid) {
LOG(log_error, logtype_default, "tdb_open: unable to open tdb", path);
goto fail;
return cdb;
fail:
- free(cdb->_private);
- free(cdb->volpath);
+ free(cdb->cnid_db_private);
free(cdb);
return NULL;
struct _cnid_tdb_private *db;
TDB_DATA key, data;
- if (!cdb || !(db = cdb->_private) || !id || !(*id)) {
+ if (!cdb || !(db = cdb->cnid_db_private) || !id || !(*id)) {
return NULL;
}
key.dptr = (unsigned char *)id;
struct _cnid_tdb_private *db;
TDB_DATA key, data, altdata;
- if (!cdb || !(db = cdb->_private) || !id || !st || !name || (db->flags & CNIDFLAG_DB_RO)) {
+ if (!cdb || !(db = cdb->cnid_db_private) || !id || !st || !name || (db->flags & CNIDFLAG_DB_RO)) {
return -1;
}
/* Get the old info. search by dev/ino */
- data.dptr = make_tdb_data(cdb->flags, st, did, name, len);
+ data.dptr = make_tdb_data(cdb->cnid_db_flags, st, did, name, len);
data.dsize = CNID_HEADER_LEN + len + 1;
key.dptr = data.dptr +CNID_DEVINO_OFS;
key.dsize = CNID_DEVINO_LEN;
}
/* search by did/name */
- data.dptr = make_tdb_data(cdb->flags, st, did, name, len);
+ data.dptr = make_tdb_data(cdb->cnid_db_flags, st, did, name, len);
data.dsize = CNID_HEADER_LEN + len + 1;
key.dptr = (unsigned char *)data.dptr +CNID_DID_OFS;
key.dsize = data.dsize - CNID_DID_OFS;
/* Make a new entry. */
- data.dptr = make_tdb_data(cdb->flags, st, did, name, len);
+ data.dptr = make_tdb_data(cdb->cnid_db_flags, st, did, name, len);
data.dsize = CNID_HEADER_LEN + len + 1;
memcpy(data.dptr, &id, sizeof(id));
subpath = prw;
strlcat(tmpbuf, user, MAXPATHLEN);
- if (getpwnam(user) == NULL) {
+ if ((pw = getpwnam(user)) == NULL) {
/* (5b) */
char *tuser;
if ((tuser = getuserbypath(tmpbuf)) != NULL) {
free(user);
user = strdup(tuser);
}
+ if ((pw = getpwnam(user)) == NULL)
+ EC_FAIL_LOG("unknown user: %s", user);
}
strlcpy(obj->username, user, MAXUSERLEN);
strlcat(tmpbuf, "/", MAXPATHLEN);
#ifdef REALPATH_TAKES_NULL
if ((resolved_path = realpath(path, NULL)) == NULL) {
- LOG(log_error, logtype_afpd, "realpath() cannot resolve path \"%s\"", path);
+ LOG(log_debug, logtype_afpd, "realpath() cannot resolve path \"%s\"", path);
return NULL;
}
return resolved_path;
return NULL;
if (realpath(path, resolved_path) == NULL) {
free(resolved_path);
- LOG(log_error, logtype_afpd, "realpath() cannot resolve path \"%s\"", path);
+ LOG(log_debug, logtype_afpd, "realpath() cannot resolve path \"%s\"", path);
return NULL;
}
/* Safe some memory */
dbd \- CNID database maintenance
.SH "SYNOPSIS"
.HP \w'\fBdbd\fR\fB\fR\ 'u
-\fBdbd\fR\fB\fR [\-fsv] \fIvolumepath\fR
+\fBdbd\fR\fB\fR [\-cfFstuvV] \fIvolumepath\fR
.SH "DESCRIPTION"
.PP
\fBdbd\fR
show statistics while running
.RE
.PP
+\-u
+.RS 4
+username for use with AFP volumes using user variable $u
+.RE
+.PP
\-v
.RS 4
verbose
indicates that a parameter can be specified in a volume specific section\&.
.SH "VARIABLE SUBSTITUTIONS"
.PP
-You can use variables in volume names\&. The use of variables in paths is not supported for now\&.
+You can use variables in volume names\&. The use of variables in paths is limited to $u\&.
.sp
.RS 4
.ie n \{\