summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjoerg <joerg@pkgsrc.org>2007-08-08 22:33:38 +0000
committerjoerg <joerg@pkgsrc.org>2007-08-08 22:33:38 +0000
commitf9b953763be90f5f4aa6340d6a5ffd8eb80c4c63 (patch)
tree7e621c7d261aae0be0cef960d2c638fda2884235
parent269656e69d31e6c387f740f23d4e12d9e1edf810 (diff)
downloadpkgsrc-f9b953763be90f5f4aa6340d6a5ffd8eb80c4c63.tar.gz
Replace note_whats_installed, add_to_list_fn and generally most
users of findbestmatchingname and findmatching name with more descriptive and easier to use iterator functions. This functions are a first step to abstract away pkgdb layout from most parts of the code. It also helps to reduce side effects and point out potential bugs in this code. Fix a potential, but practically irrelevant buffer overflow. No longer allow symbolic links directly in pkgdb to store the meta data of individual packages outside. E.g. /var/db/pkg/atk-1.18.0 must be a directory and not point to it. This is not yet enforced in all parts of the code, more changes will follow. Bump version to 20070808.
-rw-r--r--pkgtools/pkg_install/files/add/perform.c74
-rw-r--r--pkgtools/pkg_install/files/admin/main.c137
-rw-r--r--pkgtools/pkg_install/files/audit-packages/audit-packages.c77
-rw-r--r--pkgtools/pkg_install/files/create/perform.c76
-rw-r--r--pkgtools/pkg_install/files/delete/main.c6
-rw-r--r--pkgtools/pkg_install/files/delete/perform.c58
-rw-r--r--pkgtools/pkg_install/files/info/main.c10
-rw-r--r--pkgtools/pkg_install/files/info/perform.c98
-rw-r--r--pkgtools/pkg_install/files/lib/Makefile.in7
-rw-r--r--pkgtools/pkg_install/files/lib/iterate.c328
-rw-r--r--pkgtools/pkg_install/files/lib/lib.h15
-rw-r--r--pkgtools/pkg_install/files/lib/str.c36
-rw-r--r--pkgtools/pkg_install/files/lib/version.h4
13 files changed, 586 insertions, 340 deletions
diff --git a/pkgtools/pkg_install/files/add/perform.c b/pkgtools/pkg_install/files/add/perform.c
index b935335af67..c19f6ad7414 100644
--- a/pkgtools/pkg_install/files/add/perform.c
+++ b/pkgtools/pkg_install/files/add/perform.c
@@ -1,4 +1,4 @@
-/* $NetBSD: perform.c,v 1.51 2007/07/30 08:09:14 joerg Exp $ */
+/* $NetBSD: perform.c,v 1.52 2007/08/08 22:33:38 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
@@ -14,7 +14,7 @@
#if 0
static const char *rcsid = "from FreeBSD Id: perform.c,v 1.44 1997/10/13 15:03:46 jkh Exp";
#else
-__RCSID("$NetBSD: perform.c,v 1.51 2007/07/30 08:09:14 joerg Exp $");
+__RCSID("$NetBSD: perform.c,v 1.52 2007/08/08 22:33:38 joerg Exp $");
#endif
#endif
@@ -524,7 +524,7 @@ pkg_do(const char *pkg, lpkg_head_t *pkgs)
if ((s = strrchr(PkgName, '-')) != NULL) {
char buf[MaxPathSize];
- char installed[MaxPathSize];
+ char *best_installed;
/*
* See if the pkg is already installed. If so, we might
@@ -532,18 +532,19 @@ pkg_do(const char *pkg, lpkg_head_t *pkgs)
*/
(void) snprintf(buf, sizeof(buf), "%.*s[0-9]*",
(int)(s - PkgName) + 1, PkgName);
- if (findmatchingname(dbdir, buf, note_whats_installed, installed) > 0) {
+ best_installed = find_best_matching_installed_pkg(buf);
+ if (best_installed) {
if (Replace && !Fake) {
/* XXX Should list the steps in Fake mode */
snprintf(replace_from, sizeof(replace_from), "%s/%s/" REQUIRED_BY_FNAME,
- dbdir, installed);
+ dbdir, best_installed);
snprintf(replace_via, sizeof(replace_via), "%s/.%s." REQUIRED_BY_FNAME,
- dbdir, installed);
+ dbdir, best_installed);
snprintf(replace_to, sizeof(replace_to), "%s/%s/" REQUIRED_BY_FNAME,
dbdir, PkgName);
if (Verbose)
- printf("Upgrading %s to %s.\n", installed, PkgName);
+ printf("Upgrading %s to %s.\n", best_installed, PkgName);
if (fexists(replace_from)) { /* Are there any dependencies? */
/*
@@ -658,30 +659,34 @@ ignore_replace_depends_check:
printf("%s/pkg_delete -K %s '%s'\n",
BINDIR,
dbdir,
- installed);
+ best_installed);
}
- fexec(BINDIR "/pkg_delete", "-K", dbdir, installed, NULL);
+ fexec(BINDIR "/pkg_delete", "-K", dbdir, best_installed, NULL);
} else if (!is_depoted_pkg) {
- warnx("other version '%s' already installed", installed);
+ warnx("other version '%s' already installed", best_installed);
errc = 1;
goto success; /* close enough for government work */
}
+ free(best_installed);
}
}
}
/* See if there are conflicting packages installed */
for (p = Plist.head; p; p = p->next) {
- char installed[MaxPathSize];
+ char *best_installed;
if (p->type != PLIST_PKGCFL)
continue;
if (Verbose)
printf("Package `%s' conflicts with `%s'.\n", PkgName, p->name);
- if (findmatchingname(dbdir, p->name, note_whats_installed, installed) > 0) {
+ best_installed = find_best_matching_installed_pkg(p->name);
+ if (best_installed) {
warnx("Conflicting package `%s'installed, please use\n"
- "\t\"pkg_delete %s\" first to remove it!", installed, installed);
+ "\t\"pkg_delete %s\" first to remove it!",
+ best_installed, best_installed);
+ free(best_installed);
++errc;
}
}
@@ -691,13 +696,14 @@ ignore_replace_depends_check:
*/
err_prescan=0;
for (p = Plist.head; p; p = p->next) {
- char installed[MaxPathSize];
+ char *best_installed;
if (p->type != PLIST_PKGDEP)
continue;
if (Verbose)
printf("Depends pre-scan: `%s' required.\n", p->name);
- if (findmatchingname(dbdir, p->name, note_whats_installed, installed) <= 0) {
+ best_installed = find_best_matching_installed_pkg(p->name);
+ if (best_installed == NULL) {
/*
* required pkg not found. look if it's available with a more liberal
* pattern. If so, this will lead to problems later (check on "some
@@ -729,8 +735,8 @@ ignore_replace_depends_check:
(void) snprintf(buf, sizeof(buf),
skip ? "%.*s[0-9]*" : "%.*s-[0-9]*",
(int)(s - p->name) + skip, p->name);
- if (findmatchingname(dbdir, buf, note_whats_installed, installed) > 0)
- {
+ best_installed = find_best_matching_installed_pkg(buf);
+ if (best_installed) {
int done = 0;
if (Replace > 1)
@@ -752,15 +758,18 @@ ignore_replace_depends_check:
if (!done)
{
warnx("pkg `%s' required, but `%s' found installed.",
- p->name, installed);
+ p->name, best_installed);
if (Force) {
warnx("Proceeding anyway.");
} else {
err_prescan++;
}
}
+ free(best_installed);
}
}
+ } else {
+ free(best_installed);
}
}
if (err_prescan > 0) {
@@ -772,7 +781,7 @@ ignore_replace_depends_check:
/* Now check the packing list for dependencies */
for (exact = NULL, p = Plist.head; p; p = p->next) {
- char installed[MaxPathSize];
+ char *best_installed;
if (p->type == PLIST_BLDDEP) {
exact = p->name;
@@ -785,7 +794,9 @@ ignore_replace_depends_check:
if (Verbose)
printf("Package `%s' depends on `%s'.\n", PkgName, p->name);
- if (findmatchingname(dbdir, p->name, note_whats_installed, installed) != 1) {
+ best_installed = find_best_matching_installed_pkg(p->name);
+
+ if (best_installed == NULL) {
/* required pkg not found - need to pull in */
if (Fake) {
@@ -808,8 +819,10 @@ ignore_replace_depends_check:
errc += errc0;
}
}
- } else if (Verbose) {
- printf(" - %s already installed.\n", installed);
+ } else {
+ if (Verbose)
+ printf(" - %s already installed.\n", best_installed);
+ free(best_installed);
}
}
@@ -910,17 +923,14 @@ ignore_replace_depends_check:
basename_of(p->name));
if (ispkgpattern(p->name)) {
char *s;
- s = findbestmatchingname(dirname_of(contents),
- basename_of(contents));
- if (s != NULL) {
- char *t;
- t = strrchr(contents, '/');
- strcpy(t + 1, s);
- free(s);
- } else {
+
+ s = find_best_matching_installed_pkg(p->name);
+
+ if (s == NULL)
errx(EXIT_FAILURE, "Where did our dependency go?!");
- /* this shouldn't happen... X-) */
- }
+
+ (void) snprintf(contents, sizeof(contents), "%s/%s", dbdir, s);
+ free(s);
}
strlcat(contents, "/", sizeof(contents));
strlcat(contents, REQUIRED_BY_FNAME, sizeof(contents));
diff --git a/pkgtools/pkg_install/files/admin/main.c b/pkgtools/pkg_install/files/admin/main.c
index 2ff36960e25..c069bb9ad43 100644
--- a/pkgtools/pkg_install/files/admin/main.c
+++ b/pkgtools/pkg_install/files/admin/main.c
@@ -1,4 +1,4 @@
-/* $NetBSD: main.c,v 1.21 2007/07/20 22:22:52 joerg Exp $ */
+/* $NetBSD: main.c,v 1.22 2007/08/08 22:33:38 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
@@ -8,7 +8,7 @@
#include <sys/cdefs.h>
#endif
#ifndef lint
-__RCSID("$NetBSD: main.c,v 1.21 2007/07/20 22:22:52 joerg Exp $");
+__RCSID("$NetBSD: main.c,v 1.22 2007/08/08 22:33:38 joerg Exp $");
#endif
/*
@@ -83,7 +83,7 @@ int pkgcnt;
static int quiet;
-static int checkpattern_fn(const char *, const char *, void *);
+static int checkpattern_fn(const char *, void *);
static void set_unset_variable(char **, Boolean);
/* print usage message and exit */
@@ -414,9 +414,9 @@ checkall(void)
}
static int
-checkpattern_fn(const char *pattern, const char *pkg, void *vp)
+checkpattern_fn(const char *pkg, void *vp)
{
- int rc;
+ int *got_match, rc;
rc = chdir(pkg);
if (rc == -1)
@@ -429,6 +429,9 @@ checkpattern_fn(const char *pattern, const char *pkg, void *vp)
chdir("..");
+ got_match = vp;
+ *got_match = 1;
+
return 0;
}
@@ -551,32 +554,26 @@ main(int argc, char *argv[])
err(EXIT_FAILURE, "Cannot chdir to %s", _pkgdb_getPKGDB_DIR());
while (*argv != NULL) {
- if (ispkgpattern(*argv)) {
- if (findmatchingname(_pkgdb_getPKGDB_DIR(), *argv, checkpattern_fn, NULL) <= 0)
+ int got_match;
+
+ got_match = 0;
+ if (match_installed_pkgs(*argv, checkpattern_fn, &got_match) == -1)
+ errx(EXIT_FAILURE, "Cannot process pkdbdb");
+ if (got_match == 0) {
+ char *pattern;
+
+ if (ispkgpattern(*argv))
errx(EXIT_FAILURE, "No matching pkg for %s.", *argv);
- } else {
- rc = chdir(*argv);
- if (rc == -1) {
- /* found nothing - try 'pkg-[0-9]*' */
- char try[MaxPathSize];
-
- snprintf(try, sizeof(try), "%s-[0-9]*", *argv);
- if (findmatchingname(_pkgdb_getPKGDB_DIR(), try,
- checkpattern_fn, NULL) <= 0) {
-
- errx(EXIT_FAILURE, "cannot find package %s", *argv);
- } else {
- /* nothing to do - all the work is/was
- * done in checkpattern_fn() */
- }
- } else {
- check1pkg(*argv);
- if (!quiet) {
- printf(".");
- }
- chdir("..");
- }
+ if (asprintf(&pattern, "%s-[0-9]*", *argv) == -1)
+ errx(EXIT_FAILURE, "asprintf failed");
+
+ if (match_installed_pkgs(*argv, checkpattern_fn, &got_match) == -1)
+ errx(EXIT_FAILURE, "Cannot process pkdbdb");
+
+ if (got_match == 0)
+ errx(EXIT_FAILURE, "cannot find package %s", *argv);
+ free(pattern);
}
argv++;
@@ -751,32 +748,36 @@ main(int argc, char *argv[])
return 0;
}
-struct varval {
- char *variable;
- char *value;
+struct set_installed_info_arg {
+ char *variable;
+ char *value;
+ int got_match;
};
static int
-set_installed_info_var(const char *pattern, const char *name, void *ud)
+set_installed_info_var(const char *name, void *cookie)
{
- char filename[BUFSIZ];
- struct varval *varval;
+ struct set_installed_info_arg *arg = cookie;
+ char *filename;
+ int retval;
+
+ if (asprintf(&filename, "%s/%s", name, INSTALLED_INFO_FNAME) == -1)
+ errx(EXIT_FAILURE, "asprintf failed");
- varval = ud;
+ retval = var_set(filename, arg->variable, arg->value);
- (void)snprintf(filename, sizeof(filename), "%s/%s", name,
- INSTALLED_INFO_FNAME);
+ free(filename);
- return var_set(filename, varval->variable, varval->value);
+ return retval;
}
static void
set_unset_variable(char **argv, Boolean unset)
{
- struct varval varval;
- int ret = 0;
+ struct set_installed_info_arg arg;
char *eq;
char *variable;
+ int ret = 0;
if (argv[0] == NULL || argv[1] == NULL)
usage();
@@ -784,8 +785,8 @@ set_unset_variable(char **argv, Boolean unset)
variable = NULL;
if (unset) {
- varval.variable = argv[0];
- varval.value = NULL;
+ arg.variable = argv[0];
+ arg.value = NULL;
} else {
eq = NULL;
if ((eq=strchr(argv[0], '=')) == NULL)
@@ -794,46 +795,46 @@ set_unset_variable(char **argv, Boolean unset)
variable = malloc(eq-argv[0]+1);
strlcpy(variable, argv[0], eq-argv[0]+1);
- varval.variable = variable;
- varval.value = eq+1;
+ arg.variable = variable;
+ arg.value = eq+1;
if (strcmp(variable, AUTOMATIC_VARNAME) == 0 &&
- strcasecmp(varval.value, "yes") != 0 &&
- strcasecmp(varval.value, "no") != 0) {
+ strcasecmp(arg.value, "yes") != 0 &&
+ strcasecmp(arg.value, "no") != 0) {
errx(EXIT_FAILURE,
"unknown value `%s' for " AUTOMATIC_VARNAME,
- varval.value);
+ arg.value);
}
}
- if (strcspn(varval.variable, "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
- != strlen(varval.variable)) {
+ if (strpbrk(arg.variable, "ABCDEFGHIJKLMNOPQRSTUVWXYZ") != NULL) {
free(variable);
errx(EXIT_FAILURE,
"variable name must not contain uppercase letters");
}
- chdir(_pkgdb_getPKGDB_DIR());
argv++;
while (*argv != NULL) {
- if (ispkgpattern(*argv)) {
- if (findmatchingname(_pkgdb_getPKGDB_DIR(),
- *argv, set_installed_info_var,
- &varval) <= 0) {
+ arg.got_match = 0;
+ if (match_installed_pkgs(*argv, set_installed_info_var, &arg) == -1)
+ errx(EXIT_FAILURE, "Cannot process pkdbdb");
+ if (arg.got_match == 0) {
+ char *pattern;
+
+ if (ispkgpattern(*argv)) {
warnx("no matching pkg for `%s'", *argv);
ret++;
- }
- } else if (isdir(*argv) || islinktodir(*argv))
- set_installed_info_var(NULL, *argv, &varval);
- else {
- /* try 'pkg-[0-9]*' */
- char try[MaxPathSize];
-
- snprintf(try, sizeof(try), "%s-[0-9]*", *argv);
- if (findmatchingname(_pkgdb_getPKGDB_DIR(),
- try, set_installed_info_var,
- &varval) <= 0) {
- warnx("cannot find package %s", *argv);
- ret++;
+ } else {
+ if (asprintf(&pattern, "%s-[0-9]*", *argv) == -1)
+ errx(EXIT_FAILURE, "asprintf failed");
+
+ if (match_installed_pkgs(*argv, set_installed_info_var, &arg) == -1)
+ errx(EXIT_FAILURE, "Cannot process pkdbdb");
+
+ if (arg.got_match == 0) {
+ warnx("cannot find package %s", *argv);
+ ++ret;
+ }
+ free(pattern);
}
}
diff --git a/pkgtools/pkg_install/files/audit-packages/audit-packages.c b/pkgtools/pkg_install/files/audit-packages/audit-packages.c
index b01565f541f..da35a1ffafd 100644
--- a/pkgtools/pkg_install/files/audit-packages/audit-packages.c
+++ b/pkgtools/pkg_install/files/audit-packages/audit-packages.c
@@ -1,4 +1,4 @@
-/* $NetBSD: audit-packages.c,v 1.7 2007/08/01 23:58:15 taca Exp $ */
+/* $NetBSD: audit-packages.c,v 1.8 2007/08/08 22:33:39 joerg Exp $ */
/*
* Copyright (c) 2007 Adrian Portelli <adrianp@NetBSD.org>.
@@ -113,8 +113,7 @@ Boolean eol = FALSE; /* don't check eol */
int main(int, char **);
void *safe_calloc(size_t, size_t);
char *ap_fixpkgname(char *);
-static int foundpkg(const char *, const char *, void *);
-static int checkforpkg(char *);
+static int checkforpkg(const char *);
void usage(void);
int dvl(void);
void old_pvfile(void);
@@ -655,75 +654,21 @@ get_confvalues(void)
return 0;
}
-/* called by checkforpkg to see if a package exists */
-static int
-foundpkg(const char *pattern, const char *found, void *vp)
-{
- char *data = vp;
- char *buf;
- int retval = 0;
-
- buf = safe_calloc(PATH_MAX, sizeof(char));
-
- /* we only want to display this if it really is a directory */
- retval = snprintf(buf, PATH_MAX, "%s/%s", data, found);
-
- if (retval < 0 || retval >= PATH_MAX)
- return 0;
-
- if (!(isdir(buf) || islinktodir(buf)))
- return -1; /* return value seems to be ignored for now */
-
- pkgname = ap_fixpkgname(buf);
- free(buf);
-
- return 0;
-}
-
/* check to see if a package exists */
static int
-checkforpkg(char *one_package)
+checkforpkg(const char *one_package)
{
- char *dbdir = NULL;
- int retval;
- char *buf = NULL;
- char *try = NULL;
+ pkgname = find_best_matching_installed_pkg(one_package);
+ if (pkgname == NULL && !ispkgpattern(one_package)) {
+ char *pattern;
- dbdir = _pkgdb_getPKGDB_DIR();
+ if (asprintf(&pattern, "%s-[0-9]*", one_package) == -1)
+ errx(EXIT_FAILURE, "asprintf failed");
- /* expensive (pattern) match */
- if (strpbrk(one_package, "<>[]?*{")) {
- retval = findmatchingname(dbdir, one_package, foundpkg, dbdir);
-
- if (retval == -1) {
- return 1;
- } else {
- return !retval;
- }
+ pkgname = find_best_matching_installed_pkg(pattern);
+ free(pattern);
}
-
- buf = safe_calloc(PATH_MAX, sizeof(char));
-
- /* simple match */
- (void) snprintf(buf, PATH_MAX, "%s/%s", dbdir, one_package);
- retval = !(isdir(buf) || islinktodir(buf));
-
- pkgname = ap_fixpkgname(buf);
-
- if (retval == 1) {
-
- /* found nothing - try 'pkg-[0-9]*' */
- try = safe_calloc(PATH_MAX, sizeof(char));
-
- snprintf(try, PATH_MAX, "%s-[0-9]*", one_package);
- if (findmatchingname(dbdir, try, foundpkg, dbdir) > 0)
- retval = 0;
- }
-
- free(buf);
- free(try);
-
- return retval;
+ return pkgname == NULL ? 1 : 0;
}
/* usage message for this program */
diff --git a/pkgtools/pkg_install/files/create/perform.c b/pkgtools/pkg_install/files/create/perform.c
index ad055fa2e62..a6b47a7c376 100644
--- a/pkgtools/pkg_install/files/create/perform.c
+++ b/pkgtools/pkg_install/files/create/perform.c
@@ -1,4 +1,4 @@
-/* $NetBSD: perform.c,v 1.16 2007/08/03 15:44:18 joerg Exp $ */
+/* $NetBSD: perform.c,v 1.17 2007/08/08 22:33:39 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
@@ -11,7 +11,7 @@
#if 0
static const char *rcsid = "from FreeBSD Id: perform.c,v 1.38 1997/10/13 15:03:51 jkh Exp";
#else
-__RCSID("$NetBSD: perform.c,v 1.16 2007/08/03 15:44:18 joerg Exp $");
+__RCSID("$NetBSD: perform.c,v 1.17 2007/08/08 22:33:39 joerg Exp $");
#endif
#endif
@@ -56,13 +56,46 @@ sanity_check(void)
errx(2, "required package contents list is missing (-f [-]file)");
}
+static void
+register_depends(package_t *plist, char *deps, int build_only)
+{
+ char *cp;
+
+ if (Verbose && !PlistOnly) {
+ if (build_only)
+ printf("Registering build depends:");
+ else
+ printf("Registering depends:");
+ }
+ while (deps) {
+ cp = strsep(&Pkgdeps, " \t\n");
+ if (*cp) {
+ char *best_installed;
+ best_installed = find_best_matching_installed_pkg(cp);
+ if (best_installed != NULL) {
+ add_plist(plist, PLIST_BLDDEP, best_installed);
+ if (Verbose && !PlistOnly && build_only)
+ printf(" %s", cp);
+ } else
+ warnx("No matching package installed for %s", cp);
+ free(best_installed);
+ if (!build_only) {
+ add_plist(plist, PLIST_PKGDEP, cp);
+ if (Verbose && !PlistOnly)
+ printf(" %s", cp);
+ }
+ }
+ }
+ if (Verbose && !PlistOnly)
+ printf(".\n");
+}
+
int
pkg_perform(const char *pkg)
{
char *cp;
FILE *pkg_in;
package_t plist;
- char installed[MaxPathSize];
const char *full_pkg, *suffix;
char *allocated_pkg;
int retval;
@@ -105,44 +138,15 @@ pkg_perform(const char *pkg)
}
/* Stick the dependencies, if any, at the top */
- if (Pkgdeps) {
- if (Verbose && !PlistOnly)
- printf("Registering depends:");
- while (Pkgdeps) {
- cp = strsep(&Pkgdeps, " \t\n");
- if (*cp) {
- if (findmatchingname(_pkgdb_getPKGDB_DIR(), cp, note_whats_installed, installed) > 0) {
- add_plist(&plist, PLIST_BLDDEP, installed);
- }
- add_plist(&plist, PLIST_PKGDEP, cp);
- if (Verbose && !PlistOnly)
- printf(" %s", cp);
- }
- }
- if (Verbose && !PlistOnly)
- printf(".\n");
- }
+ if (Pkgdeps)
+ register_depends(&plist, Pkgdeps, 0);
/*
* Put the build dependencies after the dependencies.
* This works due to the evaluation order in pkg_add.
*/
- if (BuildPkgdeps) {
- if (Verbose && !PlistOnly)
- printf("Registering build depends:");
- while (BuildPkgdeps) {
- cp = strsep(&BuildPkgdeps, " \t\n");
- if (*cp) {
- if (findmatchingname(_pkgdb_getPKGDB_DIR(), cp, note_whats_installed, installed) > 0) {
- add_plist(&plist, PLIST_BLDDEP, installed);
- if (Verbose && !PlistOnly)
- printf(" %s", cp);
- }
- }
- }
- if (Verbose && !PlistOnly)
- printf(".\n");
- }
+ if (BuildPkgdeps)
+ register_depends(&plist, BuildPkgdeps, 1);
/* Put the conflicts directly after the dependencies, if any */
if (Pkgcfl) {
diff --git a/pkgtools/pkg_install/files/delete/main.c b/pkgtools/pkg_install/files/delete/main.c
index 02a8ca64423..65100fc1240 100644
--- a/pkgtools/pkg_install/files/delete/main.c
+++ b/pkgtools/pkg_install/files/delete/main.c
@@ -1,4 +1,4 @@
-/* $NetBSD: main.c,v 1.17 2006/04/04 06:27:13 wiz Exp $ */
+/* $NetBSD: main.c,v 1.18 2007/08/08 22:33:39 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
@@ -11,7 +11,7 @@
#if 0
static char *rcsid = "from FreeBSD Id: main.c,v 1.11 1997/10/08 07:46:48 charnier Exp";
#else
-__RCSID("$NetBSD: main.c,v 1.17 2006/04/04 06:27:13 wiz Exp $");
+__RCSID("$NetBSD: main.c,v 1.18 2007/08/08 22:33:39 joerg Exp $");
#endif
#endif
@@ -160,7 +160,7 @@ main(int argc, char **argv)
lpp = alloc_lpkg(s);
TAILQ_INSERT_TAIL(&pkgs, lpp, lp_link);
} else if (ispkgpattern(*argv)) {
- switch(findmatchingname(_pkgdb_getPKGDB_DIR(), *argv, add_to_list_fn, &pkgs)) {
+ switch (add_installed_pkgs_by_pattern(*argv, &pkgs)) {
case 0:
errx(EXIT_FAILURE, "No matching pkg for %s.", *argv);
case -1:
diff --git a/pkgtools/pkg_install/files/delete/perform.c b/pkgtools/pkg_install/files/delete/perform.c
index 5fc87904ede..35db572624d 100644
--- a/pkgtools/pkg_install/files/delete/perform.c
+++ b/pkgtools/pkg_install/files/delete/perform.c
@@ -1,4 +1,4 @@
-/* $NetBSD: perform.c,v 1.18 2007/07/26 11:30:55 joerg Exp $ */
+/* $NetBSD: perform.c,v 1.19 2007/08/08 22:33:39 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
@@ -11,7 +11,7 @@
#if 0
static const char *rcsid = "from FreeBSD Id: perform.c,v 1.15 1997/10/13 15:03:52 jkh Exp";
#else
-__RCSID("$NetBSD: perform.c,v 1.18 2007/07/26 11:30:55 joerg Exp $");
+__RCSID("$NetBSD: perform.c,v 1.19 2007/08/08 22:33:39 joerg Exp $");
#endif
#endif
@@ -83,7 +83,7 @@ static int require_find_recursive_down(lpkg_t *, package_t *);
static int require_find(char *, rec_find_t);
static int require_delete(char *, int);
static void require_print(void);
-static int undepend(const char *, const char *, void *);
+static int undepend(const char *, void *);
static char LogDir[MaxPathSize];
static char linebuf[MaxPathSize];
@@ -115,10 +115,10 @@ cleanup(int sig)
/*
* deppkgname is the pkg from which's +REQUIRED_BY file we are
* about to remove pkg2delname. This function is called from
- * findmatchingname(), deppkgname is expanded from a (possible) pattern.
+ * match_installed_pkgs(), deppkgname is expanded from a (possible) pattern.
*/
static int
-undepend(const char *pattern, const char *deppkgname, void *vp)
+undepend(const char *deppkgname, void *vp)
{
char *pkg2delname = vp;
char fname[MaxPathSize], ftmp[MaxPathSize];
@@ -266,6 +266,7 @@ unview(const char *pkgname)
int
require_delete(char *home, int tryall)
{
+ char *best_installed;
lpkg_t *lpp;
int rv, fail;
int oldcwd;
@@ -277,12 +278,14 @@ require_delete(char *home, int tryall)
(void) snprintf(pkgdir, sizeof(pkgdir), "%s", _pkgdb_getPKGDB_DIR());
+ best_installed = NULL;
+
/* walk list of things to delete */
fail = 0;
lpp = TAILQ_FIRST(&lpdelq);
for (; lpp; lpp = TAILQ_NEXT(lpp, lp_link)) {
- int rm_installed; /* delete expanded pkg, not @pkgdep value */
- char installed[MaxPathSize];
+ free(best_installed);
+ best_installed = NULL;
/* go to the db dir */
if (chdir(pkgdir) == FAIL) {
@@ -293,13 +296,13 @@ require_delete(char *home, int tryall)
}
/* look to see if package was already deleted */
- rm_installed = 0;
if (ispkgpattern(lpp->lp_name)) {
- if (findmatchingname(".", lpp->lp_name, note_whats_installed, installed) != 1) {
+
+ best_installed = find_best_matching_installed_pkg(lpp->lp_name);
+ if (best_installed == NULL) {
warnx("%s appears to have been deleted", lpp->lp_name);
continue;
}
- rm_installed = 1;
} else {
if (!fexists(lpp->lp_name)) {
warnx("%s appears to have been deleted", lpp->lp_name);
@@ -315,7 +318,7 @@ require_delete(char *home, int tryall)
}
if (Verbose)
- printf("deinstalling %s\n", rm_installed?installed:lpp->lp_name);
+ printf("deinstalling %s\n", best_installed ? best_installed : lpp->lp_name);
/* delete the package */
if (Fake)
@@ -330,18 +333,20 @@ require_delete(char *home, int tryall)
NoDeleteFiles ? "-N" : "",
CleanDirs ? "-d" : "",
Fake ? "-n" : "",
- rm_installed ? installed : lpp->lp_name, NULL);
+ best_installed ? best_installed : lpp->lp_name, NULL);
/* check for delete failure */
if (rv && !tryall) {
fail = 1;
- warnx("had problem removing %s%s", rm_installed?installed:lpp->lp_name,
+ warnx("had problem removing %s%s", best_installed?best_installed:lpp->lp_name,
Force ? ", continuing" : "");
if (!Force)
break;
}
}
+ free(best_installed);
+
/* cleanup list */
while ((lpp = TAILQ_FIRST(&lpdelq))) {
TAILQ_REMOVE(&lpdelq, lpp, lp_link);
@@ -494,18 +499,23 @@ require_find_recursive_down(lpkg_t *thislpp, package_t *plist)
/* prepare for recursion */
chdir(_pkgdb_getPKGDB_DIR());
if (ispkgpattern(lpp->lp_name)) {
- char installed[MaxPathSize];
- if (findmatchingname(".", lpp->lp_name, note_whats_installed, installed) != 1) {
+ char *best_installed;
+
+ best_installed = find_best_matching_installed_pkg(lpp->lp_name);
+
+ if (best_installed == NULL) {
warnx("cannot remove dependency for pkg-pattern %s", lpp->lp_name);
fail = 1;
goto fail;
}
- if (chdir(installed) == -1) {
- warnx("can't chdir to %s", installed);
+ if (chdir(best_installed) == -1) {
+ warnx("can't chdir to %s", best_installed);
+ free(best_installed);
fail = 1;
goto fail;
}
- sanity_check(installed);
+ sanity_check(best_installed);
+ free(best_installed);
} else {
if (chdir(lpp->lp_name) == -1) {
warnx("cannot remove dependency from %s", lpp->lp_name);
@@ -621,17 +631,18 @@ pkg_do(char *pkg)
if (!fexists(LogDir) || !(isdir(LogDir) || islinktodir(LogDir))) {
/* Check if the given package name matches something
* with 'pkg-[0-9]*' */
- char try[MaxPathSize];
lpkg_head_t trypkgs;
lpkg_t *lpp;
int qlen = 0;
TAILQ_INIT(&trypkgs);
- snprintf(try, MaxPathSize, "%s-[0-9]*", pkg);
- if (findmatchingname(_pkgdb_getPKGDB_DIR(), try,
- add_to_list_fn, &trypkgs) == 0) {
+
+ switch (add_installed_pkgs_by_basename(pkg, &trypkgs)) {
+ case 0:
warnx("package '%s' not installed", pkg);
return 1;
+ case -1:
+ errx(EXIT_FAILURE, "Error during search in pkgdb for %s", pkg);
}
TAILQ_FOREACH(lpp, &trypkgs, lp_link)
@@ -796,8 +807,7 @@ pkg_do(char *pkg)
if (Verbose)
printf("Attempting to remove dependency on package `%s'\n", p->name);
if (!Fake)
- findmatchingname(_pkgdb_getPKGDB_DIR(),
- p->name, undepend, pkg);
+ match_installed_pkgs(p->name, undepend, pkg);
}
}
if (Recurse_down) {
diff --git a/pkgtools/pkg_install/files/info/main.c b/pkgtools/pkg_install/files/info/main.c
index f93c411af7a..069e7b92236 100644
--- a/pkgtools/pkg_install/files/info/main.c
+++ b/pkgtools/pkg_install/files/info/main.c
@@ -1,4 +1,4 @@
-/* $NetBSD: main.c,v 1.17 2007/07/26 11:30:56 joerg Exp $ */
+/* $NetBSD: main.c,v 1.18 2007/08/08 22:33:39 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
@@ -11,7 +11,7 @@
#if 0
static char *rcsid = "from FreeBSD Id: main.c,v 1.14 1997/10/08 07:47:26 charnier Exp";
#else
-__RCSID("$NetBSD: main.c,v 1.17 2007/07/26 11:30:56 joerg Exp $");
+__RCSID("$NetBSD: main.c,v 1.18 2007/08/08 22:33:39 joerg Exp $");
#endif
#endif
@@ -282,8 +282,12 @@ main(int argc, char **argv)
errx(EXIT_FAILURE, "No matching pkg for %s.", *argv);
} else {
if (ispkgpattern(*argv)) {
- if (findmatchingname(_pkgdb_getPKGDB_DIR(), *argv, add_to_list_fn, &pkgs) <= 0)
+ switch (add_installed_pkgs_by_pattern(*argv, &pkgs)) {
+ case 0:
errx(EXIT_FAILURE, "No matching pkg for %s.", *argv);
+ case -1:
+ errx(EXIT_FAILURE, "Error during search in pkgdb for %s", *argv);
+ }
} else {
char *dbdir;
diff --git a/pkgtools/pkg_install/files/info/perform.c b/pkgtools/pkg_install/files/info/perform.c
index a297fa8fbd0..0dc4fb16e82 100644
--- a/pkgtools/pkg_install/files/info/perform.c
+++ b/pkgtools/pkg_install/files/info/perform.c
@@ -1,4 +1,4 @@
-/* $NetBSD: perform.c,v 1.32 2007/07/26 11:30:56 joerg Exp $ */
+/* $NetBSD: perform.c,v 1.33 2007/08/08 22:33:39 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
@@ -14,7 +14,7 @@
#if 0
static const char *rcsid = "from FreeBSD Id: perform.c,v 1.23 1997/10/13 15:03:53 jkh Exp";
#else
-__RCSID("$NetBSD: perform.c,v 1.32 2007/07/26 11:30:56 joerg Exp $");
+__RCSID("$NetBSD: perform.c,v 1.33 2007/08/08 22:33:39 joerg Exp $");
#endif
#endif
@@ -179,21 +179,16 @@ pkg_do(char *pkg)
(void) snprintf(log_dir, sizeof(log_dir), "%s/%s",
_pkgdb_getPKGDB_DIR(), pkg);
if (!fexists(log_dir) || !(isdir(log_dir) || islinktodir(log_dir))) {
- {
- /* Check if the given package name matches
- * something with 'pkg-[0-9]*' */
- char try[MaxPathSize];
- snprintf(try, MaxPathSize, "%s-[0-9]*", pkg);
- if (findmatchingname(_pkgdb_getPKGDB_DIR(), try,
- add_to_list_fn, &pkgs) > 0) {
- return 0; /* we've just appended some names to the pkgs list,
- * they will be processed after this package. */
- }
+ switch (add_installed_pkgs_by_basename(pkg, &pkgs)) {
+ case 1:
+ return 0;
+ case 0:
+ /* No match */
+ warnx("can't find package `%s'", pkg);
+ return 1;
+ case -1:
+ errx(EXIT_FAILURE, "Error during search in pkgdb for %s", pkg);
}
-
- /* No match */
- warnx("can't find package `%s'", pkg);
- return 1;
}
if (chdir(log_dir) == FAIL) {
warnx("can't change directory to '%s'!", log_dir);
@@ -322,63 +317,34 @@ bail:
}
/*
- * Function to be called for pkgs found
- */
-static int
-foundpkg(const char *pattern, const char *found, void *vp)
-{
- char *data = vp;
- char buf[MaxPathSize+1];
-
- /* we only want to display this if it really is a directory */
- snprintf(buf, sizeof(buf), "%s/%s", data, found);
- if (!(isdir(buf) || islinktodir(buf))) {
- /* return value seems to be ignored for now */
- return -1;
- }
-
- if (!Quiet) {
- printf("%s\n", found);
- }
-
- return 0;
-}
-
-/*
* Check if a package "pkgspec" (which can be a pattern) is installed.
* dbdir contains the return value of _pkgdb_getPKGDB_DIR(), for reading only.
* Return 0 if found, 1 otherwise (indicating an error).
*/
static int
-CheckForPkg(char *pkgspec, char *dbdir)
+CheckForPkg(const char *pkgname)
{
- char buf[MaxPathSize];
- int error;
+ char *best_installed;
- if (strpbrk(pkgspec, "<>[]?*{")) {
- /* expensive (pattern) match */
- error = findmatchingname(dbdir, pkgspec, foundpkg, dbdir);
- if (error == -1)
- return 1;
- else
- return !error;
- }
- /* simple match */
- (void) snprintf(buf, sizeof(buf), "%s/%s", dbdir, pkgspec);
- error = !(isdir(buf) || islinktodir(buf));
- if (!error && !Quiet) {
- printf("%s\n", pkgspec);
- }
- if (error) {
- /* found nothing - try 'pkg-[0-9]*' */
-
- char try[MaxPathSize];
- snprintf(try, MaxPathSize, "%s-[0-9]*", pkgspec);
- if (findmatchingname(dbdir, try, foundpkg, dbdir) > 0) {
- error = 0;
- }
+ best_installed = find_best_matching_installed_pkg(pkgname);
+ if (best_installed == NULL && !ispkgpattern(pkgname)) {
+ char *pattern;
+
+ if (asprintf(&pattern, "%s-[0-9]*", pkgname) == -1)
+ errx(EXIT_FAILURE, "asprintf failed");
+
+ pkgname = find_best_matching_installed_pkg(pattern);
+ free(pattern);
}
- return error;
+
+ if (best_installed == NULL)
+ return 1;
+
+ if (!Quiet)
+ printf("%s\n", best_installed);
+
+ free(best_installed);
+ return 0;
}
void
@@ -404,7 +370,7 @@ pkg_perform(lpkg_head_t *pkghead)
/* Overriding action? */
if (CheckPkg) {
- err_cnt += CheckForPkg(CheckPkg, dbdir);
+ err_cnt += CheckForPkg(CheckPkg);
} else if (Which != WHICH_LIST) {
if (!(isdir(dbdir) || islinktodir(dbdir)))
return 1;
diff --git a/pkgtools/pkg_install/files/lib/Makefile.in b/pkgtools/pkg_install/files/lib/Makefile.in
index ab0462e0f4e..173be0d7407 100644
--- a/pkgtools/pkg_install/files/lib/Makefile.in
+++ b/pkgtools/pkg_install/files/lib/Makefile.in
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile.in,v 1.15 2007/07/20 22:22:53 joerg Exp $
+# $NetBSD: Makefile.in,v 1.16 2007/08/08 22:33:39 joerg Exp $
srcdir= @srcdir@
@@ -24,8 +24,9 @@ INSTALL= @INSTALL@
LIB= libinstall.a
-OBJS= automatic.o dewey.o fexec.o file.o ftpio.o global.o lpkg.o opattern.o \
- path.o pen.o pexec.o pkgdb.o plist.o str.o var.o version.o
+OBJS= automatic.o dewey.o fexec.o file.o ftpio.o global.o iterate.o \
+ lpkg.o opattern.o path.o pen.o pexec.o pkgdb.o plist.o \
+ str.o var.o version.o
all: $(LIB)
diff --git a/pkgtools/pkg_install/files/lib/iterate.c b/pkgtools/pkg_install/files/lib/iterate.c
new file mode 100644
index 00000000000..ef01749d145
--- /dev/null
+++ b/pkgtools/pkg_install/files/lib/iterate.c
@@ -0,0 +1,328 @@
+/*-
+ * Copyright (c) 2007 Joerg Sonnenberger <joerg@NetBSD.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <nbcompat.h>
+
+#if HAVE_ERR_H
+#include <err.h>
+#endif
+
+#include "lib.h"
+
+#ifndef __UNCONST
+#define __UNCONST(a) ((void *)(unsigned long)(const void *)(a))
+#endif
+
+/*
+ * Generic iteration function:
+ * - get new entries from srciter, stop on NULL
+ * - call matchiter for those entries, stop on non-null return value.
+ */
+int
+iterate_pkg_generic_src(int (*matchiter)(const char *, void *),
+ void *match_cookie, const char *(*srciter)(void *), void *src_cookie)
+{
+ int retval;
+ const char *entry;
+
+ retval = 0;
+
+ while ((entry = (*srciter)(src_cookie)) != NULL) {
+ if ((retval = (*matchiter)(entry, match_cookie)) != 0)
+ break;
+ }
+
+ return retval;
+}
+
+static const char *
+pkg_dir_iter(void *cookie)
+{
+ DIR *dirp = cookie;
+ struct dirent *dp;
+ size_t len;
+
+ while ((dp = readdir(dirp)) != NULL) {
+#if defined(DT_UNKNOWN) && defined(DT_DIR)
+ if (dp->d_type != DT_UNKNOWN && dp->d_type != DT_REG)
+ continue;
+#endif
+ len = strlen(dp->d_name);
+ /* .tbz or .tgz suffix length + some prefix*/
+ if (len < 5)
+ continue;
+ if (memcmp(dp->d_name + len - 4, ".tgz", 4) == 0 ||
+ memcmp(dp->d_name + len - 4, ".tbz", 4) == 0)
+ return dp->d_name;
+ }
+ return NULL;
+}
+
+/*
+ * Call matchiter for every package in the directory.
+ */
+int
+iterate_local_pkg_dir(const char *dir, int (*matchiter)(const char *, void *),
+ void *cookie)
+{
+ DIR *dirp;
+ int retval;
+
+ if ((dirp = opendir(dir)) == NULL)
+ return -1;
+
+ retval = iterate_pkg_generic_src(matchiter, cookie, pkg_dir_iter, dirp);
+
+ if (closedir(dirp) == -1)
+ return -1;
+ return retval;
+}
+
+static const char *
+pkg_db_iter(void *cookie)
+{
+ DIR *dirp = cookie;
+ struct dirent *dp;
+
+ while ((dp = readdir(dirp)) != NULL) {
+ if (strcmp(dp->d_name, ".") == 0)
+ continue;
+ if (strcmp(dp->d_name, "..") == 0)
+ continue;
+ if (strcmp(dp->d_name, "pkgdb.byfile.db") == 0)
+ continue;
+ if (strcmp(dp->d_name, ".cookie") == 0)
+ continue;
+ if (strcmp(dp->d_name, "pkg-vulnerabilities") == 0)
+ continue;
+#if defined(DT_UNKNOWN) && defined(DT_DIR)
+ if (dp->d_type != DT_UNKNOWN && dp->d_type != DT_DIR)
+ continue;
+#endif
+ return dp->d_name;
+ }
+ return NULL;
+}
+
+/*
+ * Call matchiter for every installed package.
+ */
+int
+iterate_pkg_db(int (*matchiter)(const char *, void *), void *cookie)
+{
+ DIR *dirp;
+ int retval;
+
+ if ((dirp = opendir(_pkgdb_getPKGDB_DIR())) == NULL)
+ return -1;
+
+ retval = iterate_pkg_generic_src(matchiter, cookie, pkg_db_iter, dirp);
+
+ if (closedir(dirp) == -1)
+ return -1;
+ return retval;
+}
+
+static int
+match_by_basename(const char *pkg, void *cookie)
+{
+ const char *target = cookie;
+ const char *pkg_version;
+
+ if ((pkg_version = strrchr(pkg, '-')) == NULL) {
+ warnx("Entry %s in pkgdb is not a valid package name", pkg);
+ return 0;
+ }
+ if (strncmp(pkg, target, pkg_version - pkg) == 0 &&
+ strlen(target) == pkg_version - pkg)
+ return 1;
+ else
+ return 0;
+}
+
+static int
+match_by_pattern(const char *pkg, void *cookie)
+{
+ const char *pattern = cookie;
+
+ return pkg_match(pattern, pkg);
+}
+
+struct add_matching_arg {
+ lpkg_head_t *pkghead;
+ size_t got_match;
+ int (*match_fn)(const char *pkg, void *cookie);
+ void *cookie;
+};
+
+static int
+match_and_add(const char *pkg, void *cookie)
+{
+ struct add_matching_arg *arg = cookie;
+ lpkg_t *lpp;
+
+ if ((*arg->match_fn)(pkg, arg->cookie) == 1) {
+ arg->got_match = 1;
+
+ lpp = alloc_lpkg(pkg);
+ TAILQ_INSERT_TAIL(arg->pkghead, lpp, lp_link);
+ }
+ return 0;
+}
+
+/*
+ * Find all installed packages with the given basename and add them
+ * to pkghead.
+ * Returns -1 on error, 0 if no match was found and 1 otherwise.
+ */
+int
+add_installed_pkgs_by_basename(const char *pkgbase, lpkg_head_t *pkghead)
+{
+ struct add_matching_arg arg;
+
+ arg.pkghead = pkghead;
+ arg.got_match = 0;
+ arg.match_fn = match_by_basename;
+ arg.cookie = __UNCONST(pkgbase);
+
+ if (iterate_pkg_db(match_and_add, &arg) == -1) {
+ warnx("could not process pkgdb");
+ return -1;
+ }
+ return arg.got_match;
+}
+
+/*
+ * Match all installed packages against pattern, add the matches to pkghead.
+ * Returns -1 on error, 0 if no match was found and 1 otherwise.
+ */
+int
+add_installed_pkgs_by_pattern(const char *pattern, lpkg_head_t *pkghead)
+{
+ struct add_matching_arg arg;
+
+ arg.pkghead = pkghead;
+ arg.got_match = 0;
+ arg.match_fn = match_by_pattern;
+ arg.cookie = __UNCONST(pattern);
+
+ if (iterate_pkg_db(match_and_add, &arg) == -1) {
+ warnx("could not process pkgdb");
+ return -1;
+ }
+ return arg.got_match;
+}
+
+struct best_installed_match_arg {
+ const char *pattern;
+ char *best_current_match;
+};
+
+static int
+match_best_installed(const char *pkg, void *cookie)
+{
+ struct best_installed_match_arg *arg = cookie;
+
+ switch (pkg_order(arg->pattern, pkg, arg->best_current_match)) {
+ case 0:
+ case 2:
+ /*
+ * Either current package doesn't match or
+ * the older match is better. Nothing to do.
+ */
+ break;
+ case 1:
+ /* Current package is better, remember it. */
+ free(arg->best_current_match);
+ if ((arg->best_current_match = strdup(pkg)) == NULL)
+ return -1;
+ break;
+ }
+ return 0;
+}
+
+/*
+ * Returns a copy of the name of best matching package.
+ * If no package matched the pattern or an error occured, return NULL.
+ */
+char *
+find_best_matching_installed_pkg(const char *pattern)
+{
+ struct best_installed_match_arg arg;
+
+ arg.pattern = pattern;
+ arg.best_current_match = NULL;
+
+ if (iterate_pkg_db(match_best_installed, &arg) == -1) {
+ warnx("could not process pkgdb");
+ return NULL;
+ }
+
+ return arg.best_current_match;
+}
+
+struct call_matching_arg {
+ const char *pattern;
+ int (*call_fn)(const char *pkg, void *cookie);
+ void *cookie;
+};
+
+static int
+match_and_call(const char *pkg, void *cookie)
+{
+ struct call_matching_arg *arg = cookie;
+
+ if (pkg_match(arg->pattern, pkg) == 1) {
+ return (*arg->call_fn)(pkg, arg->cookie);
+ } else
+ return 0;
+}
+
+/*
+ * Find all packages that match the given pattern and call the function
+ * for each of them. Iteration stops if the callback return non-0.
+ * Returns -1 on error, 0 if the iteration finished or whatever the
+ * callback returned otherwise.
+ */
+int
+match_installed_pkgs(const char *pattern, int (*cb)(const char *, void *),
+ void *cookie)
+{
+ struct call_matching_arg arg;
+
+ arg.pattern = pattern;
+ arg.call_fn = cb;
+ arg.cookie = cookie;
+
+ return iterate_pkg_db(match_and_call, &arg);
+}
diff --git a/pkgtools/pkg_install/files/lib/lib.h b/pkgtools/pkg_install/files/lib/lib.h
index da5a56ad26f..f51a4c08b6a 100644
--- a/pkgtools/pkg_install/files/lib/lib.h
+++ b/pkgtools/pkg_install/files/lib/lib.h
@@ -1,4 +1,4 @@
-/* $NetBSD: lib.h,v 1.30 2007/08/03 13:16:00 joerg Exp $ */
+/* $NetBSD: lib.h,v 1.31 2007/08/08 22:33:39 joerg Exp $ */
/* from FreeBSD Id: lib.h,v 1.25 1997/10/08 07:48:03 charnier Exp */
@@ -335,9 +335,18 @@ void strip_txz(char *, char *, const char *);
/* callback functions for findmatchingname */
int findbestmatchingname_fn(const char *, const char *, void *); /* neither */
-int note_whats_installed(const char *, const char *, void *);
-int add_to_list_fn(const char *, const char *, void *);
+/* Iterator functions */
+int iterate_pkg_generic_src(int (*)(const char *, void *), void *,
+ const char *(*)(void *),void *);
+int iterate_local_pkg_dir(const char *, int (*)(const char *, void *),
+ void *);
+int iterate_pkg_db(int (*)(const char *, void *), void *);
+
+int add_installed_pkgs_by_basename(const char *, lpkg_head_t *);
+int add_installed_pkgs_by_pattern(const char *, lpkg_head_t *);
+char *find_best_matching_installed_pkg(const char *);
+int match_installed_pkgs(const char *, int (*)(const char *, void *), void *);
/* File */
Boolean fexists(const char *);
diff --git a/pkgtools/pkg_install/files/lib/str.c b/pkgtools/pkg_install/files/lib/str.c
index d057d8bbf89..622fdbc1872 100644
--- a/pkgtools/pkg_install/files/lib/str.c
+++ b/pkgtools/pkg_install/files/lib/str.c
@@ -1,4 +1,4 @@
-/* $NetBSD: str.c,v 1.19 2007/07/20 22:22:53 joerg Exp $ */
+/* $NetBSD: str.c,v 1.20 2007/08/08 22:33:39 joerg Exp $ */
#if HAVE_CONFIG_H
#include "config.h"
@@ -11,7 +11,7 @@
#if 0
static const char *rcsid = "Id: str.c,v 1.5 1997/10/08 07:48:21 charnier Exp";
#else
-__RCSID("$NetBSD: str.c,v 1.19 2007/07/20 22:22:53 joerg Exp $");
+__RCSID("$NetBSD: str.c,v 1.20 2007/08/08 22:33:39 joerg Exp $");
#endif
#endif
@@ -301,35 +301,3 @@ strip_txz(char *buf, char *sfx, const char *fname)
/* not found */
memcpy(buf, fname, len+1);
}
-
-/*
- * Called to see if pkg is already installed as some other version,
- * note found version in "note".
- */
-int
-note_whats_installed(const char *pattern, const char *found, void *vp)
-{
- char *note = vp;
-
- (void) strlcpy(note, found, MaxPathSize);
- return 0;
-}
-
-/*
- * alloc lpkg for pkg and add it to list.
- */
-int
-add_to_list_fn(const char *pattern, const char *pkg, void *vp)
-{
- lpkg_head_t *pkgs = vp;
- lpkg_t *lpp;
- char fn[MaxPathSize];
-
- snprintf(fn, sizeof(fn), "%s/%s", _pkgdb_getPKGDB_DIR(), pkg);
- if (isdir(fn) || islinktodir(fn)) {
- lpp = alloc_lpkg(pkg);
- TAILQ_INSERT_TAIL(pkgs, lpp, lp_link);
- }
-
- return 0;
-}
diff --git a/pkgtools/pkg_install/files/lib/version.h b/pkgtools/pkg_install/files/lib/version.h
index 90fdd02acfd..d835ba0e46f 100644
--- a/pkgtools/pkg_install/files/lib/version.h
+++ b/pkgtools/pkg_install/files/lib/version.h
@@ -1,4 +1,4 @@
-/* $NetBSD: version.h,v 1.72 2007/08/05 14:58:49 joerg Exp $ */
+/* $NetBSD: version.h,v 1.73 2007/08/08 22:33:40 joerg Exp $ */
/*
* Copyright (c) 2001 Thomas Klausner. All rights reserved.
@@ -33,6 +33,6 @@
#ifndef _INST_LIB_VERSION_H_
#define _INST_LIB_VERSION_H_
-#define PKGTOOLS_VERSION "20070804"
+#define PKGTOOLS_VERSION "20070808"
#endif /* _INST_LIB_VERSION_H_ */