BerkeleyDB cursors API requires db >= 4.6.
Push NEWS for 2.1.
+
+
+REMEMBER TO UPDATE the Changes in 2.0.x section !!!
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Changes in 2.1
+==============
+* UPD: cdb/dbd CNID backend requires BerkeleyDB >= 4.6
+* FIX: rewritten logger
+* NEW: cnid_metad: options -l and -f to configure logging
+* NEW: CNID database maintanance utility dbd
+* NEW: support BerkeleyDB upgrade. Starting with the next release
+ after 2.1 in case of BerkeleyDB library updates, Netatalk
+ will be able to upgrade the CNID databases.
+* NEW: AppleDouble compatible UNIX files utility suite `ad ...`.
+ With 2.1 only `ad ls`.
+* NEW: afpd: ACL support with ZFS
+* NEW: afpd: ExtendedAttributes support with ZFS
+
+Changes in 2.0.x
+================
+
+...........
+
+
Changes in 2.0.0
================
/*
- $Id: cmd_dbd.c,v 1.5 2009-05-28 11:28:49 franklahm Exp $
+ $Id: cmd_dbd.c,v 1.6 2009-09-03 08:35:15 franklahm Exp $
Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
static void usage ()
{
- printf("Usage: dbd [-e|-v|-x] -d [-i] | -s | -r [-f] <path to netatalk volume>\n"
+ printf("Usage: dbd [-e|-v|-x|-u] -d [-i] | -s | -r [-f] <path to netatalk volume>\n"
"dbd can dump, scan, reindex and rebuild Netatalk dbd CNID databases.\n"
"dbd must be run with appropiate permissions i.e. as root.\n\n"
"Main commands are:\n"
" 7. Check for orphaned CNIDs in database (requires -e)\n"
" Option: -f wipe database and rebuild from IDs stored in AppleDouble files,\n"
" only available for volumes with 'cachecnid' option. Implies -e.\n"
+ " -u Prepare upgrade:\n"
+ " Before installing an upgraded version of Netatalk that is linked against\n"
+ " a newer BerkeleyDB lib, run `dbd -u ...` from the OLD Netatalk pior to\n"
+ " upgrading on all volumes. This removes the BerkleyDB environment.\n"
+ " On exit cnid_dbd does this automatically, so normally calling dbd -u should not be necessary.\n\n"
"General options:\n"
" -e only work on inactive volumes and lock them (exclusive)\n"
" -x rebuild indexes (just for completeness, mostly useless!)\n"
int main(int argc, char **argv)
{
- int c, lockfd;
- int dump=0, scan=0, rebuild=0, rebuildindexes=0, dumpindexes=0, force=0;
+ int c, lockfd, ret = -1;
+ int dump=0, scan=0, rebuild=0, prep_upgrade=0, rebuildindexes=0, dumpindexes=0, force=0;
dbd_flags_t flags = 0;
char *volpath;
struct volinfo volinfo;
exit(EXIT_FAILURE);
}
- while ((c = getopt(argc, argv, ":dsrvxife")) != -1) {
+ while ((c = getopt(argc, argv, ":dsruvxife")) != -1) {
switch(c) {
case 'd':
dump = 1;
case 'r':
rebuild = 1;
break;
+ case 'u':
+ prep_upgrade = 1;
+ break;
case 'v':
verbose = 1;
break;
}
}
- if ((dump + scan + rebuild) != 1) {
+ if ((dump + scan + rebuild + prep_upgrade) != 1) {
usage();
exit(EXIT_FAILURE);
}
*/
lockfd = get_lock(dbpath);
+ /* Prepare upgrade ? */
+ if (prep_upgrade) {
+ if (dbif_prep_upgrade(dbpath))
+ goto exit_failure;
+ goto exit_success;
+ }
+
/* Check if -f is requested and wipe db if yes */
- if ((flags & DBD_FLAGS_FORCE) && (volinfo.v_flags & AFPVOL_CACHE)) {
+ if ((flags & DBD_FLAGS_FORCE) && rebuild && (volinfo.v_flags & AFPVOL_CACHE)) {
char cmd[8 + MAXPATHLEN];
snprintf(cmd, 8 + MAXPATHLEN, "rm -f %s/*", dbpath);
dbd_log( LOGDEBUG, "Removing old database of volume: '%s'", volpath);
Lets start with the BerkeleyDB stuff
*/
if ((dbd = dbif_init(dbpath, "cnid2.db")) == NULL)
- exit(EXIT_FAILURE);
+ goto exit_failure;
if (dbif_env_open(dbd, &db_param, exclusive ? (DBOPTIONS | DB_RECOVER) : DBOPTIONS) < 0) {
dbd_log( LOGSTD, "error opening database!");
- exit(EXIT_FAILURE);
+ goto exit_failure;
}
if (exclusive)
if (dbif_open(dbd, &db_param, rebuildindexes) < 0) {
dbif_close(dbd);
- exit(EXIT_FAILURE);
+ goto exit_failure;
}
if (dbd_stamp(dbd) < 0) {
dbif_close(dbd);
- exit(EXIT_FAILURE);
+ goto exit_failure;
}
if (dump) {
if (dbif_close(dbd) < 0) {
dbd_log( LOGSTD, "Error closing database");
- exit(EXIT_FAILURE);
+ goto exit_failure;
}
- free_lock(lockfd);
+exit_success:
+ ret = 0;
+exit_failure:
+ free_lock(lockfd);
+
if ((fchdir(cdir)) < 0)
dbd_log(LOGSTD, "fchdir: %s", strerror(errno));
- return 0;
+ if (ret == 0)
+ exit(EXIT_SUCCESS);
+ else
+ exit(EXIT_FAILURE);
}
/*
- * $Id: dbif.c,v 1.12 2009-05-22 20:48:44 franklahm Exp $
+ * $Id: dbif.c,v 1.13 2009-09-03 08:35:15 franklahm Exp $
*
* Copyright (C) Joerg Lenneis 2003
* Copyright (C) Frank Lahm 2009
/* --------------- */
int dbif_open(DBD *dbd, struct db_param *dbp _U_, int reindex)
{
- int ret;
- int i;
+ int ret, i, cwd;
u_int32_t count;
+ struct stat st;
+ DB *upgrade_db;
+
+ /* Try to upgrade if it's a normal on-disk database */
+ if (dbd->db_envhome) {
+ /* Remember cwd */
+ if ((cwd = open(".", O_RDONLY)) < 0) {
+ LOG(log_error, logtype_cnid, "error opening cwd: %s", strerror(errno));
+ return -1;
+ }
+
+ /* chdir to db_envhome. makes it easier checking for old db files and creating db_errlog file */
+ if ((chdir(dbd->db_envhome)) != 0) {
+ LOG(log_error, logtype_cnid, "error chdiring to db_env '%s': %s", dbd->db_envhome, strerror(errno));
+ return -1;
+ }
+
+ if ((stat(dbd->db_filename, &st)) == 0) {
+ LOG(log_debug, logtype_cnid, "See if we can upgrade the CNID database");
+ if ((ret = db_create(&upgrade_db, dbd->db_env, 0))) {
+ LOG(log_error, logtype_cnid, "error creating handle for database: %s", db_strerror(ret));
+ return -1;
+ }
+ if ((ret = upgrade_db->upgrade(upgrade_db, dbd->db_filename, 0))) {
+ LOG(log_error, logtype_cnid, "error upgarding database: %s", db_strerror(ret));
+ return -1;
+ }
+ if ((ret = upgrade_db->close(upgrade_db, 0))) {
+ LOG(log_error, logtype_cnid, "error closing database: %s", db_strerror(ret));
+ return -1;
+ }
+ if ((ret = dbd->db_env->txn_checkpoint(dbd->db_env, 0, 0, DB_FORCE))) {
+ LOG(log_error, logtype_cnid, "error forcing checkpoint: %s", db_strerror(ret));
+ return -1;
+ }
+ }
+
+ if ((fchdir(cwd)) != 0) {
+ LOG(log_error, logtype_cnid, "error chdiring back: %s", strerror(errno));
+ return -1;
+ }
+ }
+ /* Now open databases ... */
for (i = 0; i != DBIF_DB_CNT; i++) {
if ((ret = db_create(&dbd->db_table[i].db, dbd->db_env, 0))) {
LOG(log_error, logtype_cnid, "error creating handle for database %s: %s",
return 0;
}
+/*
+ In order to support silent database upgrades:
+ destroy env at cnid_dbd shutdown.
+ */
+int dbif_prep_upgrade(const char *path)
+{
+ int cwd, ret;
+ DBD *dbd;
+
+ LOG(log_debug, logtype_cnid, "Reopening BerkeleyDB environment");
+
+ if (NULL == (dbd = dbif_init(path, "cnid2.db")))
+ return -1;
+
+ /* Remember cwd */
+ if ((cwd = open(".", O_RDONLY)) < 0) {
+ LOG(log_error, logtype_cnid, "error opening cwd: %s", strerror(errno));
+ return -1;
+ }
+
+ /* chdir to db_envhome. makes it easier checking for old db files and creating db_errlog file */
+ if ((chdir(dbd->db_envhome)) != 0) {
+ LOG(log_error, logtype_cnid, "error chdiring to db_env '%s': %s", dbd->db_envhome, strerror(errno));
+ return -1;
+ }
+
+ if ((dbd->db_errlog = fopen(DB_ERRLOGFILE, "a")) == NULL)
+ LOG(log_warning, logtype_cnid, "error creating/opening DB errlogfile: %s", strerror(errno));
+
+ if ((fchdir(cwd)) != 0) {
+ LOG(log_error, logtype_cnid, "error chdiring back: %s", strerror(errno));
+ return -1;
+ }
+
+ /* Get db_env handle */
+ if ((ret = db_env_create(&dbd->db_env, 0))) {
+ LOG(log_error, logtype_cnid, "error creating DB environment: %s", db_strerror(ret));
+ dbd->db_env = NULL;
+ return -1;
+ }
+
+ /* Set logfile */
+ if (dbd->db_errlog != NULL) {
+ dbd->db_env->set_errfile(dbd->db_env, dbd->db_errlog);
+ dbd->db_env->set_msgfile(dbd->db_env, dbd->db_errlog);
+ dbd->db_env->set_verbose(dbd->db_env, DB_VERB_RECOVERY, 1);
+ }
+
+ /* Open environment with recovery */
+ if ((ret = dbd->db_env->open(dbd->db_env,
+ dbd->db_envhome,
+ DB_CREATE | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_LOCK | DB_INIT_TXN | DB_RECOVER | DB_PRIVATE,
+ 0))) {
+ LOG(log_error, logtype_cnid, "error opening DB environment: %s",
+ db_strerror(ret));
+ dbd->db_env->close(dbd->db_env, 0);
+ dbd->db_env = NULL;
+ return -1;
+ }
+
+ if (dbd->db_errlog != NULL)
+ fflush(dbd->db_errlog);
+
+ /* Remove logfiles */
+ if ((ret = dbd->db_env->log_archive(dbd->db_env, NULL, DB_ARCH_REMOVE))) {
+ LOG(log_error, logtype_cnid, "error removing transaction logfiles: %s", db_strerror(ret));
+ return -1;
+ }
+
+ if ((ret = dbd->db_env->close(dbd->db_env, 0))) {
+ LOG(log_error, logtype_cnid, "error closing DB environment after recovery: %s", db_strerror(ret));
+ dbd->db_env = NULL;
+ return -1;
+ }
+
+ LOG(log_debug, logtype_cnid, "BerkeleyDB environment recovery done.");
+
+ /* Get a new db_env handle and then remove environment */
+ if ((ret = db_env_create(&dbd->db_env, 0))) {
+ LOG(log_error, logtype_cnid, "error acquiring db_end handle: %s", db_strerror(ret));
+ dbd->db_env = NULL;
+ return -1;
+ }
+ if ((ret = dbd->db_env->remove(dbd->db_env, dbd->db_envhome, 0))) {
+ LOG(log_error, logtype_cnid, "error removing BerkeleyDB environment: %s", db_strerror(ret));
+ return -1;
+ }
+
+ LOG(log_debug, logtype_cnid, "Removed BerkeleyDB environment.");
+
+ return 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
/*
- $Id: dbif.h,v 1.7 2009-05-22 20:48:44 franklahm Exp $
+ $Id: dbif.h,v 1.8 2009-09-03 08:35:15 franklahm Exp $
Copyright (C) Joerg Lenneis 2003
Copyright (C) Frank Lahm 2009
dbd = dbif_init("cnid2.db");
Pass NULL to create an in-memory db.
Note: the DBD type is NOT from BerkeleyDB ! We've defined it.
- 3. Optional:
- Call dbif_env_open to open an dbd environment, chdir to it beforehand
+ 3. Call dbif_env_open to open an dbd environment if you called dbif_init
+ with a filename.
4. Call dbif_open to finally open the CNID database itself
Querying the CNID database
Closing
-------
Call dbif_close.
+
+ Silent Upgrade Support
+ ----------------------
+
+ On cnid_dbd shutdown we reopen the environment with recovery, close and then
+ remove it. This enables an upgraded netatalk installation possibly linked against
+ a newer bdb lib to succesfully open/create an environment and then silently
+ upgrade the database itself. How nice!
*/
#ifndef CNID_DBD_DBIF_H
extern int dbif_env_open(DBD *dbd, struct db_param *dbp, uint32_t dbenv_oflags);
extern int dbif_open(DBD *dbd, struct db_param *dbp, int reindex);
extern int dbif_close(DBD *dbd);
+extern int dbif_prep_upgrade(const char *path);
extern int dbif_get(DBD *, const int, DBT *, DBT *, u_int32_t);
extern int dbif_pget(DBD *, const int, DBT *, DBT *, DBT *, u_int32_t);
/*
- * $Id: main.c,v 1.9 2009-07-12 09:21:34 franklahm Exp $
+ * $Id: main.c,v 1.10 2009-09-03 08:35:15 franklahm Exp $
*
* Copyright (C) Joerg Lenneis 2003
* Copyright (c) Frank Lahm 2009
if (dbif_close(dbd) < 0)
err++;
+ if (dbif_prep_upgrade(dir) < 0)
+ err++;
+
free_lock(lockfd);
if (err)
-dnl $Id: db3-check.m4,v 1.19 2009-07-03 08:15:19 franklahm Exp $
+dnl $Id: db3-check.m4,v 1.20 2009-09-03 08:35:15 franklahm Exp $
dnl Autoconf macros to check for the Berkeley DB library
dnl -- check header for minimum version and return version in
bdb_search_dirs="/usr/local /usr"
search_subdirs="/ /db4.7 /db47 /db4.6 /db46 /db4.5 /db45 /db4.4 /db44 /db4"
- dnl required BDB version: 4.4, because of DB_AUTO_COMMIT
+ dnl required BDB version: 4.6, because of cursor API change
DB_MAJOR_REQ=4
- DB_MINOR_REQ=4
+ DB_MINOR_REQ=6
DB_PATCH_REQ=0
dnl make sure atalk_libname is defined beforehand