2005-03-14 20:51:43 -05:00
|
|
|
/*
|
|
|
|
* deps.c
|
2007-11-16 21:18:45 -05:00
|
|
|
*
|
2006-01-02 14:55:35 -05:00
|
|
|
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
|
2006-10-15 15:31:03 -04:00
|
|
|
* Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
|
|
|
|
* Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos@frugalware.org>
|
2007-11-16 21:18:45 -05:00
|
|
|
*
|
2005-03-14 20:51:43 -05:00
|
|
|
* 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
|
2007-11-16 21:18:45 -05:00
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
2005-03-14 20:51:43 -05:00
|
|
|
* USA.
|
|
|
|
*/
|
|
|
|
|
2007-03-05 17:13:33 -05:00
|
|
|
#include "config.h"
|
|
|
|
|
2005-03-14 20:51:43 -05:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
2007-03-05 17:13:33 -05:00
|
|
|
|
|
|
|
/* libalpm */
|
|
|
|
#include "deps.h"
|
|
|
|
#include "alpm_list.h"
|
2005-03-14 20:51:43 -05:00
|
|
|
#include "util.h"
|
|
|
|
#include "log.h"
|
2005-03-30 17:32:43 -05:00
|
|
|
#include "error.h"
|
2005-03-14 20:51:43 -05:00
|
|
|
#include "package.h"
|
|
|
|
#include "db.h"
|
|
|
|
#include "cache.h"
|
2005-04-24 16:06:00 -04:00
|
|
|
#include "handle.h"
|
|
|
|
|
2007-06-10 17:51:20 -04:00
|
|
|
static pmgraph_t *_alpm_graph_new(void)
|
|
|
|
{
|
|
|
|
pmgraph_t *graph = NULL;
|
|
|
|
|
2007-11-14 23:51:47 -05:00
|
|
|
MALLOC(graph, sizeof(pmgraph_t), RET_ERR(PM_ERR_MEMORY, NULL));
|
|
|
|
|
2007-06-10 17:51:20 -04:00
|
|
|
if(graph) {
|
|
|
|
graph->state = 0;
|
|
|
|
graph->data = NULL;
|
|
|
|
graph->parent = NULL;
|
|
|
|
graph->children = NULL;
|
|
|
|
graph->childptr = NULL;
|
|
|
|
}
|
|
|
|
return(graph);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void _alpm_graph_free(void *data)
|
|
|
|
{
|
|
|
|
pmgraph_t *graph = data;
|
|
|
|
alpm_list_free(graph->children);
|
|
|
|
free(graph);
|
|
|
|
}
|
|
|
|
|
2007-11-18 08:25:43 -05:00
|
|
|
pmdepmissing_t *_alpm_depmiss_new(const char *target, pmdepmod_t depmod,
|
|
|
|
const char *depname, const char *depversion)
|
2006-01-15 10:55:16 -05:00
|
|
|
{
|
|
|
|
pmdepmissing_t *miss;
|
|
|
|
|
2007-01-30 03:14:10 -05:00
|
|
|
ALPM_LOG_FUNC;
|
|
|
|
|
2007-10-29 02:00:52 -04:00
|
|
|
MALLOC(miss, sizeof(pmdepmissing_t), RET_ERR(PM_ERR_MEMORY, NULL));
|
2006-01-15 10:55:16 -05:00
|
|
|
|
2007-04-29 12:03:09 -04:00
|
|
|
strncpy(miss->target, target, PKG_NAME_LEN);
|
2006-01-15 10:55:16 -05:00
|
|
|
miss->depend.mod = depmod;
|
2007-04-29 12:03:09 -04:00
|
|
|
strncpy(miss->depend.name, depname, PKG_NAME_LEN);
|
2006-01-18 17:37:16 -05:00
|
|
|
if(depversion) {
|
2007-04-29 12:03:09 -04:00
|
|
|
strncpy(miss->depend.version, depversion, PKG_VERSION_LEN);
|
2006-01-18 17:37:16 -05:00
|
|
|
} else {
|
|
|
|
miss->depend.version[0] = 0;
|
|
|
|
}
|
2006-01-15 10:55:16 -05:00
|
|
|
|
|
|
|
return(miss);
|
|
|
|
}
|
|
|
|
|
2007-07-17 08:23:18 -04:00
|
|
|
/* Convert a list of pmpkg_t * to a graph structure,
|
|
|
|
* with a edge for each dependency.
|
|
|
|
* Returns a list of vertices (one vertex = one package)
|
|
|
|
* (used by alpm_sortbydeps)
|
|
|
|
*/
|
|
|
|
static alpm_list_t *_alpm_graph_init(alpm_list_t *targets)
|
|
|
|
{
|
|
|
|
alpm_list_t *i, *j, *k;
|
|
|
|
alpm_list_t *vertices = NULL;
|
|
|
|
/* We create the vertices */
|
|
|
|
for(i = targets; i; i = i->next) {
|
|
|
|
pmgraph_t *vertex = _alpm_graph_new();
|
|
|
|
vertex->data = (void *)i->data;
|
|
|
|
vertices = alpm_list_add(vertices, vertex);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We compute the edges */
|
|
|
|
for(i = vertices; i; i = i->next) {
|
|
|
|
pmgraph_t *vertex_i = i->data;
|
|
|
|
pmpkg_t *p_i = vertex_i->data;
|
2007-08-12 16:26:54 -04:00
|
|
|
/* TODO this should be somehow combined with alpm_checkdeps */
|
2007-07-17 08:23:18 -04:00
|
|
|
for(j = vertices; j; j = j->next) {
|
|
|
|
pmgraph_t *vertex_j = j->data;
|
|
|
|
pmpkg_t *p_j = vertex_j->data;
|
|
|
|
int child = 0;
|
|
|
|
for(k = alpm_pkg_get_depends(p_i); k && !child; k = k->next) {
|
2007-11-13 00:01:14 -05:00
|
|
|
pmdepend_t *depend = k->data;
|
2007-07-17 08:23:18 -04:00
|
|
|
child = alpm_depcmp(p_j, depend);
|
|
|
|
}
|
|
|
|
if(child) {
|
|
|
|
vertex_i->children =
|
|
|
|
alpm_list_add(vertex_i->children, vertex_j);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
vertex_i->childptr = vertex_i->children;
|
|
|
|
}
|
|
|
|
return(vertices);
|
|
|
|
}
|
|
|
|
|
2005-03-14 20:51:43 -05:00
|
|
|
/* Re-order a list of target packages with respect to their dependencies.
|
|
|
|
*
|
2005-03-25 17:09:14 -05:00
|
|
|
* Example (PM_TRANS_TYPE_ADD):
|
2005-03-14 20:51:43 -05:00
|
|
|
* A depends on C
|
|
|
|
* B depends on A
|
|
|
|
* Target order is A,B,C,D
|
|
|
|
*
|
|
|
|
* Should be re-ordered to C,A,B,D
|
2007-11-16 21:18:45 -05:00
|
|
|
*
|
2005-03-25 17:09:14 -05:00
|
|
|
* mode should be either PM_TRANS_TYPE_ADD or PM_TRANS_TYPE_REMOVE. This
|
|
|
|
* affects the dependency order sortbydeps() will use.
|
|
|
|
*
|
2007-01-19 04:28:44 -05:00
|
|
|
* This function returns the new alpm_list_t* target list.
|
2005-03-14 20:51:43 -05:00
|
|
|
*
|
2007-11-16 21:18:45 -05:00
|
|
|
*/
|
2007-01-31 02:14:50 -05:00
|
|
|
alpm_list_t *_alpm_sortbydeps(alpm_list_t *targets, pmtranstype_t mode)
|
2005-03-14 20:51:43 -05:00
|
|
|
{
|
2007-01-19 04:28:44 -05:00
|
|
|
alpm_list_t *newtargs = NULL;
|
2007-06-10 17:51:20 -04:00
|
|
|
alpm_list_t *vertices = NULL;
|
|
|
|
alpm_list_t *vptr;
|
|
|
|
pmgraph_t *vertex;
|
2005-03-14 20:51:43 -05:00
|
|
|
|
2007-01-30 03:14:10 -05:00
|
|
|
ALPM_LOG_FUNC;
|
|
|
|
|
2005-03-14 20:51:43 -05:00
|
|
|
if(targets == NULL) {
|
|
|
|
return(NULL);
|
|
|
|
}
|
|
|
|
|
2007-08-23 22:26:55 -04:00
|
|
|
_alpm_log(PM_LOG_DEBUG, "started sorting dependencies\n");
|
2007-06-10 17:51:20 -04:00
|
|
|
|
2007-07-17 08:23:18 -04:00
|
|
|
vertices = _alpm_graph_init(targets);
|
2007-01-30 00:41:13 -05:00
|
|
|
|
2007-06-10 17:51:20 -04:00
|
|
|
vptr = vertices;
|
|
|
|
vertex = vertices->data;
|
|
|
|
while(vptr) {
|
|
|
|
/* mark that we touched the vertex */
|
|
|
|
vertex->state = -1;
|
|
|
|
int found = 0;
|
|
|
|
while(vertex->childptr && !found) {
|
|
|
|
pmgraph_t *nextchild = (vertex->childptr)->data;
|
|
|
|
vertex->childptr = (vertex->childptr)->next;
|
|
|
|
if (nextchild->state == 0) {
|
|
|
|
found = 1;
|
|
|
|
nextchild->parent = vertex;
|
|
|
|
vertex = nextchild;
|
|
|
|
}
|
|
|
|
else if(nextchild->state == -1) {
|
2007-11-20 19:03:08 -05:00
|
|
|
pmpkg_t *vertexpkg = vertex->data;
|
|
|
|
pmpkg_t *childpkg = nextchild->data;
|
|
|
|
_alpm_log(PM_LOG_WARNING, _("dependency cycle detected:\n"));
|
|
|
|
if(mode == PM_TRANS_TYPE_REMOVE) {
|
|
|
|
_alpm_log(PM_LOG_WARNING, _("%s will be removed after its %s dependency\n"), vertexpkg->name, childpkg->name);
|
|
|
|
} else {
|
|
|
|
_alpm_log(PM_LOG_WARNING, _("%s will be installed before its %s dependency\n"), vertexpkg->name, childpkg->name);
|
|
|
|
}
|
2007-06-10 17:51:20 -04:00
|
|
|
}
|
2005-03-14 20:51:43 -05:00
|
|
|
}
|
2007-06-10 17:51:20 -04:00
|
|
|
if(!found) {
|
|
|
|
newtargs = alpm_list_add(newtargs, vertex->data);
|
|
|
|
/* mark that we've left this vertex */
|
|
|
|
vertex->state = 1;
|
|
|
|
vertex = vertex->parent;
|
|
|
|
if(!vertex) {
|
|
|
|
vptr = vptr->next;
|
|
|
|
while(vptr) {
|
|
|
|
vertex = vptr->data;
|
|
|
|
if (vertex->state == 0) break;
|
|
|
|
vptr = vptr->next;
|
2005-03-14 20:51:43 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-06-10 17:51:20 -04:00
|
|
|
|
2007-08-23 22:26:55 -04:00
|
|
|
_alpm_log(PM_LOG_DEBUG, "sorting dependencies finished\n");
|
2005-05-04 15:30:00 -04:00
|
|
|
|
2005-03-25 17:09:14 -05:00
|
|
|
if(mode == PM_TRANS_TYPE_REMOVE) {
|
|
|
|
/* we're removing packages, so reverse the order */
|
2007-01-19 04:28:44 -05:00
|
|
|
alpm_list_t *tmptargs = alpm_list_reverse(newtargs);
|
2005-03-25 17:09:14 -05:00
|
|
|
/* free the old one */
|
2007-04-28 03:54:25 -04:00
|
|
|
alpm_list_free(newtargs);
|
2005-05-04 15:30:00 -04:00
|
|
|
newtargs = tmptargs;
|
2005-03-25 17:09:14 -05:00
|
|
|
}
|
|
|
|
|
2007-06-10 17:51:20 -04:00
|
|
|
alpm_list_free_inner(vertices, _alpm_graph_free);
|
2007-09-29 00:22:32 -04:00
|
|
|
alpm_list_free(vertices);
|
2007-06-10 17:51:20 -04:00
|
|
|
|
2005-05-04 15:30:00 -04:00
|
|
|
return(newtargs);
|
2005-03-14 20:51:43 -05:00
|
|
|
}
|
|
|
|
|
2007-11-29 07:54:44 -05:00
|
|
|
/* Little helper function for alpm_list_find */
|
|
|
|
static int satisfycmp(const void *pkg, const void *depend)
|
|
|
|
{
|
|
|
|
return(!alpm_depcmp((pmpkg_t*) pkg, (pmdepend_t*) depend));
|
|
|
|
}
|
|
|
|
|
2007-08-25 19:14:34 -04:00
|
|
|
/** Checks dependencies and returns missing ones in a list.
|
|
|
|
* Dependencies can include versions with depmod operators.
|
2007-02-27 23:00:21 -05:00
|
|
|
* @param db pointer to the local package database
|
2007-08-12 16:26:54 -04:00
|
|
|
* @param reversedeps handles the backward dependencies
|
|
|
|
* @param remove an alpm_list_t* of packages to be removed
|
|
|
|
* @param upgrade an alpm_list_t* of packages to be upgraded (remove-then-upgrade)
|
2007-07-12 15:45:02 -04:00
|
|
|
* @return an alpm_list_t* of pmpkg_t* of missing_t pointers.
|
2005-03-14 20:51:43 -05:00
|
|
|
*/
|
2007-08-12 16:26:54 -04:00
|
|
|
alpm_list_t SYMEXPORT *alpm_checkdeps(pmdb_t *db, int reversedeps,
|
|
|
|
alpm_list_t *remove, alpm_list_t *upgrade)
|
2005-03-14 20:51:43 -05:00
|
|
|
{
|
2007-11-29 07:54:44 -05:00
|
|
|
alpm_list_t *i, *j;
|
|
|
|
alpm_list_t *joined, *dblist;
|
2007-01-19 04:28:44 -05:00
|
|
|
alpm_list_t *baddeps = NULL;
|
2005-03-14 20:51:43 -05:00
|
|
|
pmdepmissing_t *miss = NULL;
|
|
|
|
|
2007-01-30 03:14:10 -05:00
|
|
|
ALPM_LOG_FUNC;
|
|
|
|
|
2005-03-14 20:51:43 -05:00
|
|
|
if(db == NULL) {
|
|
|
|
return(NULL);
|
|
|
|
}
|
|
|
|
|
2007-11-29 07:54:44 -05:00
|
|
|
joined = alpm_list_join(alpm_list_copy(remove), alpm_list_copy(upgrade));
|
|
|
|
dblist = alpm_list_diff(_alpm_db_get_pkgcache(db), joined, _alpm_pkg_cmp);
|
|
|
|
alpm_list_free(joined);
|
|
|
|
|
2007-08-12 16:26:54 -04:00
|
|
|
/* look for unsatisfied dependencies of the upgrade list */
|
|
|
|
for(i = upgrade; i; i = i->next) {
|
|
|
|
pmpkg_t *tp = i->data;
|
|
|
|
_alpm_log(PM_LOG_DEBUG, "checkdeps: package %s-%s\n",
|
|
|
|
alpm_pkg_get_name(tp), alpm_pkg_get_version(tp));
|
|
|
|
|
|
|
|
for(j = alpm_pkg_get_depends(tp); j; j = j->next) {
|
|
|
|
pmdepend_t *depend = j->data;
|
|
|
|
/* 1. we check the upgrade list */
|
|
|
|
/* 2. we check database for untouched satisfying packages */
|
2007-11-29 07:54:44 -05:00
|
|
|
if(!alpm_list_find(upgrade, depend, satisfycmp) &&
|
|
|
|
!alpm_list_find(dblist, depend, satisfycmp)) {
|
|
|
|
/* Unsatisfied dependency in the upgrade list */
|
2007-08-12 16:26:54 -04:00
|
|
|
char *missdepstring = alpm_dep_get_string(depend);
|
2007-11-30 23:57:47 -05:00
|
|
|
_alpm_log(PM_LOG_DEBUG, "checkdeps: missing dependency '%s' for package '%s'\n",
|
2007-08-12 16:26:54 -04:00
|
|
|
missdepstring, alpm_pkg_get_name(tp));
|
|
|
|
free(missdepstring);
|
|
|
|
miss = _alpm_depmiss_new(alpm_pkg_get_name(tp), depend->mod,
|
|
|
|
depend->name, depend->version);
|
2007-11-29 07:54:44 -05:00
|
|
|
baddeps = alpm_list_add(baddeps, miss);
|
2007-08-12 16:26:54 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(reversedeps) {
|
|
|
|
/* reversedeps handles the backwards dependencies, ie,
|
|
|
|
* the packages listed in the requiredby field. */
|
|
|
|
|
2007-11-29 07:54:44 -05:00
|
|
|
alpm_list_t *modified = alpm_list_diff(_alpm_db_get_pkgcache(db), dblist, _alpm_pkg_cmp);
|
2005-03-14 20:51:43 -05:00
|
|
|
|
2007-11-29 07:54:44 -05:00
|
|
|
for(i = dblist; i; i = i->next) {
|
|
|
|
pmpkg_t *lp = i->data;
|
|
|
|
for(j = alpm_pkg_get_depends(lp); j; j = j->next) {
|
|
|
|
pmdepend_t *depend = j->data;
|
|
|
|
/* we won't break this depend, if it is already broken, we ignore it */
|
|
|
|
/* 1. check upgrade list for satisfiers */
|
|
|
|
/* 2. check dblist for satisfiers */
|
|
|
|
if(alpm_list_find(modified, depend, satisfycmp) &&
|
|
|
|
!alpm_list_find(upgrade, depend, satisfycmp) &&
|
|
|
|
!alpm_list_find(dblist, depend, satisfycmp)) {
|
2007-08-12 16:26:54 -04:00
|
|
|
char *missdepstring = alpm_dep_get_string(depend);
|
2007-11-30 23:57:47 -05:00
|
|
|
_alpm_log(PM_LOG_DEBUG, "checkdeps: transaction would break '%s' dependency of '%s'\n",
|
2007-11-29 07:54:44 -05:00
|
|
|
missdepstring, alpm_pkg_get_name(lp));
|
2007-08-12 16:26:54 -04:00
|
|
|
free(missdepstring);
|
2007-11-29 07:54:44 -05:00
|
|
|
miss = _alpm_depmiss_new(lp->name, depend->mod,
|
2007-11-18 08:25:43 -05:00
|
|
|
depend->name, depend->version);
|
2007-11-29 07:54:44 -05:00
|
|
|
baddeps = alpm_list_add(baddeps, miss);
|
2005-03-14 20:51:43 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-11-29 07:54:44 -05:00
|
|
|
alpm_list_free(modified);
|
2005-03-14 20:51:43 -05:00
|
|
|
}
|
2007-11-29 07:54:44 -05:00
|
|
|
alpm_list_free(dblist);
|
2005-03-14 20:51:43 -05:00
|
|
|
|
|
|
|
return(baddeps);
|
|
|
|
}
|
|
|
|
|
2007-10-29 01:01:17 -04:00
|
|
|
static int dep_vercmp(const char *version1, pmdepmod_t mod,
|
2007-07-16 12:27:42 -04:00
|
|
|
const char *version2)
|
|
|
|
{
|
|
|
|
int equal = 0;
|
|
|
|
|
|
|
|
if(mod == PM_DEP_MOD_ANY) {
|
|
|
|
equal = 1;
|
|
|
|
} else {
|
|
|
|
int cmp = _alpm_versioncmp(version1, version2);
|
|
|
|
switch(mod) {
|
|
|
|
case PM_DEP_MOD_EQ: equal = (cmp == 0); break;
|
|
|
|
case PM_DEP_MOD_GE: equal = (cmp >= 0); break;
|
|
|
|
case PM_DEP_MOD_LE: equal = (cmp <= 0); break;
|
|
|
|
default: equal = 1; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return(equal);
|
|
|
|
}
|
|
|
|
|
2007-07-12 15:20:43 -04:00
|
|
|
int SYMEXPORT alpm_depcmp(pmpkg_t *pkg, pmdepend_t *dep)
|
|
|
|
{
|
2007-11-16 16:37:57 -05:00
|
|
|
alpm_list_t *i;
|
2007-07-12 15:20:43 -04:00
|
|
|
|
|
|
|
ALPM_LOG_FUNC;
|
|
|
|
|
2007-07-16 12:27:42 -04:00
|
|
|
const char *pkgname = alpm_pkg_get_name(pkg);
|
|
|
|
const char *pkgversion = alpm_pkg_get_version(pkg);
|
2007-11-16 16:37:57 -05:00
|
|
|
int satisfy = 0;
|
2007-07-16 12:27:42 -04:00
|
|
|
|
2007-11-16 16:37:57 -05:00
|
|
|
/* check (pkg->name, pkg->version) */
|
|
|
|
satisfy = (strcmp(pkgname, dep->name) == 0
|
|
|
|
&& dep_vercmp(pkgversion, dep->mod, dep->version));
|
2007-07-16 12:27:42 -04:00
|
|
|
|
2007-11-16 16:37:57 -05:00
|
|
|
/* check provisions, format : "name version" */
|
|
|
|
for(i = alpm_pkg_get_provides(pkg); i && !satisfy; i = i->next) {
|
|
|
|
char *provname = strdup(i->data);
|
|
|
|
char *provver = strchr(provname, ' ');
|
2007-07-12 15:20:43 -04:00
|
|
|
|
2007-11-16 16:37:57 -05:00
|
|
|
if(provver == NULL) { /* no provision version */
|
|
|
|
satisfy = (dep->mod == PM_DEP_MOD_ANY
|
|
|
|
&& strcmp(provname, dep->name) == 0);
|
2007-07-12 15:20:43 -04:00
|
|
|
} else {
|
2007-11-16 16:37:57 -05:00
|
|
|
/* replace the space with a NULL byte, and advance ptr the version */
|
|
|
|
*provver = '\0';
|
|
|
|
provver += 1;
|
|
|
|
satisfy = (strcmp(provname, dep->name) == 0
|
|
|
|
&& dep_vercmp(provver, dep->mod, dep->version));
|
2007-07-12 15:20:43 -04:00
|
|
|
}
|
2007-11-16 16:37:57 -05:00
|
|
|
free(provname);
|
2007-07-12 15:20:43 -04:00
|
|
|
}
|
|
|
|
|
2007-11-16 16:37:57 -05:00
|
|
|
return(satisfy);
|
2007-07-12 15:20:43 -04:00
|
|
|
}
|
|
|
|
|
2007-03-11 17:10:02 -04:00
|
|
|
pmdepend_t SYMEXPORT *alpm_splitdep(const char *depstring)
|
2005-03-14 20:51:43 -05:00
|
|
|
{
|
2007-03-03 04:43:16 -05:00
|
|
|
pmdepend_t *depend;
|
|
|
|
char *ptr = NULL;
|
2007-06-18 10:32:38 -04:00
|
|
|
char *newstr = NULL;
|
2005-03-14 20:51:43 -05:00
|
|
|
|
2007-03-03 04:43:16 -05:00
|
|
|
if(depstring == NULL) {
|
|
|
|
return(NULL);
|
|
|
|
}
|
2007-06-18 10:32:38 -04:00
|
|
|
newstr = strdup(depstring);
|
2007-11-16 21:18:45 -05:00
|
|
|
|
2007-10-29 02:00:52 -04:00
|
|
|
MALLOC(depend, sizeof(pmdepend_t), return(NULL));
|
2005-03-14 20:51:43 -05:00
|
|
|
|
2007-03-03 04:43:16 -05:00
|
|
|
/* Find a version comparator if one exists. If it does, set the type and
|
|
|
|
* increment the ptr accordingly so we can copy the right strings. */
|
2007-06-18 10:32:38 -04:00
|
|
|
if((ptr = strstr(newstr, ">="))) {
|
2005-03-29 15:31:03 -05:00
|
|
|
depend->mod = PM_DEP_MOD_GE;
|
2007-03-03 04:43:16 -05:00
|
|
|
*ptr = '\0';
|
|
|
|
ptr += 2;
|
2007-06-18 10:32:38 -04:00
|
|
|
} else if((ptr = strstr(newstr, "<="))) {
|
2005-03-29 15:31:03 -05:00
|
|
|
depend->mod = PM_DEP_MOD_LE;
|
2007-03-03 04:43:16 -05:00
|
|
|
*ptr = '\0';
|
|
|
|
ptr += 2;
|
2007-06-18 10:32:38 -04:00
|
|
|
} else if((ptr = strstr(newstr, "="))) {
|
2005-03-29 15:31:03 -05:00
|
|
|
depend->mod = PM_DEP_MOD_EQ;
|
2007-03-03 04:43:16 -05:00
|
|
|
*ptr = '\0';
|
|
|
|
ptr += 1;
|
2005-03-14 20:51:43 -05:00
|
|
|
} else {
|
2007-03-03 04:43:16 -05:00
|
|
|
/* no version specified - copy in the name and return it */
|
2005-03-29 15:31:03 -05:00
|
|
|
depend->mod = PM_DEP_MOD_ANY;
|
2007-06-18 10:32:38 -04:00
|
|
|
strncpy(depend->name, newstr, PKG_NAME_LEN);
|
2007-03-03 04:43:16 -05:00
|
|
|
depend->version[0] = '\0';
|
2007-06-18 10:32:38 -04:00
|
|
|
free(newstr);
|
2007-03-03 04:43:16 -05:00
|
|
|
return(depend);
|
2005-03-14 20:51:43 -05:00
|
|
|
}
|
2007-02-18 13:29:28 -05:00
|
|
|
|
2007-03-03 04:43:16 -05:00
|
|
|
/* if we get here, we have a version comparator, copy the right parts
|
|
|
|
* to the right places */
|
2007-06-18 10:32:38 -04:00
|
|
|
strncpy(depend->name, newstr, PKG_NAME_LEN);
|
2007-03-03 04:43:16 -05:00
|
|
|
strncpy(depend->version, ptr, PKG_VERSION_LEN);
|
2007-06-18 10:32:38 -04:00
|
|
|
free(newstr);
|
2005-03-14 20:51:43 -05:00
|
|
|
|
2007-03-03 04:43:16 -05:00
|
|
|
return(depend);
|
2005-03-14 20:51:43 -05:00
|
|
|
}
|
|
|
|
|
2007-07-13 09:30:37 -04:00
|
|
|
/* These parameters are messy. We check if this package, given a list of
|
|
|
|
* targets and a db is safe to remove. We do NOT remove it if it is in the
|
|
|
|
* target list, or if if the package was explictly installed and
|
|
|
|
* include_explicit == 0 */
|
|
|
|
static int can_remove_package(pmdb_t *db, pmpkg_t *pkg, alpm_list_t *targets,
|
|
|
|
int include_explicit)
|
2007-02-20 03:44:32 -05:00
|
|
|
{
|
2007-11-12 20:40:08 -05:00
|
|
|
alpm_list_t *i, *requiredby;
|
2007-02-20 03:44:32 -05:00
|
|
|
|
2007-03-03 03:13:59 -05:00
|
|
|
if(_alpm_pkg_find(alpm_pkg_get_name(pkg), targets)) {
|
2007-02-20 03:44:32 -05:00
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
2007-07-13 09:30:37 -04:00
|
|
|
if(!include_explicit) {
|
|
|
|
/* see if it was explicitly installed */
|
|
|
|
if(alpm_pkg_get_reason(pkg) == PM_PKG_REASON_EXPLICIT) {
|
2007-08-23 22:26:55 -04:00
|
|
|
_alpm_log(PM_LOG_DEBUG, "excluding %s -- explicitly installed\n",
|
2007-07-13 09:30:37 -04:00
|
|
|
alpm_pkg_get_name(pkg));
|
|
|
|
return(0);
|
|
|
|
}
|
2007-02-20 03:44:32 -05:00
|
|
|
}
|
|
|
|
|
2007-07-13 09:30:37 -04:00
|
|
|
/* TODO: checkdeps could be used here, it handles multiple providers
|
|
|
|
* better, but that also makes it slower.
|
|
|
|
* Also this would require to first add the package to the targets list,
|
|
|
|
* then call checkdeps with it, then remove the package from the targets list
|
|
|
|
* if checkdeps detected it would break something */
|
|
|
|
|
2007-02-20 03:44:32 -05:00
|
|
|
/* see if other packages need it */
|
2007-11-12 20:40:08 -05:00
|
|
|
requiredby = alpm_pkg_compute_requiredby(pkg);
|
|
|
|
for(i = requiredby; i; i = i->next) {
|
2007-02-20 03:44:32 -05:00
|
|
|
pmpkg_t *reqpkg = _alpm_db_get_pkgfromcache(db, i->data);
|
2007-03-03 03:13:59 -05:00
|
|
|
if(reqpkg && !_alpm_pkg_find(alpm_pkg_get_name(reqpkg), targets)) {
|
2007-11-15 09:05:10 -05:00
|
|
|
FREELIST(requiredby);
|
2007-02-20 03:44:32 -05:00
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
}
|
2007-11-12 20:40:08 -05:00
|
|
|
FREELIST(requiredby);
|
2007-02-20 03:44:32 -05:00
|
|
|
|
|
|
|
/* it's ok to remove */
|
|
|
|
return(1);
|
|
|
|
}
|
|
|
|
|
2007-07-13 09:30:37 -04:00
|
|
|
/**
|
|
|
|
* @brief Adds unneeded dependencies to an existing list of packages.
|
|
|
|
* By unneeded, we mean dependencies that are only required by packages in the
|
|
|
|
* target list, so they can be safely removed.
|
2007-11-14 06:42:15 -05:00
|
|
|
* If the input list was topo sorted, the output list will be topo sorted too.
|
2007-07-13 09:30:37 -04:00
|
|
|
*
|
|
|
|
* @param db package database to do dependency tracing in
|
|
|
|
* @param *targs pointer to a list of packages
|
|
|
|
* @param include_explicit if 0, explicitly installed packages are not included
|
2005-03-14 20:51:43 -05:00
|
|
|
*/
|
2007-11-14 06:42:15 -05:00
|
|
|
void _alpm_recursedeps(pmdb_t *db, alpm_list_t *targs, int include_explicit)
|
2005-03-14 20:51:43 -05:00
|
|
|
{
|
2007-01-19 04:28:44 -05:00
|
|
|
alpm_list_t *i, *j, *k;
|
2005-03-14 20:51:43 -05:00
|
|
|
|
2007-01-30 03:14:10 -05:00
|
|
|
ALPM_LOG_FUNC;
|
|
|
|
|
2007-07-13 09:30:37 -04:00
|
|
|
if(db == NULL || targs == NULL) {
|
|
|
|
return;
|
2005-03-14 20:51:43 -05:00
|
|
|
}
|
|
|
|
|
2007-11-14 06:42:15 -05:00
|
|
|
for(i = targs; i; i = i->next) {
|
|
|
|
pmpkg_t *pkg = i->data;
|
|
|
|
for(j = alpm_pkg_get_depends(pkg); j; j = j->next) {
|
2007-11-13 00:01:14 -05:00
|
|
|
pmdepend_t *depend = j->data;
|
|
|
|
|
2007-11-14 06:42:15 -05:00
|
|
|
for(k = _alpm_db_get_pkgcache(db); k; k = k->next) {
|
|
|
|
pmpkg_t *deppkg = k->data;
|
|
|
|
if(alpm_depcmp(deppkg,depend)
|
|
|
|
&& can_remove_package(db, deppkg, targs, include_explicit)) {
|
|
|
|
_alpm_log(PM_LOG_DEBUG, "adding '%s' to the targets\n",
|
|
|
|
alpm_pkg_get_name(deppkg));
|
2007-02-20 03:44:32 -05:00
|
|
|
/* add it to the target list */
|
2007-11-14 06:42:15 -05:00
|
|
|
targs = alpm_list_add(targs, _alpm_pkg_dup(deppkg));
|
2005-03-14 20:51:43 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* populates *list with packages that need to be installed to satisfy all
|
2005-04-06 14:29:17 -04:00
|
|
|
* dependencies (recursive) for syncpkg
|
2005-03-14 20:51:43 -05:00
|
|
|
*
|
2007-08-12 16:26:54 -04:00
|
|
|
* @param remove contains packages elected for removal
|
2007-07-13 17:03:23 -04:00
|
|
|
* make sure **list is already initialized
|
2005-03-14 20:51:43 -05:00
|
|
|
*/
|
2007-01-23 22:02:53 -05:00
|
|
|
int _alpm_resolvedeps(pmdb_t *local, alpm_list_t *dbs_sync, pmpkg_t *syncpkg,
|
2007-08-12 16:26:54 -04:00
|
|
|
alpm_list_t **list, alpm_list_t *remove, pmtrans_t *trans, alpm_list_t **data)
|
2005-03-14 20:51:43 -05:00
|
|
|
{
|
2007-07-13 17:03:23 -04:00
|
|
|
alpm_list_t *i, *j, *k;
|
2007-01-19 04:28:44 -05:00
|
|
|
alpm_list_t *targ;
|
|
|
|
alpm_list_t *deps = NULL;
|
2005-03-14 20:51:43 -05:00
|
|
|
|
2007-01-30 03:14:10 -05:00
|
|
|
ALPM_LOG_FUNC;
|
|
|
|
|
2007-07-13 17:03:23 -04:00
|
|
|
if(local == NULL || dbs_sync == NULL || syncpkg == NULL || list == NULL) {
|
2005-04-02 15:30:09 -05:00
|
|
|
return(-1);
|
|
|
|
}
|
2005-03-30 17:32:43 -05:00
|
|
|
|
2007-08-23 22:26:55 -04:00
|
|
|
_alpm_log(PM_LOG_DEBUG, "started resolving dependencies\n");
|
2007-01-19 04:28:44 -05:00
|
|
|
targ = alpm_list_add(NULL, syncpkg);
|
2007-08-12 16:26:54 -04:00
|
|
|
deps = alpm_checkdeps(local, 0, remove, targ);
|
2007-04-28 03:54:25 -04:00
|
|
|
alpm_list_free(targ);
|
2005-03-14 20:51:43 -05:00
|
|
|
|
|
|
|
if(deps == NULL) {
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
for(i = deps; i; i = i->next) {
|
|
|
|
int found = 0;
|
|
|
|
pmdepmissing_t *miss = i->data;
|
2007-07-13 17:03:23 -04:00
|
|
|
pmdepend_t *missdep = &(miss->depend);
|
2006-01-15 10:55:16 -05:00
|
|
|
pmpkg_t *sync = NULL;
|
2005-03-14 20:51:43 -05:00
|
|
|
|
2007-07-13 17:03:23 -04:00
|
|
|
/* check if one of the packages in *list already satisfies this dependency */
|
|
|
|
for(j = *list; j && !found; j = j->next) {
|
2007-03-03 03:13:59 -05:00
|
|
|
pmpkg_t *sp = j->data;
|
2007-07-13 17:03:23 -04:00
|
|
|
if(alpm_depcmp(sp, missdep)) {
|
2007-10-26 19:14:35 -04:00
|
|
|
char *missdepstring = alpm_dep_get_string(missdep);
|
2007-08-23 22:26:55 -04:00
|
|
|
_alpm_log(PM_LOG_DEBUG, "%s satisfies dependency %s -- skipping\n",
|
2007-10-26 19:14:35 -04:00
|
|
|
alpm_pkg_get_name(sp), missdepstring);
|
|
|
|
free(missdepstring);
|
2006-01-18 17:37:16 -05:00
|
|
|
found = 1;
|
2005-10-21 15:55:24 -04:00
|
|
|
}
|
2006-01-15 10:55:16 -05:00
|
|
|
}
|
2006-01-18 17:37:16 -05:00
|
|
|
if(found) {
|
2006-01-15 10:55:16 -05:00
|
|
|
continue;
|
|
|
|
}
|
2005-10-21 15:55:24 -04:00
|
|
|
|
2006-01-15 10:55:16 -05:00
|
|
|
/* find the package in one of the repositories */
|
|
|
|
/* check literals */
|
2007-07-13 17:03:23 -04:00
|
|
|
for(j = dbs_sync; j && !found; j = j->next) {
|
2007-08-12 17:41:30 -04:00
|
|
|
sync = _alpm_db_get_pkgfromcache(j->data, missdep->name);
|
|
|
|
if(!sync) {
|
|
|
|
continue;
|
|
|
|
}
|
2007-08-12 16:26:54 -04:00
|
|
|
found = alpm_depcmp(sync, missdep) && !_alpm_pkg_find(alpm_pkg_get_name(sync), remove);
|
2007-08-12 17:41:30 -04:00
|
|
|
if(!found) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/* If package is in the ignorepkg list, ask before we pull it */
|
|
|
|
if(_alpm_pkg_should_ignore(sync)) {
|
|
|
|
pmpkg_t *dummypkg = _alpm_pkg_new(miss->target, NULL);
|
|
|
|
QUESTION(trans, PM_TRANS_CONV_INSTALL_IGNOREPKG, dummypkg, sync, NULL, &found);
|
|
|
|
_alpm_pkg_free(dummypkg);
|
2007-07-13 17:03:23 -04:00
|
|
|
}
|
2006-01-15 10:55:16 -05:00
|
|
|
}
|
2007-07-13 17:03:23 -04:00
|
|
|
/*TODO this autoresolves the first 'satisfier' package... we should fix this
|
2007-03-03 03:13:59 -05:00
|
|
|
* somehow */
|
2006-01-15 10:55:16 -05:00
|
|
|
/* check provides */
|
2007-12-05 06:02:41 -05:00
|
|
|
/* we don't check literals again to avoid duplicated PM_TRANS_CONV_INSTALL_IGNOREPKG messages */
|
2007-07-13 17:03:23 -04:00
|
|
|
for(j = dbs_sync; j && !found; j = j->next) {
|
|
|
|
for(k = _alpm_db_get_pkgcache(j->data); k && !found; k = k->next) {
|
|
|
|
sync = k->data;
|
2007-08-12 17:41:30 -04:00
|
|
|
if(!sync) {
|
|
|
|
continue;
|
|
|
|
}
|
2007-12-05 06:02:41 -05:00
|
|
|
found = alpm_depcmp(sync, missdep) && strcmp(sync->name, missdep->name)
|
|
|
|
&& !_alpm_pkg_find(alpm_pkg_get_name(sync), remove);
|
2007-08-12 17:41:30 -04:00
|
|
|
if(!found) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if(_alpm_pkg_should_ignore(sync)) {
|
|
|
|
pmpkg_t *dummypkg = _alpm_pkg_new(miss->target, NULL);
|
|
|
|
QUESTION(trans, PM_TRANS_CONV_INSTALL_IGNOREPKG, dummypkg, sync, NULL, &found);
|
|
|
|
_alpm_pkg_free(dummypkg);
|
|
|
|
}
|
2005-03-14 20:51:43 -05:00
|
|
|
}
|
2006-01-15 10:55:16 -05:00
|
|
|
}
|
2007-03-03 03:13:59 -05:00
|
|
|
|
2007-07-13 17:03:23 -04:00
|
|
|
if(!found) {
|
2007-10-26 19:14:35 -04:00
|
|
|
char *missdepstring = alpm_dep_get_string(missdep);
|
|
|
|
_alpm_log(PM_LOG_ERROR, _("cannot resolve \"%s\", a dependency of \"%s\"\n"),
|
|
|
|
missdepstring, miss->target);
|
|
|
|
free(missdepstring);
|
2006-01-21 13:28:38 -05:00
|
|
|
if(data) {
|
2007-12-02 18:24:22 -05:00
|
|
|
MALLOC(miss, sizeof(pmdepmissing_t),/*nothing*/);
|
2007-11-26 10:54:47 -05:00
|
|
|
if(!miss) {
|
2006-01-21 13:28:38 -05:00
|
|
|
pm_errno = PM_ERR_MEMORY;
|
2007-11-26 10:54:47 -05:00
|
|
|
FREELIST(*data);
|
2006-01-21 13:28:38 -05:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
*miss = *(pmdepmissing_t *)i->data;
|
2007-01-19 04:28:44 -05:00
|
|
|
*data = alpm_list_add(*data, miss);
|
2006-01-21 13:28:38 -05:00
|
|
|
}
|
|
|
|
pm_errno = PM_ERR_UNSATISFIED_DEPS;
|
2006-01-15 10:55:16 -05:00
|
|
|
goto error;
|
2007-08-12 17:41:30 -04:00
|
|
|
} else {
|
2007-08-23 22:26:55 -04:00
|
|
|
_alpm_log(PM_LOG_DEBUG, "pulling dependency %s (needed by %s)\n",
|
2007-07-13 17:03:23 -04:00
|
|
|
alpm_pkg_get_name(sync), alpm_pkg_get_name(syncpkg));
|
|
|
|
*list = alpm_list_add(*list, sync);
|
2007-08-12 16:26:54 -04:00
|
|
|
if(_alpm_resolvedeps(local, dbs_sync, sync, list, remove, trans, data)) {
|
2007-07-13 17:03:23 -04:00
|
|
|
goto error;
|
2005-03-14 20:51:43 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-11-16 21:18:45 -05:00
|
|
|
|
2007-08-23 22:26:55 -04:00
|
|
|
_alpm_log(PM_LOG_DEBUG, "finished resolving dependencies\n");
|
2005-03-14 20:51:43 -05:00
|
|
|
|
|
|
|
FREELIST(deps);
|
|
|
|
|
|
|
|
return(0);
|
|
|
|
|
|
|
|
error:
|
|
|
|
FREELIST(deps);
|
|
|
|
return(-1);
|
|
|
|
}
|
|
|
|
|
2007-11-12 23:48:15 -05:00
|
|
|
const char SYMEXPORT *alpm_miss_get_target(const pmdepmissing_t *miss)
|
2006-11-22 04:03:41 -05:00
|
|
|
{
|
2007-01-30 03:14:10 -05:00
|
|
|
ALPM_LOG_FUNC;
|
|
|
|
|
2006-11-22 04:03:41 -05:00
|
|
|
/* Sanity checks */
|
|
|
|
ASSERT(miss != NULL, return(NULL));
|
|
|
|
|
|
|
|
return miss->target;
|
|
|
|
}
|
|
|
|
|
2007-07-16 08:08:48 -04:00
|
|
|
pmdepend_t SYMEXPORT *alpm_miss_get_dep(pmdepmissing_t *miss)
|
2006-11-22 04:03:41 -05:00
|
|
|
{
|
2007-01-30 03:14:10 -05:00
|
|
|
ALPM_LOG_FUNC;
|
|
|
|
|
2006-11-22 04:03:41 -05:00
|
|
|
/* Sanity checks */
|
2007-07-16 08:08:48 -04:00
|
|
|
ASSERT(miss != NULL, return(NULL));
|
2006-11-22 04:03:41 -05:00
|
|
|
|
2007-11-13 00:01:14 -05:00
|
|
|
return &(miss->depend);
|
2006-11-22 04:03:41 -05:00
|
|
|
}
|
|
|
|
|
2007-11-12 23:48:15 -05:00
|
|
|
pmdepmod_t SYMEXPORT alpm_dep_get_mod(const pmdepend_t *dep)
|
2006-11-22 04:03:41 -05:00
|
|
|
{
|
2007-01-30 03:14:10 -05:00
|
|
|
ALPM_LOG_FUNC;
|
|
|
|
|
2006-11-22 04:03:41 -05:00
|
|
|
/* Sanity checks */
|
2007-07-16 08:08:48 -04:00
|
|
|
ASSERT(dep != NULL, return(-1));
|
2006-11-22 04:03:41 -05:00
|
|
|
|
2007-07-16 08:08:48 -04:00
|
|
|
return dep->mod;
|
2006-11-22 04:03:41 -05:00
|
|
|
}
|
|
|
|
|
2007-11-12 23:48:15 -05:00
|
|
|
const char SYMEXPORT *alpm_dep_get_name(const pmdepend_t *dep)
|
2006-11-22 04:03:41 -05:00
|
|
|
{
|
2007-01-30 03:14:10 -05:00
|
|
|
ALPM_LOG_FUNC;
|
|
|
|
|
2006-11-22 04:03:41 -05:00
|
|
|
/* Sanity checks */
|
2007-07-16 08:08:48 -04:00
|
|
|
ASSERT(dep != NULL, return(NULL));
|
2006-11-22 04:03:41 -05:00
|
|
|
|
2007-07-16 08:08:48 -04:00
|
|
|
return dep->name;
|
2006-11-22 04:03:41 -05:00
|
|
|
}
|
2007-06-29 05:41:48 -04:00
|
|
|
|
2007-11-12 23:48:15 -05:00
|
|
|
const char SYMEXPORT *alpm_dep_get_version(const pmdepend_t *dep)
|
2007-06-29 05:41:48 -04:00
|
|
|
{
|
|
|
|
ALPM_LOG_FUNC;
|
|
|
|
|
|
|
|
/* Sanity checks */
|
|
|
|
ASSERT(dep != NULL, return(NULL));
|
|
|
|
|
2007-07-16 08:08:48 -04:00
|
|
|
return dep->version;
|
2007-06-29 05:41:48 -04:00
|
|
|
}
|
|
|
|
|
2007-11-12 23:48:15 -05:00
|
|
|
/** Reverse of splitdep; make a dep string from a pmdepend_t struct.
|
|
|
|
* The string must be freed!
|
|
|
|
* @param dep the depend to turn into a string
|
|
|
|
* @return a string-formatted dependency with operator if necessary
|
|
|
|
*/
|
|
|
|
char SYMEXPORT *alpm_dep_get_string(const pmdepend_t *dep)
|
2007-10-24 20:31:28 -04:00
|
|
|
{
|
2007-11-12 23:48:15 -05:00
|
|
|
char *opr, *str = NULL;
|
|
|
|
size_t len;
|
|
|
|
|
2007-10-24 20:31:28 -04:00
|
|
|
ALPM_LOG_FUNC;
|
|
|
|
|
|
|
|
/* Sanity checks */
|
|
|
|
ASSERT(dep != NULL, return(NULL));
|
|
|
|
|
|
|
|
switch(dep->mod) {
|
|
|
|
case PM_DEP_MOD_ANY:
|
2007-11-12 23:48:15 -05:00
|
|
|
opr = "";
|
2007-10-24 20:31:28 -04:00
|
|
|
break;
|
|
|
|
case PM_DEP_MOD_GE:
|
2007-11-12 23:48:15 -05:00
|
|
|
opr = ">=";
|
2007-10-24 20:31:28 -04:00
|
|
|
break;
|
|
|
|
case PM_DEP_MOD_LE:
|
2007-11-12 23:48:15 -05:00
|
|
|
opr = "<=";
|
|
|
|
break;
|
|
|
|
case PM_DEP_MOD_EQ:
|
|
|
|
opr = "=";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
opr = "";
|
2007-10-24 20:31:28 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-11-12 23:48:15 -05:00
|
|
|
/* we can always compute len and print the string like this because opr
|
|
|
|
* and ver will be empty when PM_DEP_MOD_ANY is the depend type */
|
|
|
|
len = strlen(dep->name) + strlen(opr) + strlen(dep->version) + 1;
|
|
|
|
MALLOC(str, len, RET_ERR(PM_ERR_MEMORY, NULL));
|
|
|
|
snprintf(str, len, "%s%s%s", dep->name, opr, dep->version);
|
|
|
|
|
|
|
|
return(str);
|
2007-10-24 20:31:28 -04:00
|
|
|
}
|
2005-03-14 20:51:43 -05:00
|
|
|
/* vim: set ts=2 sw=2 noet: */
|