[pacman-dev] [PATCH] WIP: check local DB version

Dan McGee dan at archlinux.org
Thu Feb 3 12:15:42 EST 2011


---
Thoughts on this approach to a sanity check? It is a bit unfortunate that we do
the glob() call only to throw the results away, but it does work. It would be a
lot more efficient to do our own opendir()/access() loop since we only care
about existence, not the actual file paths. We could also scan only the first
few entries if we felt that was safe enough of an approach.

-Dan

 lib/libalpm/alpm.c  |    2 ++
 lib/libalpm/alpm.h  |    1 +
 lib/libalpm/db.c    |   46 ++++++++++++++++++++++++++++++++++++++++++++++
 lib/libalpm/db.h    |    4 +++-
 lib/libalpm/error.c |    2 ++
 lib/libalpm/trans.c |   15 +++++++++++++--
 src/pacman/util.c   |    4 ++++
 7 files changed, 71 insertions(+), 3 deletions(-)

diff --git a/lib/libalpm/alpm.c b/lib/libalpm/alpm.c
index 7c3bfc2..4f95832 100644
--- a/lib/libalpm/alpm.c
+++ b/lib/libalpm/alpm.c
@@ -56,6 +56,8 @@ int SYMEXPORT alpm_initialize(void)
 	}
 	if(_alpm_db_register_local() == NULL) {
 		/* error code should be set */
+		_alpm_handle_free(handle);
+		handle = NULL;
 		return(-1);
 	}
 
diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h
index 19ea4ff..c4edb43 100644
--- a/lib/libalpm/alpm.h
+++ b/lib/libalpm/alpm.h
@@ -497,6 +497,7 @@ enum _pmerrno_t {
 	PM_ERR_DB_NULL,
 	PM_ERR_DB_NOT_NULL,
 	PM_ERR_DB_NOT_FOUND,
+	PM_ERR_DB_VERSION,
 	PM_ERR_DB_WRITE,
 	PM_ERR_DB_REMOVE,
 	/* Servers */
diff --git a/lib/libalpm/db.c b/lib/libalpm/db.c
index c80dcbb..6ebc344 100644
--- a/lib/libalpm/db.c
+++ b/lib/libalpm/db.c
@@ -31,6 +31,8 @@
 #include <sys/stat.h>
 #include <regex.h>
 #include <time.h>
+#include <limits.h> /* PATH_MAX */
+#include <glob.h>
 
 /* libalpm */
 #include "db.h"
@@ -405,6 +407,50 @@ const char *_alpm_db_path(pmdb_t *db)
 	return(db->_path);
 }
 
+int _alpm_db_version(pmdb_t *db)
+{
+	const char *db_path;
+
+	if(db && db->_version) {
+		return(db->_version);
+	}
+
+	db_path = _alpm_db_path(db);
+	if(!db || !db_path) {
+		return(-1);
+	}
+
+	if(db->is_local) {
+		char path[PATH_MAX];
+		int globret;
+		glob_t globbuf;
+
+		snprintf(path, PATH_MAX, "%s*/depends", db_path);
+		globret = glob(path, GLOB_NOSORT, NULL, &globbuf);
+		switch(globret) {
+			case 0:
+				/* we found some depends files */
+				db->_version = 1;
+				break;
+			case GLOB_NOMATCH:
+				/* this is the good case */
+				db->_version = 2;
+				break;
+			case GLOB_NOSPACE:
+			case GLOB_ABORTED:
+				/* error cases */
+				db->_version = -1;
+				break;
+		}
+		globfree(&globbuf);
+		_alpm_log(PM_LOG_DEBUG, "database version for tree %s set to %d\n",
+				db->treename, db->_version);
+		return(db->_version);
+	} else {
+		return(-1);
+	}
+}
+
 int _alpm_db_cmp(const void *d1, const void *d2)
 {
 	pmdb_t *db1 = (pmdb_t *)d1;
diff --git a/lib/libalpm/db.h b/lib/libalpm/db.h
index b7fa7ca..9b3c42c 100644
--- a/lib/libalpm/db.h
+++ b/lib/libalpm/db.h
@@ -50,6 +50,7 @@ struct __pmdb_t {
 	char *treename;
 	/* do not access directly, use _alpm_db_path(db) for lazy access */
 	char *_path;
+	int _version;
 	int pkgcache_loaded;
 	int grpcache_loaded;
 	/* also indicates whether we are RO or RW */
@@ -63,14 +64,15 @@ struct __pmdb_t {
 
 
 /* db.c, database general calls */
+pmdb_t *_alpm_db_new(const char *treename, int is_local);
 void _alpm_db_free(pmdb_t *db);
 const char *_alpm_db_path(pmdb_t *db);
+int _alpm_db_version(pmdb_t *db);
 int _alpm_db_cmp(const void *d1, const void *d2);
 alpm_list_t *_alpm_db_search(pmdb_t *db, const alpm_list_t *needles);
 pmdb_t *_alpm_db_register_local(void);
 pmdb_t *_alpm_db_register_sync(const char *treename);
 void _alpm_db_unregister(pmdb_t *db);
-pmdb_t *_alpm_db_new(const char *treename, int is_local);
 
 /* be_*.c, backend specific calls */
 int _alpm_local_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq);
diff --git a/lib/libalpm/error.c b/lib/libalpm/error.c
index 1b144a5..bbe210b 100644
--- a/lib/libalpm/error.c
+++ b/lib/libalpm/error.c
@@ -77,6 +77,8 @@ const char SYMEXPORT *alpm_strerror(int err)
 			return _("database already registered");
 		case PM_ERR_DB_NOT_FOUND:
 			return _("could not find database");
+		case PM_ERR_DB_VERSION:
+			return _("database is incorrect version");
 		case PM_ERR_DB_WRITE:
 			return _("could not update database");
 		case PM_ERR_DB_REMOVE:
diff --git a/lib/libalpm/trans.c b/lib/libalpm/trans.c
index 804ab7a..3bc2207 100644
--- a/lib/libalpm/trans.c
+++ b/lib/libalpm/trans.c
@@ -59,10 +59,11 @@
  * @return 0 on success, -1 on error (pm_errno is set accordingly)
  */
 int SYMEXPORT alpm_trans_init(pmtransflag_t flags,
-                              alpm_trans_cb_event event, alpm_trans_cb_conv conv,
-                              alpm_trans_cb_progress progress)
+		alpm_trans_cb_event event, alpm_trans_cb_conv conv,
+		alpm_trans_cb_progress progress)
 {
 	pmtrans_t *trans;
+	const int localdb_version = 2;
 
 	ALPM_LOG_FUNC;
 
@@ -79,6 +80,16 @@ int SYMEXPORT alpm_trans_init(pmtransflag_t flags,
 		}
 	}
 
+	/* check database version */
+	if(_alpm_db_version(handle->db_local) < localdb_version) {
+		_alpm_log(PM_LOG_ERROR,
+				_("%s database version %d is too old, version %d required\n"),
+				handle->db_local->treename, _alpm_db_version(handle->db_local),
+				localdb_version);
+		_alpm_lckrm();
+		RET_ERR(PM_ERR_DB_VERSION, -1);
+	}
+
 	trans = _alpm_trans_new();
 	if(trans == NULL) {
 		RET_ERR(PM_ERR_MEMORY, -1);
diff --git a/src/pacman/util.c b/src/pacman/util.c
index c08ebb1..9d50afb 100644
--- a/src/pacman/util.c
+++ b/src/pacman/util.c
@@ -63,6 +63,10 @@ int trans_init(pmtransflag_t flags)
 			fprintf(stderr, _("  if you're sure a package manager is not already\n"
 						"  running, you can remove %s\n"), alpm_option_get_lockfile());
 		}
+		else if(pm_errno == PM_ERR_DB_VERSION) {
+			fprintf(stderr, _("  try running pacman-db-upgrade\n"));
+		}
+
 		return(-1);
 	}
 	return(0);
-- 
1.7.4



More information about the pacman-dev mailing list