/* $Id: depends.c,v 1.21 2011/01/30 10:28:09 imil Exp $ */ /* * Copyright (c) 2009, 2010 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Emile "iMil" Heitor . * * 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 AUTHOR 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 AUTHOR 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. * */ #include "pkgin.h" static Plisthead *plisthead = NULL; void free_deptree(Deptreehead *deptreehead) { Pkgdeptree *pdp; if (deptreehead == NULL) return; while (!SLIST_EMPTY(deptreehead)) { pdp = SLIST_FIRST(deptreehead); SLIST_REMOVE_HEAD(deptreehead, next); XFREE(pdp->depname); XFREE(pdp); } } /* match dependency extension */ char * match_dep_ext(char *depname, const char *ext) { char *pdep = NULL; for (; *ext != 0; ext++) if ((pdep = strrchr(depname, *ext)) != NULL) break; return pdep; } /* basic full package format detection */ int exact_pkgfmt(const char *pkgname) { char *p; if ((p = strrchr(pkgname, '-')) == NULL) return 0; p++; /* naive assumption, will fail with foo-100bar, hopefully, there's * only a few packages needing to be fully specified */ return isdigit((int)*p); } /* sqlite callback * DIRECT_DEPS or REVERSE_DEPS result, feeds a Pkgdeptree SLIST * Deptreehead is the head of Pkgdeptree */ static int pdb_rec_direct_deps(void *param, int argc, char **argv, char **colname) { int argvlen; char *depname; Pkgdeptree *deptree, *pdp; Deptreehead *pdphead = (Deptreehead *)param; if (argv == NULL) return PDB_ERR; depname = end_expr(plisthead, argv[0]); /* foo| */ argvlen = strlen(depname); /* dependency already recorded, do not insert on list */ SLIST_FOREACH(pdp, pdphead, next) { if (strlen(pdp->matchname) + 1 == argvlen && strncmp(depname, pdp->matchname, argvlen - 1) == 0) { XFREE(depname); /* proceed to next result */ return PDB_OK; } } /* remove delimiter */ depname[argvlen - 1] = '\0'; XMALLOC(deptree, sizeof(Pkgdeptree)); XSTRDUP(deptree->depname, argv[0]); deptree->matchname = depname; deptree->computed = 0; deptree->level = 0; /* used in LOCAL_REVERSE_DEPS / autoremove.c */ if (argc > 1 && argv[1] != NULL) deptree->pkgkeep = 1; else deptree->pkgkeep = 0; SLIST_INSERT_HEAD(pdphead, deptree, next); return PDB_OK; } /* recursively parse dependencies: this is our central function */ void full_dep_tree(const char *pkgname, const char * depquery, Deptreehead *pdphead) { Pkgdeptree *pdp; int level; char query[BUFSIZ]; query[0] = '\0'; if (depquery == DIRECT_DEPS) { /* querying remote packages, load remote packages list */ plisthead = rec_pkglist(REMOTE_PKGS_QUERY); /* first package to recurse on and exact pkg name, this is an * exact match due to many versions of the package */ if (exact_pkgfmt(pkgname)) snprintf(query, BUFSIZ, EXACT_DIRECT_DEPS, pkgname); } else if (depquery == LOCAL_REVERSE_DEPS || depquery == LOCAL_DIRECT_DEPS) { /* querying local packages, load local packages list */ plisthead = rec_pkglist(LOCAL_PKGS_QUERY); } else { printf("oops\n"); return; } level = 1; /* getting direct dependencies */ if (query[0] == '\0') snprintf(query, BUFSIZ, depquery, pkgname); if (pkgindb_doquery(query, pdb_rec_direct_deps, pdphead) != 0) return; while (SLIST_FIRST(pdphead)->level == 0) { SLIST_FOREACH(pdp, pdphead, next) { if (pdp->level != 0) break; pdp->level = level; snprintf(query, BUFSIZ, depquery, pdp->matchname); pkgindb_doquery(query, pdb_rec_direct_deps, pdphead); #if 0 printf("%i: p: %s, l: %d\n", level, pdp->depname, pdp->level); #endif } /* SLIST_FOREACH */ ++level; } free_pkglist(plisthead); } void show_direct_depends(const char *pkgname) { char query[BUFSIZ]; Pkgdeptree *pdp; Deptreehead deptreehead; if ((plisthead = rec_pkglist(REMOTE_PKGS_QUERY)) == NULL) { printf("%s\n", MSG_EMPTY_AVAIL_PKGLIST); return; } /* warn if more than one package with this name is available */ if (count_samepkg(plisthead, pkgname) < 2) { SLIST_INIT(&deptreehead); if (exact_pkgfmt(pkgname)) snprintf(query, BUFSIZ, EXACT_DIRECT_DEPS, pkgname); else snprintf(query, BUFSIZ, DIRECT_DEPS, pkgname); if (pkgindb_doquery(query, pdb_rec_direct_deps, &deptreehead) == 0) { printf(MSG_DIRECT_DEPS_FOR, pkgname); SLIST_FOREACH(pdp, &deptreehead, next) { printf("\t%s\n", pdp->depname); } free_deptree(&deptreehead); } } free_pkglist(plisthead); } void show_full_dep_tree(const char *pkgname, const char *depquery, const char *msg) { Pkgdeptree *pdp; Deptreehead deptreehead; /* replacement for SLIST_HEAD() */ int count; const char *pkgquery; if (depquery == LOCAL_REVERSE_DEPS) pkgquery = LOCAL_PKGS_QUERY; else pkgquery = REMOTE_PKGS_QUERY; if ((plisthead = rec_pkglist(pkgquery)) == NULL) errx(EXIT_FAILURE, MSG_EMPTY_AVAIL_PKGLIST); count = count_samepkg(plisthead, pkgname); /* free plisthead now so it is NULL for full_dep_tree() */ free_pkglist(plisthead); if (count > 1) return; SLIST_INIT(&deptreehead); printf(msg, pkgname); full_dep_tree(pkgname, depquery, &deptreehead); SLIST_FOREACH(pdp, &deptreehead, next) printf("\t%s\n", pdp->depname); free_deptree(&deptreehead); }