/* $Id: order.c,v 1.9 2009/05/07 21:22:52 imil Exp $ */ /* * Copyright (c) 2009 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 "pkg_dry.h" /* * order.c has only one purpose: arrange lists order in order to satisfy * pkg_add / pkg_delete. */ /* find dependency deepness for package removal and record it to pdp->level */ static void remove_dep_deepness(Deptreehead *deptreehead) { char *depname, *p; Pkgdeptree *pdp, *lvldp; Deptreehead lvldeptree; SLIST_INIT(&lvldeptree); /* get higher recursion level */ SLIST_FOREACH(pdp, deptreehead, next) { if (pdp->level == -1) { /* unique package, just return */ pdp->level = 0; return; } pdp->level = 0; /* depname received from deptreehead is in package format */ XSTRDUP(depname, pdp->depname); if (pdp->depname == NULL) /* there's something wrong with database's record, probably * a mistaken dependency */ continue; if ((p = strrchr(depname, '-')) != NULL) *p = '\0'; full_dep_tree(depname, LOCAL_REVERSE_DEPS, &lvldeptree, __func__, 0); SLIST_FOREACH(lvldp, &lvldeptree, next) pdp->level++; XFREE(depname); free_deptree(&lvldeptree); #if 0 printf("%s -> %d\n", pdp->depname, pdp->level); #endif } } /* order the remove list according to dependency level */ Deptreehead * order_remove(Deptreehead *deptreehead) { int i, maxlevel = 0; Pkgdeptree *pdp, *opdp = NULL; Deptreehead *ordtreehead; /* package removal cannot trust recorded dependencies, reorder */ remove_dep_deepness(deptreehead); SLIST_FOREACH(pdp, deptreehead, next) if (pdp->level > maxlevel) maxlevel = pdp->level; XMALLOC(ordtreehead, sizeof(Deptreehead)); SLIST_INIT(ordtreehead); for (i = maxlevel; i >=0; i--) SLIST_FOREACH(pdp, deptreehead, next) { if (pdp->level == i) { XMALLOC(opdp, sizeof(Pkgdeptree)); memcpy(opdp, pdp, sizeof(Pkgdeptree)); SLIST_INSERT_HEAD(ordtreehead, opdp, next); } } return ordtreehead; } /* find dependency deepness for upgrade and record it to pimpact->level */ static void upgrade_dep_deepness(Impacthead *impacthead) { char *depname, *p; Pkgimpact *pimpact; Pkgdeptree *lvldp; Deptreehead lvldeptree; SLIST_INIT(&lvldeptree); /* get higher recursion level */ SLIST_FOREACH(pimpact, impacthead, next) { if (pimpact->level == -1) { /* unique package, just return */ pimpact->level = 0; return; } if (pimpact->action == TOINSTALL) /* only deal with TOUPGRADE */ continue; pimpact->level = 0; /* depname received from impact is in real dependency format */ depname = end_expr(pimpact->depname); if ((p = strrchr(depname, DELIMITER)) != NULL) *p = '\0'; full_dep_tree(depname, LOCAL_REVERSE_DEPS, &lvldeptree, __func__, 0); SLIST_FOREACH(lvldp, &lvldeptree, next) pimpact->level++; #if 0 printf("%s (%s) -> %d\n", pimpact->depname, depname, pimpact->level); #endif XFREE(depname); free_deptree(&lvldeptree); } } /* order the remove-for-upgrade list according to dependency level */ Deptreehead * order_upgrade_remove(Impacthead *impacthead) { Deptreehead *ordtreehead; Pkgimpact *pimpact; Pkgdeptree *pdp; int i, maxlevel = 0; upgrade_dep_deepness(impacthead); /* record higher dependency level on impact upgrade list */ SLIST_FOREACH(pimpact, impacthead, next) if (pimpact->action == TOUPGRADE && pimpact->level > maxlevel) maxlevel = pimpact->level; XMALLOC(ordtreehead, sizeof(Deptreehead)); SLIST_INIT(ordtreehead); for (i = maxlevel; i >= 0; i--) SLIST_FOREACH(pimpact, impacthead, next) { if (pimpact->action == TOUPGRADE && pimpact->level == i) { XMALLOC(pdp, sizeof(Pkgdeptree)); XSTRDUP(pdp->depname, pimpact->oldpkg); pdp->matchname = NULL; /* safety */ SLIST_INSERT_HEAD(ordtreehead, pdp, next); } } return ordtreehead; } /* * order the install list according to dependency level * here we only rely on basic level given by pkg_summary, the only drawback * is that pkg_add will install direct dependencies, giving a "failed, * package already installed" */ Deptreehead * order_install(Impacthead *impacthead) { Deptreehead *ordtreehead; Pkgimpact *pimpact; Pkgdeptree *pdp; int i, maxlevel = 0; /* record higher dependency level on impact list */ SLIST_FOREACH(pimpact, impacthead, next) { if ((pimpact->action == TOUPGRADE || pimpact->action == TOINSTALL) && pimpact->level > maxlevel) maxlevel = pimpact->level; } XMALLOC(ordtreehead, sizeof(Deptreehead)); SLIST_INIT(ordtreehead); for (i = 0; i <= maxlevel; i++) { SLIST_FOREACH(pimpact, impacthead, next) { if ((pimpact->action == TOUPGRADE || pimpact->action == TOINSTALL) && pimpact->level == i) { XMALLOC(pdp, sizeof(Pkgdeptree)); XSTRDUP(pdp->depname, pimpact->pkgname); pdp->matchname = NULL; /* safety */ pdp->level = pimpact->level; SLIST_INSERT_HEAD(ordtreehead, pdp, next); } } } return ordtreehead; }