[pacman-dev] Database consistency checking
Xavier
shiningxc at gmail.com
Fri Jul 20 17:09:55 EDT 2007
On Wed, Jul 18, 2007 at 05:23:50PM +0200, Xavier wrote:
> By calling check_depends(pkg) on all package from the local database, I have
> enough information for computing all requiredby fields. But the problem is I
> can't store these.
>
> In this part :
> 139 if(deppkg && alpm_depcmp(deppkg, dep)) {
> 140 found = 1;
>
> I would need to do something like :
> alpm_list_t *newrqdby = alpm_pkg_get_newrequiredby(deppkg);
> newrqdby = alpm_list_add(newrqdby, pkgname).
>
> And when everything is done, compare old and new requiredby lists for each
> package. But I don't see any way to do that.
> (that would also make my check_requiredby() function useless).
>
> Or maybe I could achieve the same (in a less efficient way) with a more
> complicated check_requiredby function.
> But on the algorithm side, this check_requiredby function is stupid because
> everything is done by check_depends..
Well, here is the original testdb file I already posted, plus the above
suggestion implemented (which allows more efficient code + the detection
of wrongly duplicated requiredby).
But that really sucks of course :( I hate C.. There is really no clean way
to do what I want?
I guess I could create a new pkg structure type only for that testdb file,
for storing the new requiredby field, or having a second local pkgcache
(duplicating every package and storing them in a list, and modifying the
requiredy field there).
But the code is already huge compared to the simple things it does.
It would make it even more huge :p
I think I'll start learning C# so I can hack on Maelstorm when its released
:)
Or maybe the best thing here would be to use libalpm bindings with an higher
level language.
-------------- next part --------------
>From 87a2748822e95d65d358fd81f31825f10e1c256c Mon Sep 17 00:00:00 2001
From: Chantry Xavier <shiningxc at gmail.com>
Date: Tue, 17 Jul 2007 14:21:01 +0200
Subject: [PATCH] Add testdb util for finding inconsistencies in the database.
Signed-off-by: Chantry Xavier <shiningxc at gmail.com>
---
src/util/.gitignore | 1 +
src/util/Makefile.am | 5 +-
src/util/testdb.c | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 206 insertions(+), 1 deletions(-)
create mode 100644 src/util/testdb.c
diff --git a/src/util/.gitignore b/src/util/.gitignore
index 96ef10d..3668880 100644
--- a/src/util/.gitignore
+++ b/src/util/.gitignore
@@ -2,3 +2,4 @@
.libs
vercmp
testpkg
+testdb
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
index 0c48f10..676b442 100644
--- a/src/util/Makefile.am
+++ b/src/util/Makefile.am
@@ -1,4 +1,4 @@
-bin_PROGRAMS = vercmp testpkg
+bin_PROGRAMS = vercmp testpkg testdb
INCLUDES = -I$(top_srcdir)/lib/libalpm
@@ -10,4 +10,7 @@ vercmp_LDADD = $(top_builddir)/lib/libalpm/.libs/libalpm.la
testpkg_SOURCES = testpkg.c
testpkg_LDADD = $(top_builddir)/lib/libalpm/.libs/libalpm.la
+testdb_SOURCES = testdb.c
+testdb_LDADD = $(top_builddir)/lib/libalpm/.libs/libalpm.la
+
# vim:set ts=2 sw=2 noet:
diff --git a/src/util/testdb.c b/src/util/testdb.c
new file mode 100644
index 0000000..9d7a8d8
--- /dev/null
+++ b/src/util/testdb.c
@@ -0,0 +1,201 @@
+/*
+ * testdb.c : Test a pacman local database for validity
+ *
+ * Copyright (c) 2007 by Aaron Griffin <aaronmgriffin at gmail.com>
+ *
+ * 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.
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <libgen.h>
+
+#include <alpm.h>
+#include <alpm_list.h>
+
+#define PATH_MAX 1024
+
+static void cleanup(int signum) {
+ if(alpm_release() == -1) {
+ fprintf(stderr, "error releasing alpm: %s\n", alpm_strerror(pm_errno));
+ }
+
+ exit(signum);
+}
+
+void output_cb(pmloglevel_t level, char *fmt, va_list args)
+{
+ if(strlen(fmt)) {
+ switch(level) {
+ case PM_LOG_ERROR: printf("error: "); break;
+ case PM_LOG_WARNING: printf("warning: "); break;
+ default: return;
+ }
+ vprintf(fmt, args);
+ printf("\n");
+ }
+}
+
+int db_test(char *dbpath)
+{
+ struct dirent *ent;
+ char path[PATH_MAX];
+ struct stat buf;
+ int ret = 0;
+
+ DIR *dir;
+
+ if(!(dir = opendir(dbpath))) {
+ fprintf(stderr, "error : %s : %s\n", dbpath, strerror(errno));
+ return(1);
+ }
+
+ while ((ent = readdir(dir)) != NULL) {
+ if(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) {
+ continue;
+ }
+ /* check for desc, depends, and files */
+ snprintf(path, PATH_MAX, "%s/%s/desc", dbpath, ent->d_name);
+ if(stat(path, &buf)) {
+ printf("%s: description file is missing\n", ent->d_name);
+ ret++;
+ }
+ snprintf(path, PATH_MAX, "%s/%s/depends", dbpath, ent->d_name);
+ if(stat(path, &buf)) {
+ printf("%s: dependency file is missing\n", ent->d_name);
+ ret++;
+ }
+ snprintf(path, PATH_MAX, "%s/%s/files", dbpath, ent->d_name);
+ if(stat(path, &buf)) {
+ printf("%s: file list is missing\n", ent->d_name);
+ ret++;
+ }
+ }
+ return(ret);
+}
+
+int check_requiredby(pmpkg_t *pkg)
+{
+ int retval = 0;
+ alpm_list_t *reqs, *deps;
+ const char *pkgname = alpm_pkg_get_name(pkg);
+
+ for(reqs = alpm_pkg_get_requiredby(pkg); reqs; reqs = reqs->next) {
+ int found = 0;
+ char *reqname = reqs->data;
+ pmpkg_t *reqpkg = alpm_db_get_pkg(alpm_option_get_localdb(), reqname);
+ for(deps = alpm_pkg_get_depends(reqpkg); deps && !found; deps = deps->next) {
+ pmdepend_t *dep = alpm_splitdep(deps->data);
+ found = alpm_depcmp(pkg, dep);
+ free(dep);
+ }
+ if(!found) {
+ printf("%s : wrong requiredby field %s\n", pkgname, reqname);
+ retval++;
+ }
+ }
+ return(retval);
+}
+
+int check_depends(pmpkg_t *pkg)
+{
+ int retval = 0;
+ alpm_list_t *i, *j;
+ pmdb_t *db = alpm_option_get_localdb();
+
+ const char *pkgname = alpm_pkg_get_name(pkg);
+ alpm_list_t *depends = alpm_pkg_get_depends(pkg);
+
+ for(i = depends; i; i = i->next) {
+ if(!i->data) {
+ continue;
+ }
+ char *depname = i->data;
+ pmdepend_t* dep = alpm_splitdep(depname);
+ if(dep == NULL) {
+ continue;
+ }
+ int found = 0;
+ for(j = alpm_db_getpkgcache(db); j; j = j->next) {
+ pmpkg_t *deppkg = j->data;
+ if(deppkg && alpm_depcmp(deppkg, dep)) {
+ found = 1;
+ alpm_list_t *rqdby = alpm_pkg_get_requiredby(deppkg);
+ const char *deppkgname = alpm_pkg_get_name(deppkg);
+ if(!alpm_list_find_str(rqdby, pkgname)) {
+ printf("%s : missing requiredby field %s\n", deppkgname, pkgname);
+ retval++;
+ }
+ }
+ }
+ if(!found) {
+ printf("%s : missing dependency %s\n", pkgname, depname);
+ retval++;
+ }
+ free(dep);
+ }
+ return(retval);
+}
+
+int main(int argc, char **argv)
+{
+ int retval = 0; /* default = false */
+ pmdb_t *db = NULL;
+ char dbpath[PATH_MAX];
+ alpm_list_t *i;
+
+ if(argc != 2) {
+ fprintf(stderr, "usage: %s <pacman db>\n", basename(argv[0]));
+ return(1);
+ }
+
+ snprintf(dbpath, PATH_MAX, "%s/local", argv[1]);
+
+ retval = db_test(dbpath);
+ if(retval) {
+ exit(retval);
+ }
+
+ if(alpm_initialize() == -1) {
+ fprintf(stderr, "cannot initialize alpm: %s\n", alpm_strerror(pm_errno));
+ return(1);
+ }
+
+ /* let us get log messages from libalpm */
+ alpm_option_set_logcb(output_cb);
+
+ alpm_option_set_dbpath(argv[1]);
+
+ db = alpm_db_register("local");
+ if(db == NULL) {
+ fprintf(stderr, "error: could not register 'local' database (%s)\n",
+ alpm_strerror(pm_errno));
+ cleanup(EXIT_FAILURE);
+ }
+
+ for(i = alpm_db_getpkgcache(db); i; i = alpm_list_next(i)) {
+ pmpkg_t *pkg = alpm_list_getdata(i);
+ retval += check_requiredby(pkg);
+ retval += check_depends(pkg);
+ }
+
+ cleanup(retval);
+}
--
1.5.2.4
-------------- next part --------------
>From c0f445808507029391522e7a1524cec82dfc59f0 Mon Sep 17 00:00:00 2001
From: Chantry Xavier <shiningxc at gmail.com>
Date: Fri, 20 Jul 2007 17:02:59 +0200
Subject: [PATCH] testdb : slightly more efficient implementation.
This also detects wrongly duplicated requiredby entries.
---
lib/libalpm/alpm.h | 2 +
lib/libalpm/package.c | 20 +++++++++
lib/libalpm/package.h | 1 +
src/util/testdb.c | 109 +++++++++++++++++++++++++++++++++++++------------
4 files changed, 105 insertions(+), 27 deletions(-)
diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h
index 9e641f3..cdd6311 100644
--- a/lib/libalpm/alpm.h
+++ b/lib/libalpm/alpm.h
@@ -211,6 +211,8 @@ alpm_list_t *alpm_pkg_get_licenses(pmpkg_t *pkg);
alpm_list_t *alpm_pkg_get_groups(pmpkg_t *pkg);
alpm_list_t *alpm_pkg_get_depends(pmpkg_t *pkg);
alpm_list_t *alpm_pkg_get_requiredby(pmpkg_t *pkg);
+alpm_list_t *alpm_pkg_get_newrequiredby(pmpkg_t *pkg);
+void alpm_pkg_set_newrequiredby(pmpkg_t *pkg, alpm_list_t *newrequiredby);
alpm_list_t *alpm_pkg_get_conflicts(pmpkg_t *pkg);
alpm_list_t *alpm_pkg_get_provides(pmpkg_t *pkg);
alpm_list_t *alpm_pkg_get_replaces(pmpkg_t *pkg);
diff --git a/lib/libalpm/package.c b/lib/libalpm/package.c
index d5eca20..437647f 100644
--- a/lib/libalpm/package.c
+++ b/lib/libalpm/package.c
@@ -519,6 +519,25 @@ alpm_list_t SYMEXPORT *alpm_pkg_get_requiredby(pmpkg_t *pkg)
return pkg->requiredby;
}
+void SYMEXPORT alpm_pkg_set_newrequiredby(pmpkg_t *pkg, alpm_list_t *newrequiredby)
+{
+ pkg->newrequiredby = newrequiredby;
+}
+
+alpm_list_t SYMEXPORT *alpm_pkg_get_newrequiredby(pmpkg_t *pkg)
+{
+ ALPM_LOG_FUNC;
+
+ /* Sanity checks */
+ ASSERT(handle != NULL, return(NULL));
+ ASSERT(pkg != NULL, return(NULL));
+
+ if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_DEPENDS)) {
+ _alpm_db_read(pkg->data, pkg, INFRQ_DEPENDS);
+ }
+ return pkg->newrequiredby;
+}
+
alpm_list_t SYMEXPORT *alpm_pkg_get_conflicts(pmpkg_t *pkg)
{
ALPM_LOG_FUNC;
@@ -746,6 +765,7 @@ pmpkg_t *_alpm_pkg_dup(pmpkg_t *pkg)
newpkg->licenses = alpm_list_strdup(alpm_pkg_get_licenses(pkg));
/*newpkg->desc_localized = alpm_list_strdup(pkg->desc_localized);*/
newpkg->requiredby = alpm_list_strdup(alpm_pkg_get_requiredby(pkg));
+ newpkg->newrequiredby = alpm_list_strdup(alpm_pkg_get_newrequiredby(pkg));
newpkg->conflicts = alpm_list_strdup(alpm_pkg_get_conflicts(pkg));
newpkg->files = alpm_list_strdup(alpm_pkg_get_files(pkg));
newpkg->backup = alpm_list_strdup(alpm_pkg_get_backup(pkg));
diff --git a/lib/libalpm/package.h b/lib/libalpm/package.h
index f704ab9..8c89807 100644
--- a/lib/libalpm/package.h
+++ b/lib/libalpm/package.h
@@ -75,6 +75,7 @@ struct __pmpkg_t {
alpm_list_t *backup;
alpm_list_t *depends;
alpm_list_t *requiredby;
+ alpm_list_t *newrequiredby;
alpm_list_t *conflicts;
alpm_list_t *provides;
/* internal */
diff --git a/src/util/testdb.c b/src/util/testdb.c
index 9d7a8d8..8040894 100644
--- a/src/util/testdb.c
+++ b/src/util/testdb.c
@@ -92,27 +92,17 @@ int db_test(char *dbpath)
return(ret);
}
-int check_requiredby(pmpkg_t *pkg)
+static void display_list(alpm_list_t *list)
{
- int retval = 0;
- alpm_list_t *reqs, *deps;
- const char *pkgname = alpm_pkg_get_name(pkg);
-
- for(reqs = alpm_pkg_get_requiredby(pkg); reqs; reqs = reqs->next) {
- int found = 0;
- char *reqname = reqs->data;
- pmpkg_t *reqpkg = alpm_db_get_pkg(alpm_option_get_localdb(), reqname);
- for(deps = alpm_pkg_get_depends(reqpkg); deps && !found; deps = deps->next) {
- pmdepend_t *dep = alpm_splitdep(deps->data);
- found = alpm_depcmp(pkg, dep);
- free(dep);
- }
- if(!found) {
- printf("%s : wrong requiredby field %s\n", pkgname, reqname);
- retval++;
+ alpm_list_t *i;
+ for(i = list; i; i = i->next) {
+ char *s = i->data;
+ if(i->next) {
+ printf("%s, ", s);
+ } else {
+ printf("%s\n", s);
}
}
- return(retval);
}
int check_depends(pmpkg_t *pkg)
@@ -123,6 +113,7 @@ int check_depends(pmpkg_t *pkg)
const char *pkgname = alpm_pkg_get_name(pkg);
alpm_list_t *depends = alpm_pkg_get_depends(pkg);
+ alpm_list_t *missing_deps = NULL;
for(i = depends; i; i = i->next) {
if(!i->data) {
@@ -138,23 +129,66 @@ int check_depends(pmpkg_t *pkg)
pmpkg_t *deppkg = j->data;
if(deppkg && alpm_depcmp(deppkg, dep)) {
found = 1;
- alpm_list_t *rqdby = alpm_pkg_get_requiredby(deppkg);
- const char *deppkgname = alpm_pkg_get_name(deppkg);
- if(!alpm_list_find_str(rqdby, pkgname)) {
- printf("%s : missing requiredby field %s\n", deppkgname, pkgname);
- retval++;
- }
+ alpm_list_t *newrqdby = alpm_pkg_get_newrequiredby(deppkg);
+ newrqdby = alpm_list_add(newrqdby, (char *)pkgname);
+ alpm_pkg_set_newrequiredby(deppkg, newrqdby);
}
}
if(!found) {
- printf("%s : missing dependency %s\n", pkgname, depname);
- retval++;
+ missing_deps = alpm_list_add(missing_deps, depname);
}
free(dep);
}
+ if(missing_deps) {
+ retval++;
+ printf("missing deps for %s : ", pkgname);
+ display_list(missing_deps);
+ }
return(retval);
}
+int _alpm_str_cmp(const void *s1, const void *s2)
+{
+ return(strcmp(s1, s2));
+}
+
+static void diff(alpm_list_t *list1, alpm_list_t *list2,
+ alpm_list_t **result1, alpm_list_t **result2)
+{
+ list1 = alpm_list_msort(list1, alpm_list_count(list1), _alpm_str_cmp);
+ list2 = alpm_list_msort(list2, alpm_list_count(list2), _alpm_str_cmp);
+
+ alpm_list_t *i = list1;
+ alpm_list_t *j = list2;
+
+ while(i || j) {
+ char *s1 = NULL;
+ char *s2 = NULL;
+ int n;
+ if(i && !j) {
+ n = -1;
+ } else if(!i && j) {
+ n = 1;
+ } else {
+ s1 = i->data;
+ s2 = j->data;
+ n = strcmp(s1, s2);
+ }
+ if(n < 0) {
+ s1 = i->data;
+ *result1 = alpm_list_add(*result1, s1);
+ i = i->next;
+ } else if (n > 0) {
+ s2 = j->data;
+ *result2 = alpm_list_add(*result2, s2);
+ j = j->next;
+ } else {
+ i = i->next;
+ j = j->next;
+ }
+ }
+}
+
int main(int argc, char **argv)
{
int retval = 0; /* default = false */
@@ -191,11 +225,32 @@ int main(int argc, char **argv)
cleanup(EXIT_FAILURE);
}
+ printf("CHECKING DEPENDENCIES\n\n");
for(i = alpm_db_getpkgcache(db); i; i = alpm_list_next(i)) {
pmpkg_t *pkg = alpm_list_getdata(i);
- retval += check_requiredby(pkg);
retval += check_depends(pkg);
}
+ printf("\nCHECKING REQUIREDBY\n\n");
+ for(i = alpm_db_getpkgcache(db); i; i = alpm_list_next(i)) {
+ alpm_list_t *extra = NULL, *missing = NULL;
+ pmpkg_t *pkg = alpm_list_getdata(i);
+ alpm_list_t *rqdby = alpm_pkg_get_requiredby(pkg);
+ alpm_list_t *newrqdby = alpm_pkg_get_newrequiredby(pkg);
+ diff(rqdby, newrqdby, &extra, &missing);
+ if(extra || missing) {
+ retval++;
+ const char *pkgname = alpm_pkg_get_name(pkg);
+ if(extra) {
+ printf("wrong requiredby for %s : ", pkgname);
+ display_list(extra);
+ }
+ if(missing) {
+ printf("missing requiredby for %s : ", pkgname);
+ display_list(missing);
+ }
+ }
+ }
+
cleanup(retval);
}
--
1.5.2.4
More information about the pacman-dev
mailing list