Projects
Kolab:3.4
cyrus-imapd
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 118
View file
cyrus-imapd.spec
Changed
@@ -69,6 +69,7 @@ Patch0001: cyrus-imapd-2.5-ctl_mboxlist-mbtype.patch Patch0002: cyrus-imapd-2.5-default-skiplist.patch +Patch0003: cyrus-imapd-2.5-revert-safe-skiplist.patch BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) @@ -261,6 +262,7 @@ %patch0001 -p1 %patch0002 -p1 +%patch0003 -p1 %if 0%{?with_bdb} < 1 sed -i -e 's/,berkeley//g' cunit/db.testc
View file
cyrus-imapd-2.5-revert-safe-skiplist.patch
Added
@@ -0,0 +1,431 @@ +diff --git a/lib/cyrusdb_skiplist.c b/lib/cyrusdb_skiplist.c +index 18d3ca3..fc540e0 100644 +--- a/lib/cyrusdb_skiplist.c ++++ b/lib/cyrusdb_skiplist.c +@@ -399,7 +399,7 @@ static unsigned RECSIZE_safe(struct dbengine *db, const char *ptr) + case ADD: + level = LEVEL_safe(db, ptr); + if (!level) { +- syslog(LOG_ERR, "IOERROR: skiplist RECSIZE not safe %s, offset %u", ++ syslog(LOG_ERR, "IOERROR: skiplist2 RECSIZE_safe not safe %s, offset %u", + db->fname, (unsigned)(ptr - db->map_base)); + return 0; + } +@@ -413,20 +413,50 @@ static unsigned RECSIZE_safe(struct dbengine *db, const char *ptr) + break; + + case DELETE: +- if (!is_safe(db, ptr+8)) { +- syslog(LOG_ERR, "IOERROR: skiplist RECSIZE not safe %s, offset %u", +- db->fname, (unsigned)(ptr - db->map_base)); +- return 0; +- } + ret += 8; + break; + + case COMMIT: +- if (!is_safe(db, ptr+4)) { +- syslog(LOG_ERR, "IOERROR: skiplist RECSIZE not safe %s, offset %u", +- db->fname, (unsigned)(ptr - db->map_base)); +- return 0; +- } ++ ret += 4; ++ break; ++ } ++ ++ return ret; ++} ++ ++/* how many levels does this record have? */ ++static unsigned LEVEL(const char *ptr) ++{ ++ const uint32_t *p, *q; ++ ++ assert(TYPE(ptr) == DUMMY || TYPE(ptr) == INORDER || TYPE(ptr) == ADD); ++ p = q = (uint32_t *) FIRSTPTR(ptr); ++ while (*p != (uint32_t)-1) p++; ++ return (p - q); ++} ++ ++/* how big is this record? */ ++static unsigned RECSIZE(const char *ptr) ++{ ++ int ret = 0; ++ switch (TYPE(ptr)) { ++ case DUMMY: ++ case INORDER: ++ case ADD: ++ ret += 4; /* tag */ ++ ret += 4; /* keylen */ ++ ret += ROUNDUP(KEYLEN(ptr)); /* key */ ++ ret += 4; /* datalen */ ++ ret += ROUNDUP(DATALEN(ptr)); /* data */ ++ ret += 4 * LEVEL(ptr); /* pointers */ ++ ret += 4; /* padding */ ++ break; ++ ++ case DELETE: ++ ret += 8; ++ break; ++ ++ case COMMIT: + ret += 4; + break; + } +@@ -494,12 +524,7 @@ static int newtxn(struct dbengine *db, struct txn **tidptr) + } + + +-static unsigned PADDING_safe(struct dbengine *db, const char *ptr) +-{ +- unsigned size = RECSIZE_safe(db, ptr); +- if (!size) return 0; +- return ntohl(*((uint32_t *)((ptr) + size - 4))); +-} ++#define PADDING(ptr) (ntohl(*((uint32_t *)((ptr) + RECSIZE(ptr) - 4)))) + + /* given an open, mapped db, read in the header information */ + static int read_header(struct dbengine *db) +@@ -570,9 +595,9 @@ static int read_header(struct dbengine *db) + db->fname); + r = CYRUSDB_IOERROR; + } +- if (!r && LEVEL_safe(db, dptr) != db->maxlevel) { ++ if (!r && LEVEL(dptr) != db->maxlevel) { + syslog(LOG_ERR, "DBERROR: %s: DUMMY level(%d) != db->maxlevel(%d)", +- db->fname, LEVEL_safe(db, dptr), db->maxlevel); ++ db->fname, LEVEL(dptr), db->maxlevel); + r = CYRUSDB_IOERROR; + } + +@@ -1281,7 +1306,7 @@ static int mystore(struct dbengine *db, + return CYRUSDB_EXISTS; + } else { + /* replace with an equal height node */ +- lvl = LEVEL_safe(db, ptr); ++ lvl = LEVEL(ptr); + + /* log a removal */ + WRITEV_ADD_TO_IOVEC(iov, num_iov, (char *) &delrectype, 4); +@@ -1575,8 +1600,8 @@ static int myabort(struct dbengine *db, struct txn *tid) + + /* find the last log entry */ + for (offset = tid->logstart, ptr = db->map_base + offset; +- offset + RECSIZE_safe(db, ptr) != (uint32_t) tid->logend; +- offset += RECSIZE_safe(db, ptr), ptr = db->map_base + offset) ; ++ offset + RECSIZE(ptr) != (uint32_t) tid->logend; ++ offset += RECSIZE(ptr), ptr = db->map_base + offset) ; + + offset = ptr - db->map_base; + +@@ -1613,7 +1638,7 @@ static int myabort(struct dbengine *db, struct txn *tid) + /* re-add this record. it can't exist right now. */ + netnewoffset = *((uint32_t *)(ptr + 4)); + q = db->map_base + ntohl(netnewoffset); +- lvl = LEVEL_safe(db, q); ++ lvl = LEVEL(q); + (void) find_node(db, KEY(q), KEYLEN(q), updateoffsets); + for (i = 0; i < lvl; i++) { + /* the current pointers FROM this node are correct, +@@ -1628,7 +1653,7 @@ static int myabort(struct dbengine *db, struct txn *tid) + } + + /* remove looking at this */ +- tid->logend -= RECSIZE_safe(db, ptr); ++ tid->logend -= RECSIZE(ptr); + } + + /* truncate the file to remove log entries */ +@@ -1742,13 +1767,13 @@ static int mycheckpoint(struct dbengine *db) + uint32_t netnewoffset; + + ptr = db->map_base + offset; +- lvl = LEVEL_safe(db, ptr); ++ lvl = LEVEL(ptr); + db->listsize++; + + num_iov = 0; + WRITEV_ADD_TO_IOVEC(iov, num_iov, (char *) &iorectype, 4); + /* copy all but the rectype from the record */ +- WRITEV_ADD_TO_IOVEC(iov, num_iov, (char *) ptr + 4, RECSIZE_safe(db, ptr) - 4); ++ WRITEV_ADD_TO_IOVEC(iov, num_iov, (char *) ptr + 4, RECSIZE(ptr) - 4); + + newoffset = lseek(db->fd, 0, SEEK_END); + netnewoffset = htonl(newoffset); +@@ -1915,9 +1940,9 @@ static int dump(struct dbengine *db, int detail __attribute__((unused))) + case INORDER: + case ADD: + printf("kl=%d dl=%d lvl=%d\n", +- KEYLEN(ptr), DATALEN(ptr), LEVEL_safe(db, ptr)); ++ KEYLEN(ptr), DATALEN(ptr), LEVEL(ptr)); + printf("\t"); +- for (i = 0; i < LEVEL_safe(db, ptr); i++) { ++ for (i = 0; i < LEVEL(ptr); i++) { + printf("%04X ", FORWARD(ptr, i)); + } + printf("\n"); +@@ -1932,7 +1957,7 @@ static int dump(struct dbengine *db, int detail __attribute__((unused))) + break; + } + +- ptr += RECSIZE_safe(db, ptr); ++ ptr += RECSIZE(ptr); + } + + unlock(db); +@@ -1961,7 +1986,7 @@ static int myconsistent(struct dbengine *db, struct txn *tid, int locked) + + ptr = db->map_base + offset; + +- for (i = 0; i < LEVEL_safe(db, ptr); i++) { ++ for (i = 0; i < LEVEL(ptr); i++) { + offset = FORWARD(ptr, i); + + if (offset > db->map_size) { +@@ -2005,11 +2030,9 @@ static int myconsistent(struct dbengine *db, struct txn *tid, int locked) + static int recovery(struct dbengine *db, int flags) + { + const char *ptr, *keyptr; +- unsigned filesize = db->map_size; + unsigned updateoffsetsSKIPLIST_MAXLEVEL+1; + uint32_t offset, offsetnet, myoff = 0; +- int r = 0; +- int need_checkpoint = libcyrus_config_getswitch(CYRUSOPT_SKIPLIST_ALWAYS_CHECKPOINT); ++ int r = 0, need_checkpoint = 0; + time_t start = time(NULL); + unsigned i; + +@@ -2063,11 +2086,11 @@ static int recovery(struct dbengine *db, int flags) + } + + /* pointers for db->maxlevel */ +- if (!r && LEVEL_safe(db, ptr) != db->maxlevel) { ++ if (!r && LEVEL(ptr) != db->maxlevel) { + r = CYRUSDB_IOERROR; + syslog(LOG_ERR, + "DBERROR: skiplist recovery %s: dummy node level: %d != %d", +- db->fname, LEVEL_safe(db, ptr), db->maxlevel); ++ db->fname, LEVEL(ptr), db->maxlevel); + } + + for (i = 0; i < db->maxlevel; i++) { +@@ -2078,7 +2101,7 @@ static int recovery(struct dbengine *db, int flags) + + /* reset the data that was written INORDER by the last checkpoint */ + offset = DUMMY_OFFSET(db) + DUMMY_SIZE(db); +- while (!r && (offset < filesize) ++ while (!r && (offset < db->map_size) + && TYPE(db->map_base + offset) == INORDER) { + ptr = db->map_base + offset; + offsetnet = htonl(offset); +@@ -2088,9 +2111,9 @@ static int recovery(struct dbengine *db, int flags) + /* xxx check \0 fill on key */ + + /* xxx check \0 fill on data */ +- ++ + /* update previous pointers, record these for updating */ +- for (i = 0; !r && i < LEVEL_safe(db, ptr); i++) { ++ for (i = 0; !r && i < LEVEL(ptr); i++) { + r = lseek(db->fd, updateoffsetsi, SEEK_SET); + if (r < 0) { + syslog(LOG_ERR, "DBERROR: lseek %s: %m", db->fname); +@@ -2113,23 +2136,15 @@ static int recovery(struct dbengine *db, int flags) + updateoffsetsi = offset + (PTR(ptr, i) - ptr); + } + +- if (!r) { +- unsigned size = RECSIZE_safe(db, ptr); +- if (!size) { +- syslog(LOG_ERR, "skiplist recovery %s: damaged record at %u, truncating here", +- db->fname, offset); +- filesize = offset; +- break; +- } +- +- if (PADDING_safe(db, ptr) != (uint32_t) -1) { +- syslog(LOG_ERR, "DBERROR: %s: offset %04X padding not -1", +- db->fname, offset); +- filesize = offset; +- break; +- } ++ /* check padding */ ++ if (!r && PADDING(ptr) != (uint32_t) -1) { ++ syslog(LOG_ERR, "DBERROR: %s: offset %04X padding not -1", ++ db->fname, offset); ++ r = CYRUSDB_IOERROR; ++ } + +- offset += size; ++ if (!r) { ++ offset += RECSIZE(ptr); + } + } + +@@ -2164,7 +2179,7 @@ static int recovery(struct dbengine *db, int flags) + } + + /* replay the log */ +- while (!r && offset < filesize) { ++ while (!r && offset < db->map_size) { + const char *p, *q; + + /* refresh map, so we see the writes we've just done */ +@@ -2176,7 +2191,7 @@ static int recovery(struct dbengine *db, int flags) + /* bugs in recovery truncates could have left some bogus zeros here */ + if (TYPE(ptr) == 0) { + int orig = offset; +- while (TYPE(ptr) == 0 && offset < filesize) { ++ while (TYPE(ptr) == 0 && offset < db->map_size) { + offset += 4; + ptr = db->map_base + offset; + } +@@ -2189,7 +2204,7 @@ static int recovery(struct dbengine *db, int flags) + + /* if this is a commit, we've processed everything in this txn */ + if (TYPE(ptr) == COMMIT) { +- offset += RECSIZE_safe(db, ptr); ++ offset += RECSIZE(ptr); + continue; + } + +@@ -2203,7 +2218,7 @@ static int recovery(struct dbengine *db, int flags) + } + + /* look ahead for a commit */ +- q = db->map_base + filesize; ++ q = db->map_base + db->map_size; + p = ptr; + for (;;) { + if (RECSIZE_safe(db, p) <= 0) { +@@ -2215,7 +2230,7 @@ static int recovery(struct dbengine *db, int flags) + p = q; + break; + } +- p += RECSIZE_safe(db, p); ++ p += RECSIZE(p); + if (p >= q) break; + if (TYPE(p) == COMMIT) break; + } +@@ -2224,7 +2239,16 @@ static int recovery(struct dbengine *db, int flags) + "skiplist recovery %s: found partial txn, not replaying", + db->fname); + +- filesize = offset; ++ /* no commit, we should truncate */ ++ if (ftruncate(db->fd, offset) < 0) { ++ syslog(LOG_ERR, ++ "DBERROR: skiplist recovery %s: ftruncate: %m", ++ db->fname); ++ r = CYRUSDB_IOERROR; ++ } ++ ++ /* set the map size back as well */ ++ db->map_size = offset; + + break; + } +@@ -2290,7 +2314,7 @@ static int recovery(struct dbengine *db, int flags) + } + offsetnet = htonl(offset); + +- lvl = LEVEL_safe(db, ptr); ++ lvl = LEVEL(ptr); + if (lvl > SKIPLIST_MAXLEVEL) { + syslog(LOG_ERR, + "DBERROR: skiplist recovery %s: node claims level %d (greater than max %d)", +@@ -2299,15 +2323,15 @@ static int recovery(struct dbengine *db, int flags) + } else { + /* NOTE - in the bogus case where a record with the same key already + * exists, there are three possible cases: +- * lvl == LEVEL_safe(db, keyptr) ++ * lvl == LEVEL(keyptr) + * * trivial: all to me, all mine to keyptr's FORWARD +- * lvl > LEVEL_safe(db, keyptr) - ++ * lvl > LEVEL(keyptr) - + * * all updateoffsets values should point to me +- * * up until LEVEL_safe(db, keyptr) set to keyptr's next values ++ * * up until LEVEL(keyptr) set to keyptr's next values + * (updateoffsetsi should be keyptr in these cases) + * then point all my higher pointers are updateoffsetsi's + * FORWARD instead. +- * lvl < LEVEL_safe(db, keyptr) ++ * lvl < LEVEL(keyptr) + * * updateoffsets values up to lvl should point to me + * * all mine should point to keyptr's next values + * * from lvl up, all updateoffsetsi should point to +@@ -2319,7 +2343,7 @@ static int recovery(struct dbengine *db, int flags) + */ + for (i = 0; i < lvl; i++) { + /* set our next pointers */ +- if (keyptr && i < LEVEL_safe(db, keyptr)) { ++ if (keyptr && i < LEVEL(keyptr)) { + /* need to replace the matching record key */ + newoffsetsi = + htonl(FORWARD(keyptr, i)); +@@ -2338,9 +2362,9 @@ static int recovery(struct dbengine *db, int flags) + lseek(db->fd, FIRSTPTR(ptr) - db->map_base, SEEK_SET); + retry_write(db->fd, (char *) newoffsets, 4 * lvl); + +- if (keyptr && lvl < LEVEL_safe(db, keyptr)) { ++ if (keyptr && lvl < LEVEL(keyptr)) { + uint32_t newoffsetnet; +- for (i = lvl; i < LEVEL_safe(db, keyptr); i++) { ++ for (i = lvl; i < LEVEL(keyptr); i++) { + newoffsetnet = htonl(FORWARD(keyptr, i)); + /* replace 'updateoffsets' to point onwards */ + lseek(db->fd, +@@ -2356,22 +2380,21 @@ static int recovery(struct dbengine *db, int flags) + } + + /* move to next record */ +- unsigned size = RECSIZE_safe(db, ptr); +- if (!size) break; +- offset += size; ++ offset += RECSIZE(ptr); + } + +- /* didn't read the exact end? We should truncate */ +- if (offset < db->map_size) { +- if (ftruncate(db->fd, offset) < 0) { +- syslog(LOG_ERR, +- "DBERROR: skiplist recovery %s: ftruncate: %m", +- db->fname); +- r = CYRUSDB_IOERROR; +- } ++ if (libcyrus_config_getswitch(CYRUSOPT_SKIPLIST_ALWAYS_CHECKPOINT)) { ++ /* refresh map, so we see the writes we've just done */ ++ map_refresh(db->fd, 0, &db->map_base, &db->map_len, db->map_size, ++ db->fname, 0); + +- /* set the map size back as well */ +- db->map_size = offset; ++ r = mycheckpoint(db); ++ ++ if (r || !(flags & RECOVERY_CALLER_LOCKED)) { ++ unlock(db); ++ } ++ ++ return r; + } + + /* fsync the recovered database */ +@@ -2404,16 +2427,13 @@ static int recovery(struct dbengine *db, int flags) + } + + if (!r && need_checkpoint) { +- /* refresh map, so we see the writes we've just done */ +- map_refresh(db->fd, 0, &db->map_base, &db->map_len, db->map_size, +- db->fname, 0); + r = mycheckpoint(db); + } + +- if (r || !(flags & RECOVERY_CALLER_LOCKED)) { ++ if(r || !(flags & RECOVERY_CALLER_LOCKED)) { + unlock(db); + } +- ++ + return r; + } +
View file
cyrus-imapd.cvt_cyrusdb_all
Changed
@@ -1,428 +1,95 @@ #!/bin/bash +# Simplified version of Simon Matter's cvt_cyrusdb_all. -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + -f "/etc/sysconfig/cyrus-imapd" && \ + . /etc/sysconfig/cyrus-imapd -# This script converts all db files of a cyrus installation from their -# existing format to the format required by the current installation. -# The format of current db files is determined using the 'file' command -# with a magic file added for skiplist db, the new format is read from -# a config file usually in /usr/share/cyrus-imapd/rpm/db.cfg, which is -# created while compiling. After converting, the db.cfg file is -# copied to a cache file usually at /var/lib/imap/rpm/db.cfg.cache to -# allow bypassing this converting script if both files are identical. -# While this is a bit less secure, it may be useful on big server where -# db converting is done automatically. -# -# This script can safely be run as root, it will reexec itself as user -# cyrus if needed. -# -# author: Simon Matter, Invoca Systems <simon.matter@invoca.ch> + -f "/etc/default/cyrus-imapd" && \ + . /etc/default/cyrus-imapd -# changelog -# v1.0.1, Oct 22 2002 Simon Matter <simon.matter@invoca.ch> -# - added two-step conversion method -# -# v1.0.2, Jan 10 2003 Simon Matter <simon.matter@invoca.ch> -# - fixed a bug where cvt_cyrusdb was called to convert empty or -# nonexistent files -# -# v1.0.3, Mar 14 2003 Simon Matter <simon.matter@invoca.ch> -# - fixed a problem with new versions of the file command -# -# v1.0.4 -# - added GPL license -# -# v1.0.5, May 02 2003 Simon Matter <simon.matter@invoca.ch> -# - modified exec path -# -# v1.0.6, Jul 18 2003 Simon Matter <simon.matter@invoca.ch> -# - changed db3 to berkeley -# - added new db backends for 2.2 -# -# v1.0.7, Jan 23 2004 Simon Matter <simon.matter@invoca.ch> -# - included some modifications from Luca Olivetti <luca@olivetti.cjb.net> -# - added masssievec functionality -# -# v1.0.8, Jan 28 2004 Simon Matter <simon.matter@invoca.ch> -# - convert sieve scripts to UTF-8 before calling masssievec -# -# v1.0.9, Jan 29 2004 Simon Matter <simon.matter@invoca.ch> -# - convert sieve scripts to UTF-8 only if sievec failed before -# -# v1.0.10, Feb 24 2004 Simon Matter <simon.matter@invoca.ch> -# - change su within init script to get input from -# /dev/null, this prevents hang when running in SELinux -# -# v1.0.11, Mar 02 2004 Simon Matter <simon.matter@invoca.ch> -# - fixed SELinux fix -# -# v1.0.12, Dec 16 2004 Simon Matter <simon.matter@invoca.ch> -# - use runuser instead of su if available -# -# v1.0.13, Jul 15 2005 Simon Matter <simon.matter@invoca.ch> -# - don't use flat in the two step conversion, use skiplist instead -# -# v1.0.14, Jul 18 2005 Simon Matter <simon.matter@invoca.ch> -# - replace the order of the magic files in the file call to make -# sure skiplist is detected correctly. -# -# v1.0.15, Aug 17 2005 Simon Matter <simon.matter@invoca.ch> -# - add functionality to export all berkeley db files to skiplist -# -# v1.1.0, Aug 18 2005 Simon Matter <simon.matter@invoca.ch> -# - fix export functionality, try to recover Berkeley databases -# as much as possible before any conversion. -# -# v1.1.1, Dec 05 2005 Simon Matter <simon.matter@invoca.ch> -# - run db_checkpoint in background with a timeout to prevent -# that cyrus-imapd doesn't start at all if it hangs. -# -# v1.1.2, Dec 06 2005 Simon Matter <simon.matter@invoca.ch> -# - make handling of db_checkpoint more robust -# -# v1.2.0, Jan 12 2006 Simon Matter <simon.matter@invoca.ch> -# - adopt for cyrus-imapd-2.3 -# -# v1.2.1, Jan 13 2006 Simon Matter <simon.matter@invoca.ch> -# - code cleanup -# -# v1.2.2, Nov 29 2007 Simon Matter <simon.matter@invoca.ch> -# - add ability to handle "@include" options in imapd.conf, patch -# provided by Tim Bannister -# -# v1.2.3, Feb 07 2008 Simon Matter <simon.matter@invoca.ch> -# - add ability to handle tabs in imapd.conf, patch provided -# by Franz Knipp -# - disable default values for some config options like sievedir -# -# v1.2.4, Apr 23 2008 Simon Matter <simon.matter@invoca.ch> -# - add support for statuscache.db -# -# v1.3.0, Sep 29 2008 Simon Matter <simon.matter@invoca.ch> -# - add multi-instance support -# -# v1.3.1, Oct 09 2008 Simon Matter <simon.matter@invoca.ch> -# - improve variable handling -# -# v1.3.2, May 26 2009 Simon Matter <simon.matter@invoca.ch> -# - add some sanity checks to multi-instance support -# -# v1.3.3, May 27 2009 Simon Matter <simon.matter@invoca.ch> -# - make some cosmetic changes -# -# v1.3.4, Dec 22 2009 Simon Matter <simon.matter@invoca.ch> -# - add support for user_deny.db -# -# v1.3.5, Mar 6 2014 Jeroen van Meeuwen <vanmeeuwen@kolabsys.com> -# - use default database configuration values if not specified in -# configuration - -VERSION=1.3.5 - - -f /etc/sysconfig/cyrus-imapd${INSTANCE} && \ - . /etc/sysconfig/cyrus-imapd${INSTANCE} - - "${QUICK}" == "1" && exit 0 - -PIDFILE=/var/run/cyrus-master${INSTANCE}.pid - -# instance config -CYRUSCONF=/etc/cyrus${INSTANCE}.conf -IMAPDCONF=/etc/imapd${INSTANCE}.conf - -# make sure what we have is a valid instance -# and that config files are present -if -n "${INSTANCE}" ; then - -L /etc/rc.d/init.d/${BASENAME} || exit 0 -fi - -f ${CYRUSCONF} || exit 0 - -f ${IMAPDCONF} || exit 0 - -if -f ${PIDFILE} ; then - read CYRUS_PID < ${PIDFILE} - if -n "${CYRUS_PID}" ; then - if ps -p ${CYRUS_PID} > /dev/null 2>&1; then - echo "ERROR: cyrus-master is running, unable to convert mailboxes!" - exit 1 - fi - fi -fi - -if ! -f ${IMAPDCONF} ; then - echo "ERROR: configuration file '${IMAPDCONF}' not found, exiting!" - exit 1 -fi - -# fallback to su if runuser not available -if -x /sbin/runuser ; then - RUNUSER=runuser +# Ensure this script is run as the cyrus user. +if -x "$(which runuser 2>/dev/null)" ; then + SWITCHUSER=runuser else - RUNUSER=su -fi - -# force cyrus user for security reasons -if ! $(whoami) = "cyrus" ; then - if ! -z "${INSTANCE}" ; then - exec $RUNUSER -s /bin/bash - cyrus -c "cd \$HOME < /dev/null ; INSTANCE=${INSTANCE} $0 $*" - else - exec $RUNUSER -s /bin/bash - cyrus -c "cd \$HOME < /dev/null ; INSTANCE=$0 $*" - fi + SWITCHUSER=su fi -# special function for migration -EXPORT=$1 - -# files get mode 0600 -umask 166 - -# show version info in log files -echo "cvt_cyrusdb_all version: $VERSION" - -# expand_config <path> -# handle "@include" sections from imapd style config file -expand_config() { - while read line; do - if printf "%s\n" "${line}" | grep -q '^@include:'; then - expand_config "$( printf "%s\n" "${line}" | cut -d : -f 2- | sed -e 's/^\t *//' )" - else - printf "%s\n" "${line}" - fi - done < $1 +#if ! $(whoami) = "cyrus" ; then +# exec $SWITCHUSER -s /bin/bash - cyrus -c "cd \$HOME < /dev/null ; INSTANCE=$0 $*" +#fi + +declare -a dbs +declare -a db_paths + +dbs${#dbs@}="annotation_db"; db_paths${#db_paths@}="annotations.db" +dbs${#dbs@}="duplicate_db"; db_paths${#db_paths@}="deliver.db" +dbs${#dbs@}="mboxkey_db"; db_paths${#db_paths@}="" +dbs${#dbs@}="mboxlist_db"; db_paths${#db_paths@}="mailboxes.db" +dbs${#dbs@}="ptscache_db"; db_paths${#db_paths@}="annotations.db" +dbs${#dbs@}="quota_db"; db_paths${#db_paths@}="quotas.db" +dbs${#dbs@}="seenstate_db"; db_paths${#db_paths@}="" +dbs${#dbs@}="statuscache_db"; db_paths${#db_paths@}="statuscache.db" +dbs${#dbs@}="subscription_db"; db_paths${#db_paths@}="" +dbs${#dbs@}="tls_sessions_db"; db_paths${#db_paths@}="tls_sessions.db" +dbs${#dbs@}="userdeny_db"; db_paths${#db_paths@}="user_deny.db" + +# /usr/lib/cyrus-imapd/cyr_dbtool /var/lib/imap/annotations.db skiplist consistent; echo $? +# Yes, consistent +# 0 + +function cvt_database() { + echo "would convert $1" } -# get_config <config> <default> -# extracts config option from config file -get_config() { - searchstr=$1 - if config="$(expand_config ${IMAPDCONF} | egrep "^${searchstr}:")"; then - CFGVAL="$(printf "%s\n" "$config" | cut -d : -f 2- | sed -e 's/^\t *//')" - else - if -z "$2" ; then - echo "ERROR: config option '$1' not found in ${IMAPDCONF}, exiting!" 1>&2 - return 1 - fi - CFGVAL="$2" - fi - echo "get_config ${1}: $CFGVAL" 1>&2 - echo "$CFGVAL" +function get_config() { + echo $(/usr/lib/cyrus-imapd/cyr_info conf | grep -E "^$1:\s+" | sed -r -e 's/a-z0-9_-+\:(.*)/\1/g') } -# where to find files and directories -data_dir=/var/lib/imap/rpm -lib_dir=/usr/lib/cyrus-imapd -system_magic=$(file --version | awk '/magic file/ {print $4}') -cyrus_magic=${data_dir}/magic -cvt_cyrusdb=${lib_dir}/cvt_cyrusdb -sievec=${lib_dir}/sievec -masssievec=${lib_dir}/masssievec -imap_prefix=$(get_config configdirectory) || exit 1 -sieve_dir=$(get_config sievedir) || exit 1 -db_cfg=${data_dir}/db.cfg -db_current=${imap_prefix}/rpm/db.cfg.current -db_cache=${imap_prefix}/rpm/db.cfg.cache - -# source default db backend config -. $db_cfg - -# get configured db backend config -annotation_db=$(get_config annotation_db $annotation_db) || annotation_db="twoskip" -duplicate_db=$(get_config duplicate_db $duplicate_db) || duplicate_db="twoskip" -mboxkey_db=$(get_config mboxkey_db $mboxkey_db) || mboxkey_db="twoskip" -mboxlist_db=$(get_config mboxlist_db $mboxlist_db) || mboxlist_db="twoskip" -ptscache_db=$(get_config ptscache_db $ptscache_db) || ptscache_db="twoskip" -quota_db=$(get_config quota_db $quota_db) || quota_db="twoskip" -seenstate_db=$(get_config seenstate_db $seenstate_db) || seenstate_db="twoskip" -statuscache_db=$(get_config statuscache_db $statuscache_db) || statuscache_db="twoskip" -subscription_db=$(get_config subscription_db $subscription_db) || subscription_db="twoskip" -tls_sessions_db=$(get_config tls_sessions_db $tls_sessions_db) || tls_sessions_db="twoskip" -userdeny_db=$(get_config userdeny_db $userdeny_db) || userdeny_db="flat" -zoneinfo_db=$(get_config zoneinfo_db $zoneinfo_db) || zoneinfo_db="twoskip" - -# remember current db backend config -{ -echo "annotation_db=${annotation_db}" -echo "duplicate_db=${duplicate_db}" -echo "mboxkey_db=${mboxkey_db}" -echo "mboxlist_db=${mboxlist_db}" -echo "ptscache_db=${ptscache_db}" -echo "quota_db=${quota_db}" -echo "seenstate_db=${seenstate_db}" -echo "statuscache_db=${statuscache_db}" -echo "sieve_version=${sieve_version}" -echo "subscription_db=${subscription_db}" -echo "tls_sessions_db=${tlscache_db}" -echo "userdeny_db=${userdeny_db}" -echo "zoneinfo_db=${zoneinfo_db}" -} | sort > $db_current - -# file_type <file> -file_type() { - this_type=$(file -b -m "${cyrus_magic}:${system_magic}" "$1" 2> /dev/null) - if echo "$this_type" | grep -qi skiplist > /dev/null 2>&1; then - echo skiplist - elif echo "$this_type" | grep -qi twoskip > /dev/null 2>&1; then - echo twoskip - elif echo "$this_type" | grep -qi text > /dev/null 2>&1; then - echo flat - else - echo berkeley - fi +function get_config_default() { + echo $(/usr/lib/cyrus-imapd/cyr_info allconf | grep -E "^$1:\s+" | sed -r -e 's/a-z0-9_-+\:(.*)/\1/g') } -# cvt_file <file> <db> -cvt_file() { - target="$1" - new_db="$2" - if -s "$target" ; then - old_db=$(file_type "$target") - if ! "$old_db" = "$new_db" ; then - # The two-step conversion is paranoia against the filenames being encoded - # inside the database or logfiles (berkeley does this, for example). - rm -f "${target}.skiplist" - if "$old_db" = "skiplist" ; then - cp -a "$target" "${target}.skiplist" - else - $cvt_cyrusdb -C $IMAPDCONF "$target" "$old_db" "${target}.skiplist" skiplist - fi - RETVAL=$? - ERRVAL=$(( $ERRVAL + $RETVAL )) - if $RETVAL -eq 0 ; then - rm -f "$target" - if -s "${target}.skiplist" ; then - if "$new_db" = "skiplist" ; then - cp -a "${target}.skiplist" "$target" - else - $cvt_cyrusdb -C $IMAPDCONF "${target}.skiplist" skiplist "$target" "$new_db" - fi - fi - RETVAL=$? - ERRVAL=$(( $ERRVAL + $RETVAL )) - if $RETVAL -eq 0 ; then - rm -f "${target}.skiplist" - else - echo "ERROR: unable to convert ${target}.skiplist from skiplist to $new_db" - fi - else - echo "ERROR: unable to convert $target from $old_db to skiplist" - fi - fi - fi -} +function get_current() { + value=$(/usr/lib/cyrus-imapd/cyr_info allconf | grep -E "^$1_path:\s+" | sed -r -e 's/a-z0-9_-+\:(.*)/\1/g') -# cvt_to_utf8 <file> -cvt_to_utf8() { - target="$1" - if -s "$target" ; then - if ! $sievec -C $IMAPDCONF "$target" "${target}.sievec"; then - iconv --from-code=ISO-8859-1 --to-code=UTF-8 --output="${target}.UTF-8" "$target" - if -s "${target}.UTF-8" ; then - # preserve timestamp - touch --reference="${target}" "${target}.UTF-8" - mv -f "${target}.UTF-8" "$target" - else - ERRVAL=$(( $ERRVAL + 1 )) - fi + if -z "${value}" ; then + value="/var/lib/imap/annotations.db" fi - rm -f "${target}.sievec" - fi } -ERRVAL=0 +annotation_db=$(get_config "annotation_db") +annotation_db_current=$(get_current "annotation_db") +annotation_db_default=$(get_config_default "annotation_db") -# make sure our Berkeley databases are in a sane state -# wait for db_checkpoint to end successfully or kill it after a timeout -db_checkpoint -v -1 -h ${imap_prefix}/db & -DB_CHECK_PID=$! -CNT=0 -while $CNT -lt 60 ; do - if ! kill -0 $DB_CHECK_PID > /dev/null 2>&1; then - break - fi - sleep 1 - let CNT+=1 -done -if kill -0 $DB_CHECK_PID > /dev/null 2>&1; then - kill -USR1 $DB_CHECK_PID > /dev/null 2>&1 - sleep 1 - kill -KILL $DB_CHECK_PID > /dev/null 2>&1 - wait $DB_CHECK_PID > /dev/null 2>&1 -fi +if ! -z "${annotation_db}" ; then + echo "annotation_db format configured to be ${annotation_db}" -# do a normal recovery -db_recover -v -h ${imap_prefix}/db -RETVAL=$? -if $RETVAL -ne 0 ; then - # try a catastrophic recovery instead of normal recovery - db_recover -v -c -h ${imap_prefix}/db - RETVAL=$? - ERRVAL=$(( $ERRVAL + $RETVAL )) - if $RETVAL -ne 0 ; then - echo "ERROR: catastrophic recovery of Berkeley databases failed" - fi -fi + if ! -z "${annotation_db_default}" ; then + echo "annotation_db default format is ${annotation_db_default}" -if "$EXPORT" = "export" ; then - # convert all db files to portable format for migration - # TODO: quota_db, we don't touch it for now - cvt_file ${imap_prefix}/annotations.db "twoskip" - cvt_file ${imap_prefix}/deliver.db "twoskip" - cvt_file ${imap_prefix}/mailboxes.db "twoskip" - cvt_file ${imap_prefix}/ptclient/ptscache.db "twoskip" - cvt_file ${imap_prefix}/statuscache.db "twoskip" - cvt_file ${imap_prefix}/tls_sessions.db "twoskip" - cvt_file ${imap_prefix}/user_deny.db "flat" - cvt_file ${imap_prefix}/zoneinfo.db "skiplist" - rm -vf ${imap_prefix}/db/log.* - rm -vf ${imap_prefix}/db/__db.* + if "${annotation_db}" != "${annotation_db_default}" ; then + cvt_database annotation_db + echo "those two do not match" + else + echo "configured and default match" + fi + else + echo "default not known" + fi else - # always convert db files which have been converted to skiplist - # TODO: quota_db, we don't touch it for now - cvt_file ${imap_prefix}/annotations.db "$annotation_db" - cvt_file ${imap_prefix}/deliver.db "$duplicate_db" - cvt_file ${imap_prefix}/mailboxes.db "$mboxlist_db" - cvt_file ${imap_prefix}/ptclient/ptscache.db "$ptscache_db" - cvt_file ${imap_prefix}/statuscache.db "$statuscache_db" - cvt_file ${imap_prefix}/tls_sessions.db "$tlscache_db" - cvt_file ${imap_prefix}/user_deny.db "$userdeny_db" - cvt_file ${imap_prefix}/zoneinfo.db "$zoneinfo_db" - # do we have to convert all databases? - if ! cmp -s $db_current $db_cache; then - # we treat sieve scripts the same way like db files - find ${sieve_dir}/ -name "*.script" -type f | while read db_file trash; do - cvt_to_utf8 "$db_file" - done - $masssievec $sievec $IMAPDCONF - # convert all db files left - find ${imap_prefix}/user/ -name "*.seen" -type f | while read db_file trash; do - cvt_file "$db_file" "$seenstate_db" - done - find ${imap_prefix}/user/ -name "*.sub" -type f | while read db_file trash; do - cvt_file "$db_file" "$subscription_db" - done - find ${imap_prefix}/user/ -name "*.mboxkey" -type f | while read db_file trash; do - cvt_file "$db_file" "$mboxkey_db" - done - fi -fi + if ! -z "${annotation_db_default}" ; then + echo "annotation_db default format is ${annotation_db_default}" -# update the config cache file so we can check whether something has changed -if $ERRVAL -eq 0 ; then - mv -f $db_current $db_cache -else - rm -f $db_cache - rm -f $db_current + if "${annotation_db}" != "${annotation_db_default}" ; then + cvt_database annotation_db + echo "those two do not match" + else + echo "configured and default match" + fi + else + echo "default not known" + fi fi -exit $ERRVAL +echo "annotation db: ${annotation_db}" +echo "annotation db (default): ${annotation_db_default}"
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.