00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "config.h"
00023
00024 #include <stdlib.h>
00025 #include <stdio.h>
00026 #include <string.h>
00027
00028
00029 #include "deps.h"
00030 #include "alpm_list.h"
00031 #include "util.h"
00032 #include "log.h"
00033 #include "error.h"
00034 #include "package.h"
00035 #include "db.h"
00036 #include "cache.h"
00037 #include "handle.h"
00038
00039 void _alpm_dep_free(pmdepend_t *dep)
00040 {
00041 FREE(dep->name);
00042 FREE(dep->version);
00043 FREE(dep);
00044 }
00045
00046 static pmgraph_t *_alpm_graph_new(void)
00047 {
00048 pmgraph_t *graph = NULL;
00049
00050 ALPM_LOG_FUNC;
00051
00052 MALLOC(graph, sizeof(pmgraph_t), RET_ERR(PM_ERR_MEMORY, NULL));
00053
00054 if(graph) {
00055 graph->state = 0;
00056 graph->data = NULL;
00057 graph->parent = NULL;
00058 graph->children = NULL;
00059 graph->childptr = NULL;
00060 }
00061 return(graph);
00062 }
00063
00064 static void _alpm_graph_free(void *data)
00065 {
00066 pmgraph_t *graph = data;
00067 alpm_list_free(graph->children);
00068 free(graph);
00069 }
00070
00071 pmdepmissing_t *_alpm_depmiss_new(const char *target, pmdepend_t *dep)
00072 {
00073 pmdepmissing_t *miss;
00074
00075 ALPM_LOG_FUNC;
00076
00077 MALLOC(miss, sizeof(pmdepmissing_t), RET_ERR(PM_ERR_MEMORY, NULL));
00078
00079 STRDUP(miss->target, target, RET_ERR(PM_ERR_MEMORY, NULL));
00080 miss->depend = _alpm_dep_dup(dep);
00081
00082 return(miss);
00083 }
00084
00085 void _alpm_depmiss_free(pmdepmissing_t *miss)
00086 {
00087 _alpm_dep_free(miss->depend);
00088 FREE(miss->target);
00089 FREE(miss);
00090 }
00091
00092
00093
00094
00095
00096
00097 static alpm_list_t *_alpm_graph_init(alpm_list_t *targets)
00098 {
00099 alpm_list_t *i, *j, *k;
00100 alpm_list_t *vertices = NULL;
00101
00102 for(i = targets; i; i = i->next) {
00103 pmgraph_t *vertex = _alpm_graph_new();
00104 vertex->data = (void *)i->data;
00105 vertices = alpm_list_add(vertices, vertex);
00106 }
00107
00108
00109 for(i = vertices; i; i = i->next) {
00110 pmgraph_t *vertex_i = i->data;
00111 pmpkg_t *p_i = vertex_i->data;
00112
00113 for(j = vertices; j; j = j->next) {
00114 pmgraph_t *vertex_j = j->data;
00115 pmpkg_t *p_j = vertex_j->data;
00116 int child = 0;
00117 for(k = alpm_pkg_get_depends(p_i); k && !child; k = k->next) {
00118 pmdepend_t *depend = k->data;
00119 child = alpm_depcmp(p_j, depend);
00120 }
00121 if(child) {
00122 vertex_i->children =
00123 alpm_list_add(vertex_i->children, vertex_j);
00124 }
00125 }
00126 vertex_i->childptr = vertex_i->children;
00127 }
00128 return(vertices);
00129 }
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146 alpm_list_t *_alpm_sortbydeps(alpm_list_t *targets, pmtranstype_t mode)
00147 {
00148 alpm_list_t *newtargs = NULL;
00149 alpm_list_t *vertices = NULL;
00150 alpm_list_t *vptr;
00151 pmgraph_t *vertex;
00152
00153 ALPM_LOG_FUNC;
00154
00155 if(targets == NULL) {
00156 return(NULL);
00157 }
00158
00159 _alpm_log(PM_LOG_DEBUG, "started sorting dependencies\n");
00160
00161 vertices = _alpm_graph_init(targets);
00162
00163 vptr = vertices;
00164 vertex = vertices->data;
00165 while(vptr) {
00166
00167 vertex->state = -1;
00168 int found = 0;
00169 while(vertex->childptr && !found) {
00170 pmgraph_t *nextchild = (vertex->childptr)->data;
00171 vertex->childptr = (vertex->childptr)->next;
00172 if (nextchild->state == 0) {
00173 found = 1;
00174 nextchild->parent = vertex;
00175 vertex = nextchild;
00176 }
00177 else if(nextchild->state == -1) {
00178 pmpkg_t *vertexpkg = vertex->data;
00179 pmpkg_t *childpkg = nextchild->data;
00180 _alpm_log(PM_LOG_WARNING, _("dependency cycle detected:\n"));
00181 if(mode == PM_TRANS_TYPE_REMOVE) {
00182 _alpm_log(PM_LOG_WARNING, _("%s will be removed after its %s dependency\n"), vertexpkg->name, childpkg->name);
00183 } else {
00184 _alpm_log(PM_LOG_WARNING, _("%s will be installed before its %s dependency\n"), vertexpkg->name, childpkg->name);
00185 }
00186 }
00187 }
00188 if(!found) {
00189 newtargs = alpm_list_add(newtargs, vertex->data);
00190
00191 vertex->state = 1;
00192 vertex = vertex->parent;
00193 if(!vertex) {
00194 vptr = vptr->next;
00195 while(vptr) {
00196 vertex = vptr->data;
00197 if (vertex->state == 0) break;
00198 vptr = vptr->next;
00199 }
00200 }
00201 }
00202 }
00203
00204 _alpm_log(PM_LOG_DEBUG, "sorting dependencies finished\n");
00205
00206 if(mode == PM_TRANS_TYPE_REMOVE) {
00207
00208 alpm_list_t *tmptargs = alpm_list_reverse(newtargs);
00209
00210 alpm_list_free(newtargs);
00211 newtargs = tmptargs;
00212 }
00213
00214 alpm_list_free_inner(vertices, _alpm_graph_free);
00215 alpm_list_free(vertices);
00216
00217 return(newtargs);
00218 }
00219
00220
00221 static int satisfycmp(const void *pkg, const void *depend)
00222 {
00223 return(!alpm_depcmp((pmpkg_t*) pkg, (pmdepend_t*) depend));
00224 }
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234 alpm_list_t SYMEXPORT *alpm_checkdeps(pmdb_t *db, int reversedeps,
00235 alpm_list_t *remove, alpm_list_t *upgrade)
00236 {
00237 alpm_list_t *i, *j;
00238 alpm_list_t *targets, *dblist = NULL, *modified = NULL;
00239 alpm_list_t *baddeps = NULL;
00240 pmdepmissing_t *miss = NULL;
00241
00242 ALPM_LOG_FUNC;
00243
00244 if(db == NULL) {
00245 return(NULL);
00246 }
00247
00248 targets = alpm_list_join(alpm_list_copy(remove), alpm_list_copy(upgrade));
00249 for(i = _alpm_db_get_pkgcache(db); i; i = i->next) {
00250 void *pkg = i->data;
00251 if(alpm_list_find(targets, pkg, _alpm_pkg_cmp)) {
00252 modified = alpm_list_add(modified, pkg);
00253 } else {
00254 dblist = alpm_list_add(dblist, pkg);
00255 }
00256 }
00257 alpm_list_free(targets);
00258
00259
00260 for(i = upgrade; i; i = i->next) {
00261 pmpkg_t *tp = i->data;
00262 _alpm_log(PM_LOG_DEBUG, "checkdeps: package %s-%s\n",
00263 alpm_pkg_get_name(tp), alpm_pkg_get_version(tp));
00264
00265 for(j = alpm_pkg_get_depends(tp); j; j = j->next) {
00266 pmdepend_t *depend = j->data;
00267
00268
00269 if(!alpm_list_find(upgrade, depend, satisfycmp) &&
00270 !alpm_list_find(dblist, depend, satisfycmp)) {
00271
00272 char *missdepstring = alpm_dep_get_string(depend);
00273 _alpm_log(PM_LOG_DEBUG, "checkdeps: missing dependency '%s' for package '%s'\n",
00274 missdepstring, alpm_pkg_get_name(tp));
00275 free(missdepstring);
00276 miss = _alpm_depmiss_new(alpm_pkg_get_name(tp), depend);
00277 baddeps = alpm_list_add(baddeps, miss);
00278 }
00279 }
00280 }
00281
00282 if(reversedeps) {
00283
00284
00285 for(i = dblist; i; i = i->next) {
00286 pmpkg_t *lp = i->data;
00287 for(j = alpm_pkg_get_depends(lp); j; j = j->next) {
00288 pmdepend_t *depend = j->data;
00289
00290
00291
00292 if(alpm_list_find(modified, depend, satisfycmp) &&
00293 !alpm_list_find(upgrade, depend, satisfycmp) &&
00294 !alpm_list_find(dblist, depend, satisfycmp)) {
00295 char *missdepstring = alpm_dep_get_string(depend);
00296 _alpm_log(PM_LOG_DEBUG, "checkdeps: transaction would break '%s' dependency of '%s'\n",
00297 missdepstring, alpm_pkg_get_name(lp));
00298 free(missdepstring);
00299 miss = _alpm_depmiss_new(lp->name, depend);
00300 baddeps = alpm_list_add(baddeps, miss);
00301 }
00302 }
00303 }
00304 }
00305 alpm_list_free(modified);
00306 alpm_list_free(dblist);
00307
00308 return(baddeps);
00309 }
00310
00311 static int dep_vercmp(const char *version1, pmdepmod_t mod,
00312 const char *version2)
00313 {
00314 int equal = 0;
00315
00316 if(mod == PM_DEP_MOD_ANY) {
00317 equal = 1;
00318 } else {
00319 int cmp = _alpm_versioncmp(version1, version2);
00320 switch(mod) {
00321 case PM_DEP_MOD_EQ: equal = (cmp == 0); break;
00322 case PM_DEP_MOD_GE: equal = (cmp >= 0); break;
00323 case PM_DEP_MOD_LE: equal = (cmp <= 0); break;
00324 case PM_DEP_MOD_LT: equal = (cmp < 0); break;
00325 case PM_DEP_MOD_GT: equal = (cmp > 0); break;
00326 default: equal = 1; break;
00327 }
00328 }
00329 return(equal);
00330 }
00331
00332 int SYMEXPORT alpm_depcmp(pmpkg_t *pkg, pmdepend_t *dep)
00333 {
00334 alpm_list_t *i;
00335
00336 ALPM_LOG_FUNC;
00337
00338 const char *pkgname = alpm_pkg_get_name(pkg);
00339 const char *pkgversion = alpm_pkg_get_version(pkg);
00340 int satisfy = 0;
00341
00342
00343 satisfy = (strcmp(pkgname, dep->name) == 0
00344 && dep_vercmp(pkgversion, dep->mod, dep->version));
00345
00346
00347 for(i = alpm_pkg_get_provides(pkg); i && !satisfy; i = i->next) {
00348 char *provname = strdup(i->data);
00349 char *provver = strchr(provname, '=');
00350
00351 if(provver == NULL) {
00352 satisfy = (dep->mod == PM_DEP_MOD_ANY
00353 && strcmp(provname, dep->name) == 0);
00354 } else {
00355
00356 *provver = '\0';
00357 provver += 1;
00358 satisfy = (strcmp(provname, dep->name) == 0
00359 && dep_vercmp(provver, dep->mod, dep->version));
00360 }
00361 free(provname);
00362 }
00363
00364 return(satisfy);
00365 }
00366
00367 pmdepend_t SYMEXPORT *alpm_splitdep(const char *depstring)
00368 {
00369 pmdepend_t *depend;
00370 char *ptr = NULL;
00371 char *newstr = NULL;
00372
00373 if(depstring == NULL) {
00374 return(NULL);
00375 }
00376 STRDUP(newstr, depstring, RET_ERR(PM_ERR_MEMORY, NULL));
00377
00378 CALLOC(depend, sizeof(pmdepend_t), 1, RET_ERR(PM_ERR_MEMORY, NULL));
00379
00380
00381
00382 if((ptr = strstr(newstr, ">="))) {
00383 depend->mod = PM_DEP_MOD_GE;
00384 *ptr = '\0';
00385 ptr += 2;
00386 } else if((ptr = strstr(newstr, "<="))) {
00387 depend->mod = PM_DEP_MOD_LE;
00388 *ptr = '\0';
00389 ptr += 2;
00390 } else if((ptr = strstr(newstr, "="))) {
00391 depend->mod = PM_DEP_MOD_EQ;
00392 *ptr = '\0';
00393 ptr += 1;
00394 } else if((ptr = strstr(newstr, "<"))) {
00395 depend->mod = PM_DEP_MOD_LT;
00396 *ptr = '\0';
00397 ptr += 1;
00398 } else if((ptr = strstr(newstr, ">"))) {
00399 depend->mod = PM_DEP_MOD_GT;
00400 *ptr = '\0';
00401 ptr += 1;
00402 } else {
00403
00404 depend->mod = PM_DEP_MOD_ANY;
00405 STRDUP(depend->name, newstr, RET_ERR(PM_ERR_MEMORY, NULL));
00406 depend->version = NULL;
00407 free(newstr);
00408 return(depend);
00409 }
00410
00411
00412
00413 STRDUP(depend->name, newstr, RET_ERR(PM_ERR_MEMORY, NULL));
00414 STRDUP(depend->version, ptr, RET_ERR(PM_ERR_MEMORY, NULL));
00415 free(newstr);
00416
00417 return(depend);
00418 }
00419
00420 pmdepend_t *_alpm_dep_dup(const pmdepend_t *dep)
00421 {
00422 pmdepend_t *newdep;
00423 CALLOC(newdep, sizeof(pmdepend_t), 1, RET_ERR(PM_ERR_MEMORY, NULL));
00424
00425 STRDUP(newdep->name, dep->name, RET_ERR(PM_ERR_MEMORY, NULL));
00426 STRDUP(newdep->version, dep->version, RET_ERR(PM_ERR_MEMORY, NULL));
00427 newdep->mod = dep->mod;
00428
00429 return(newdep);
00430 }
00431
00432
00433
00434
00435
00436 static int can_remove_package(pmdb_t *db, pmpkg_t *pkg, alpm_list_t *targets,
00437 int include_explicit)
00438 {
00439 alpm_list_t *i, *requiredby;
00440
00441 if(_alpm_pkg_find(alpm_pkg_get_name(pkg), targets)) {
00442 return(0);
00443 }
00444
00445 if(!include_explicit) {
00446
00447 if(alpm_pkg_get_reason(pkg) == PM_PKG_REASON_EXPLICIT) {
00448 _alpm_log(PM_LOG_DEBUG, "excluding %s -- explicitly installed\n",
00449 alpm_pkg_get_name(pkg));
00450 return(0);
00451 }
00452 }
00453
00454
00455
00456
00457
00458
00459
00460
00461 requiredby = alpm_pkg_compute_requiredby(pkg);
00462 for(i = requiredby; i; i = i->next) {
00463 pmpkg_t *reqpkg = _alpm_db_get_pkgfromcache(db, i->data);
00464 if(reqpkg && !_alpm_pkg_find(alpm_pkg_get_name(reqpkg), targets)) {
00465 FREELIST(requiredby);
00466 return(0);
00467 }
00468 }
00469 FREELIST(requiredby);
00470
00471
00472 return(1);
00473 }
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485 void _alpm_recursedeps(pmdb_t *db, alpm_list_t *targs, int include_explicit)
00486 {
00487 alpm_list_t *i, *j, *k;
00488
00489 ALPM_LOG_FUNC;
00490
00491 if(db == NULL || targs == NULL) {
00492 return;
00493 }
00494
00495 for(i = targs; i; i = i->next) {
00496 pmpkg_t *pkg = i->data;
00497 for(j = alpm_pkg_get_depends(pkg); j; j = j->next) {
00498 pmdepend_t *depend = j->data;
00499
00500 for(k = _alpm_db_get_pkgcache(db); k; k = k->next) {
00501 pmpkg_t *deppkg = k->data;
00502 if(alpm_depcmp(deppkg,depend)
00503 && can_remove_package(db, deppkg, targs, include_explicit)) {
00504 _alpm_log(PM_LOG_DEBUG, "adding '%s' to the targets\n",
00505 alpm_pkg_get_name(deppkg));
00506
00507 targs = alpm_list_add(targs, _alpm_pkg_dup(deppkg));
00508 }
00509 }
00510 }
00511 }
00512 }
00513
00514
00515
00516
00517
00518
00519
00520 int _alpm_resolvedeps(pmdb_t *local, alpm_list_t *dbs_sync, pmpkg_t *syncpkg,
00521 alpm_list_t **list, alpm_list_t *remove, pmtrans_t *trans, alpm_list_t **data)
00522 {
00523 alpm_list_t *i, *j, *k;
00524 alpm_list_t *targ;
00525 alpm_list_t *deps = NULL;
00526
00527 ALPM_LOG_FUNC;
00528
00529 if(local == NULL || dbs_sync == NULL || syncpkg == NULL || list == NULL) {
00530 return(-1);
00531 }
00532
00533 _alpm_log(PM_LOG_DEBUG, "started resolving dependencies\n");
00534 targ = alpm_list_add(NULL, syncpkg);
00535 deps = alpm_checkdeps(local, 0, remove, targ);
00536 alpm_list_free(targ);
00537
00538 if(deps == NULL) {
00539 return(0);
00540 }
00541
00542 for(i = deps; i; i = i->next) {
00543 int found = 0;
00544 pmdepmissing_t *miss = i->data;
00545 pmdepend_t *missdep = alpm_miss_get_dep(miss);
00546 pmpkg_t *sync = NULL;
00547
00548
00549 for(j = *list; j && !found; j = j->next) {
00550 pmpkg_t *sp = j->data;
00551 if(alpm_depcmp(sp, missdep)) {
00552 char *missdepstring = alpm_dep_get_string(missdep);
00553 _alpm_log(PM_LOG_DEBUG, "%s satisfies dependency %s -- skipping\n",
00554 alpm_pkg_get_name(sp), missdepstring);
00555 free(missdepstring);
00556 found = 1;
00557 }
00558 }
00559 if(found) {
00560 continue;
00561 }
00562
00563
00564
00565 for(j = dbs_sync; j && !found; j = j->next) {
00566 sync = _alpm_db_get_pkgfromcache(j->data, missdep->name);
00567 if(!sync) {
00568 continue;
00569 }
00570 found = alpm_depcmp(sync, missdep) && !_alpm_pkg_find(alpm_pkg_get_name(sync), remove);
00571 if(!found) {
00572 continue;
00573 }
00574
00575 if(_alpm_pkg_should_ignore(sync)) {
00576 pmpkg_t *dummypkg = _alpm_pkg_new(miss->target, NULL);
00577 QUESTION(trans, PM_TRANS_CONV_INSTALL_IGNOREPKG, dummypkg, sync, NULL, &found);
00578 _alpm_pkg_free(dummypkg);
00579 }
00580 }
00581
00582
00583
00584
00585 for(j = dbs_sync; j && !found; j = j->next) {
00586 for(k = _alpm_db_get_pkgcache(j->data); k && !found; k = k->next) {
00587 sync = k->data;
00588 if(!sync) {
00589 continue;
00590 }
00591 found = alpm_depcmp(sync, missdep) && strcmp(sync->name, missdep->name)
00592 && !_alpm_pkg_find(alpm_pkg_get_name(sync), remove);
00593 if(!found) {
00594 continue;
00595 }
00596 if(_alpm_pkg_should_ignore(sync)) {
00597 pmpkg_t *dummypkg = _alpm_pkg_new(miss->target, NULL);
00598 QUESTION(trans, PM_TRANS_CONV_INSTALL_IGNOREPKG, dummypkg, sync, NULL, &found);
00599 _alpm_pkg_free(dummypkg);
00600 }
00601 }
00602 }
00603
00604 if(!found) {
00605 char *missdepstring = alpm_dep_get_string(missdep);
00606 _alpm_log(PM_LOG_ERROR, _("cannot resolve \"%s\", a dependency of \"%s\"\n"),
00607 missdepstring, miss->target);
00608 free(missdepstring);
00609 if(data) {
00610 MALLOC(miss, sizeof(pmdepmissing_t),);
00611 if(!miss) {
00612 pm_errno = PM_ERR_MEMORY;
00613 FREELIST(*data);
00614 goto error;
00615 }
00616 *miss = *(pmdepmissing_t *)i->data;
00617 *data = alpm_list_add(*data, miss);
00618 }
00619 pm_errno = PM_ERR_UNSATISFIED_DEPS;
00620 goto error;
00621 } else {
00622 _alpm_log(PM_LOG_DEBUG, "pulling dependency %s (needed by %s)\n",
00623 alpm_pkg_get_name(sync), alpm_pkg_get_name(syncpkg));
00624 *list = alpm_list_add(*list, sync);
00625 if(_alpm_resolvedeps(local, dbs_sync, sync, list, remove, trans, data)) {
00626 goto error;
00627 }
00628 }
00629 }
00630
00631 _alpm_log(PM_LOG_DEBUG, "finished resolving dependencies\n");
00632
00633 alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_depmiss_free);
00634 alpm_list_free(deps);
00635
00636 return(0);
00637
00638 error:
00639 FREELIST(deps);
00640 return(-1);
00641 }
00642
00643 const char SYMEXPORT *alpm_miss_get_target(const pmdepmissing_t *miss)
00644 {
00645 ALPM_LOG_FUNC;
00646
00647
00648 ASSERT(miss != NULL, return(NULL));
00649
00650 return(miss->target);
00651 }
00652
00653 pmdepend_t SYMEXPORT *alpm_miss_get_dep(pmdepmissing_t *miss)
00654 {
00655 ALPM_LOG_FUNC;
00656
00657
00658 ASSERT(miss != NULL, return(NULL));
00659
00660 return(miss->depend);
00661 }
00662
00663 pmdepmod_t SYMEXPORT alpm_dep_get_mod(const pmdepend_t *dep)
00664 {
00665 ALPM_LOG_FUNC;
00666
00667
00668 ASSERT(dep != NULL, return(-1));
00669
00670 return(dep->mod);
00671 }
00672
00673 const char SYMEXPORT *alpm_dep_get_name(const pmdepend_t *dep)
00674 {
00675 ALPM_LOG_FUNC;
00676
00677
00678 ASSERT(dep != NULL, return(NULL));
00679
00680 return(dep->name);
00681 }
00682
00683 const char SYMEXPORT *alpm_dep_get_version(const pmdepend_t *dep)
00684 {
00685 ALPM_LOG_FUNC;
00686
00687
00688 ASSERT(dep != NULL, return(NULL));
00689
00690 return(dep->version);
00691 }
00692
00693
00694
00695
00696
00697
00698 char SYMEXPORT *alpm_dep_get_string(const pmdepend_t *dep)
00699 {
00700 char *name, *opr, *ver, *str = NULL;
00701 size_t len;
00702
00703 ALPM_LOG_FUNC;
00704
00705
00706 ASSERT(dep != NULL, return(NULL));
00707
00708 if(dep->name) {
00709 name = dep->name;
00710 } else {
00711 name = "";
00712 }
00713
00714 switch(dep->mod) {
00715 case PM_DEP_MOD_ANY:
00716 opr = "";
00717 break;
00718 case PM_DEP_MOD_GE:
00719 opr = ">=";
00720 break;
00721 case PM_DEP_MOD_LE:
00722 opr = "<=";
00723 break;
00724 case PM_DEP_MOD_EQ:
00725 opr = "=";
00726 break;
00727 case PM_DEP_MOD_LT:
00728 opr = "<";
00729 break;
00730 case PM_DEP_MOD_GT:
00731 opr = ">";
00732 break;
00733 default:
00734 opr = "";
00735 break;
00736 }
00737
00738 if(dep->version) {
00739 ver = dep->version;
00740 } else {
00741 ver = "";
00742 }
00743
00744
00745
00746
00747 len = strlen(name) + strlen(opr) + strlen(ver) + 1;
00748 MALLOC(str, len, RET_ERR(PM_ERR_MEMORY, NULL));
00749 snprintf(str, len, "%s%s%s", name, opr, ver);
00750
00751 return(str);
00752 }
00753