pkgsrc-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
pkg/46281: pkgin fails to clean its database properly
>Number: 46281
>Category: pkg
>Synopsis: pkgin fails to clean its database properly
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: pkg-manager
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Thu Mar 29 12:55:00 +0000 2012
>Originator: Filip Hajny
>Release: n/a
>Organization:
Joyent
>Environment:
SunOS af9b008b-434d-4d53-af5c-bb9ee6ea4746 5.11 joyent_20120126T071347Z i86pc
i386 i86pc
>Description:
In all pkgin 0.5.x versions (i.e. since 2011Q4), there is a serious bug that
affects *any* day to day operations. This is only manifest on SunOS, or - more
likely - on non-NetBSD platforms.
When the remote package repository is updated, pkgin needs to synchronize with
its local SQLite database, using 'pkgin update' (or with 'pkgin -f update'
regardless of any remote changes). As part of the database sync, the local
REMOTE_* tables need to be cleaned before new/updated contents is inserted. The
way this is currently implement in pkgin's summary.c code, is to take the
struct that holds the database table list, and try to *iterate* through it by
assuming the strings are laid out consequently:
for (ptbl = __UNCONST(sum.tbl_name), i = 0;
i < nelms;
ptbl += ((strlen(ptbl) + 1) * sizeof(char)), i++) {
if (strstr(ptbl, "_PKG") != NULL)
continue;
snprintf(buf, BUFSIZ, DELETE_REMOTE, ptbl, ptbl, repo, ptbl);
pkgindb_doquery(buf, NULL, NULL);
}
While this works apparently on NetBSD, there is no ground to believe this
should be so on any platform. On SunOS, the 2nd and further iterations of loop
end up pulling completely irrelevant strings from memory, which means the
database cleanup operation is a failure. Even though no real error is echoed
back to the user, the database is corrupted as stale entries pollute the table
of package dependencies, requires and provides, and on any subsequent database
update, this gets worse and worse. If the package count changes in the repo,
you'll end up getting ridiculous dependencies reported on any install/upgrade
request, as the indexing on the stale entries is off.
I've been in touch with imil, but it looks like he has had very little time
available to work on pkgin in 2012, so this remains a problem.
>How-To-Repeat:
Build pkgin>=0.5 on any SunOS platform.
Point it to a package repository.
Run 'pkgin -f update' at least twice.
>Fix:
There is clear advantage to having to loop through a struct, and the list of
tables is fixed and known anyway. This is a very crude patch, which only seems
to help stop the cancerous growth of REMOTE_DEPS (the most annoying one), but
not of the other tables. A better solution is needed.
--- summary.c.orig 2011-10-29 14:06:22.000000000 +0000
+++ summary.c
@@ -536,6 +536,19 @@ delete_remote_tbl(struct Summary sum, ch
"DELETE FROM REMOTE_PKG WHERE REPOSITORY = '%s';", repo);
pkgindb_doquery(buf, NULL, NULL);
}
+static void
+delete_remote_tbl_each(char *ptbl, char *repo)
+{
+ char buf[BUFSIZ];
+
+ snprintf(buf, BUFSIZ, DELETE_REMOTE,
+ ptbl, ptbl, repo, ptbl);
+ pkgindb_doquery(buf, NULL, NULL);
+
+ if (strstr(ptbl, "_DEPS") != NULL)
+ {
+ snprintf(buf, BUFSIZ,
+ "DELETE FROM REMOTE_PKG WHERE REPOSITORY = '%s';",
repo);
+ pkgindb_doquery(buf, NULL, NULL);
+ }
+}
static int
pdb_clean_remote(void *param, int argc, char **argv, char **colname)
@@ -556,7 +569,10 @@ pdb_clean_remote(void *param, int argc,
/* did not find argv[0] (db repository) in pkg_repos */
printf(MSG_CLEANING_DB_FROM_REPO, argv[0]);
- delete_remote_tbl(sumsw[1], argv[0]);
+ delete_remote_tbl_each("REMOTE_DEPS", argv[0]);
+ delete_remote_tbl_each("REMOTE_CONFLICTS", argv[0]);
+ delete_remote_tbl_each("REMOTE_REQUIRES", argv[0]);
+ delete_remote_tbl_each("REMOTE_PROVIDES", argv[0]);
snprintf(query, BUFSIZ,
"DELETE FROM REPOS WHERE REPO_URL = \'%s\';", argv[0]);
@@ -668,7 +684,10 @@ update_db(int which, char **pkgkeep)
printf(MSG_PROCESSING_REMOTE_SUMMARY, *prepos);
/* delete remote* associated to this repository
*/
- delete_remote_tbl(sumsw[i], *prepos);
+ delete_remote_tbl_each("REMOTE_DEPS", *prepos);
+ delete_remote_tbl_each("REMOTE_CONFLICTS",
*prepos);
+ delete_remote_tbl_each("REMOTE_REQUIRES",
*prepos);
+ delete_remote_tbl_each("REMOTE_PROVIDES",
*prepos);
/* update remote* table for this repository */
insert_summary(sumsw[i], summary, *prepos);
}
Home |
Main Index |
Thread Index |
Old Index