예제 #1
0
파일: deps.c 프로젝트: gtmanfred/pacman
/** Check if pkg2 satisfies a dependency of pkg1 */
static int _alpm_pkg_depends_on(alpm_pkg_t *pkg1, alpm_pkg_t *pkg2)
{
	alpm_list_t *i;
	for(i = alpm_pkg_get_depends(pkg1); i; i = i->next) {
		if(_alpm_depcmp(pkg2, i->data)) {
			return 1;
		}
	}
	return 0;
}
예제 #2
0
파일: deps.c 프로젝트: gtmanfred/pacman
static alpm_pkg_t *find_dep_satisfier(alpm_list_t *pkgs, alpm_depend_t *dep)
{
	alpm_list_t *i;

	for(i = pkgs; i; i = i->next) {
		alpm_pkg_t *pkg = i->data;
		if(_alpm_depcmp(pkg, dep)) {
			return pkg;
		}
	}
	return NULL;
}
예제 #3
0
파일: deps.c 프로젝트: mineo/pacman
static pmpkg_t *find_dep_satisfier(alpm_list_t *pkgs, pmdepend_t *dep)
{
	alpm_list_t *i;

	for(i = pkgs; i; i = alpm_list_next(i)) {
		pmpkg_t *pkg = i->data;
		if(_alpm_depcmp(pkg, dep)) {
			return pkg;
		}
	}
	return NULL;
}
예제 #4
0
/**
 * @brief Check if packages from list1 conflict with packages from list2.
 *
 * @details This looks at the conflicts fields of all packages from list1, and
 * sees if they match packages from list2. If a conflict (pkg1, pkg2) is found,
 * it is added to the baddeps list in this order if order >= 0, or reverse
 * order (pkg2,pkg1) otherwise.
 *
 * @param handle the context handle
 * @param list1 first list of packages
 * @param list2 second list of packages
 * @param baddeps list to store conflicts
 * @param order if >= 0 the conflict order is preserved, if < 0 it's reversed
 */
static void check_conflict(alpm_handle_t *handle,
		alpm_list_t *list1, alpm_list_t *list2,
		alpm_list_t **baddeps, int order)
{
	alpm_list_t *i;

	if(!baddeps) {
		return;
	}
	for(i = list1; i; i = i->next) {
		alpm_pkg_t *pkg1 = i->data;
		alpm_list_t *j;

		for(j = alpm_pkg_get_conflicts(pkg1); j; j = j->next) {
			alpm_depend_t *conflict = j->data;
			alpm_list_t *k;

			for(k = list2; k; k = k->next) {
				alpm_pkg_t *pkg2 = k->data;

				if(pkg1->name_hash == pkg2->name_hash
						&& strcmp(pkg1->name, pkg2->name) == 0) {
					/* skip the package we're currently processing */
					continue;
				}

				if(_alpm_depcmp(pkg2, conflict)) {
					if(order >= 0) {
						add_conflict(handle, baddeps, pkg1, pkg2, conflict);
					} else {
						add_conflict(handle, baddeps, pkg2, pkg1, conflict);
					}
				}
			}
		}
	}
}
예제 #5
0
파일: deps.c 프로젝트: mineo/pacman
/**
 * helper function for resolvedeps: search for dep satisfier in dbs
 *
 * @param handle the context handle
 * @param dep is the dependency to search for
 * @param dbs are the databases to search
 * @param excluding are the packages to exclude from the search
 * @param prompt if true, will cause an unresolvable dependency to issue an
 *        interactive prompt asking whether the package should be removed from
 *        the transaction or the transaction aborted; if false, simply returns
 *        an error code without prompting
 * @return the resolved package
 **/
static pmpkg_t *resolvedep(pmhandle_t *handle, pmdepend_t *dep,
		alpm_list_t *dbs, alpm_list_t *excluding, int prompt)
{
	alpm_list_t *i, *j;
	int ignored = 0;

	alpm_list_t *providers = NULL;
	int count;

	/* 1. literals */
	for(i = dbs; i; i = i->next) {
		pmpkg_t *pkg = _alpm_db_get_pkgfromcache(i->data, dep->name);
		if(pkg && _alpm_depcmp(pkg, dep) && !_alpm_pkg_find(excluding, pkg->name)) {
			if(_alpm_pkg_should_ignore(handle, pkg)) {
				int install = 0;
				if(prompt) {
					QUESTION(handle->trans, PM_TRANS_CONV_INSTALL_IGNOREPKG, pkg,
							 NULL, NULL, &install);
				} else {
					_alpm_log(handle, PM_LOG_WARNING, _("ignoring package %s-%s\n"), pkg->name, pkg->version);
				}
				if(!install) {
					ignored = 1;
					continue;
				}
			}
			return pkg;
		}
	}
	/* 2. satisfiers (skip literals here) */
	for(i = dbs; i; i = i->next) {
		for(j = _alpm_db_get_pkgcache(i->data); j; j = j->next) {
			pmpkg_t *pkg = j->data;
			if(_alpm_depcmp(pkg, dep) && strcmp(pkg->name, dep->name) != 0 &&
			             !_alpm_pkg_find(excluding, pkg->name)) {
				if(_alpm_pkg_should_ignore(handle, pkg)) {
					int install = 0;
					if(prompt) {
						QUESTION(handle->trans, PM_TRANS_CONV_INSTALL_IGNOREPKG,
									pkg, NULL, NULL, &install);
					} else {
						_alpm_log(handle, PM_LOG_WARNING, _("ignoring package %s-%s\n"), pkg->name, pkg->version);
					}
					if(!install) {
						ignored = 1;
						continue;
					}
				}
				_alpm_log(handle, PM_LOG_DEBUG, "provider found (%s provides %s)\n",
						pkg->name, dep->name);
				providers = alpm_list_add(providers, pkg);
				/* keep looking for other providers in the all dbs */
			}
		}
	}

	/* first check if one provider is already installed locally */
	for(i = providers; i; i = i->next) {
		pmpkg_t *pkg = i->data;
		if(_alpm_pkghash_find(_alpm_db_get_pkgcache_hash(handle->db_local), pkg->name)) {
			alpm_list_free(providers);
			return pkg;
		}
	}
	count = alpm_list_count(providers);
	if(count >= 1) {
		/* default to first provider if there is no QUESTION callback */
		int index = 0;
		if(count > 1) {
			/* if there is more than one provider, we ask the user */
			QUESTION(handle->trans, PM_TRANS_CONV_SELECT_PROVIDER,
					providers, dep, NULL, &index);
		}
		if(index >= 0 && index < count) {
			pmpkg_t *pkg = alpm_list_getdata(alpm_list_nth(providers, index));
			alpm_list_free(providers);
			return pkg;
		}
		alpm_list_free(providers);
		providers = NULL;
	}

	if(ignored) { /* resolvedeps will override these */
		handle->pm_errno = PM_ERR_PKG_IGNORED;
	} else {
		handle->pm_errno = PM_ERR_PKG_NOT_FOUND;
	}
	return NULL;
}
예제 #6
0
int _alpm_sync_prepare(alpm_handle_t *handle, alpm_list_t **data)
{
	alpm_list_t *i, *j;
	alpm_list_t *deps = NULL;
	alpm_list_t *unresolvable = NULL;
	alpm_list_t *remove = NULL;
	int ret = 0;
	alpm_trans_t *trans = handle->trans;

	if(data) {
		*data = NULL;
	}

	/* ensure all sync database are valid since we will be using them */
	for(i = handle->dbs_sync; i; i = i->next) {
		const alpm_db_t *db = i->data;
		if(!(db->status & DB_STATUS_VALID)) {
			RET_ERR(handle, ALPM_ERR_DB_INVALID, -1);
		}
	}

	if(!(trans->flags & ALPM_TRANS_FLAG_NODEPS)) {
		alpm_list_t *resolved = NULL; /* target list after resolvedeps */

		/* Build up list by repeatedly resolving each transaction package */
		/* Resolve targets dependencies */
		EVENT(trans, ALPM_TRANS_EVT_RESOLVEDEPS_START, NULL, NULL);
		_alpm_log(handle, ALPM_LOG_DEBUG, "resolving target's dependencies\n");

		/* build remove list for resolvedeps */
		for(i = trans->add; i; i = i->next) {
			alpm_pkg_t *spkg = i->data;
			for(j = spkg->removes; j; j = j->next) {
				remove = alpm_list_add(remove, j->data);
			}
		}

		/* Compute the fake local database for resolvedeps (partial fix for the
		 * phonon/qt issue) */
		alpm_list_t *localpkgs = alpm_list_diff(_alpm_db_get_pkgcache(handle->db_local),
				trans->add, _alpm_pkg_cmp);

		/* Resolve packages in the transaction one at a time, in addition
		   building up a list of packages which could not be resolved. */
		for(i = trans->add; i; i = i->next) {
			alpm_pkg_t *pkg = i->data;
			if(_alpm_resolvedeps(handle, localpkgs, pkg, trans->add,
						&resolved, remove, data) == -1) {
				unresolvable = alpm_list_add(unresolvable, pkg);
			}
			/* Else, [resolved] now additionally contains [pkg] and all of its
			   dependencies not already on the list */
		}
		alpm_list_free(localpkgs);

		/* If there were unresolvable top-level packages, prompt the user to
		   see if they'd like to ignore them rather than failing the sync */
		if(unresolvable != NULL) {
			int remove_unresolvable = 0;
			QUESTION(trans, ALPM_TRANS_CONV_REMOVE_PKGS, unresolvable,
					NULL, NULL, &remove_unresolvable);
			if(remove_unresolvable) {
				/* User wants to remove the unresolvable packages from the
				   transaction. The packages will be removed from the actual
				   transaction when the transaction packages are replaced with a
				   dependency-reordered list below */
				handle->pm_errno = 0; /* pm_errno was set by resolvedeps */
				if(data) {
					alpm_list_free_inner(*data, (alpm_list_fn_free)_alpm_depmiss_free);
					alpm_list_free(*data);
					*data = NULL;
				}
			} else {
				/* pm_errno is set by resolvedeps */
				alpm_list_free(resolved);
				ret = -1;
				goto cleanup;
			}
		}

		/* Set DEPEND reason for pulled packages */
		for(i = resolved; i; i = i->next) {
			alpm_pkg_t *pkg = i->data;
			if(!_alpm_pkg_find(trans->add, pkg->name)) {
				pkg->reason = ALPM_PKG_REASON_DEPEND;
			}
		}

		/* Unresolvable packages will be removed from the target list, so
		   we free the transaction specific fields */
		alpm_list_free_inner(unresolvable, (alpm_list_fn_free)_alpm_pkg_free_trans);

		/* re-order w.r.t. dependencies */
		alpm_list_free(trans->add);
		trans->add = _alpm_sortbydeps(handle, resolved, 0);
		alpm_list_free(resolved);

		EVENT(trans, ALPM_TRANS_EVT_RESOLVEDEPS_DONE, NULL, NULL);
	}

	if(!(trans->flags & ALPM_TRANS_FLAG_NOCONFLICTS)) {
		/* check for inter-conflicts and whatnot */
		EVENT(trans, ALPM_TRANS_EVT_INTERCONFLICTS_START, NULL, NULL);

		_alpm_log(handle, ALPM_LOG_DEBUG, "looking for conflicts\n");

		/* 1. check for conflicts in the target list */
		_alpm_log(handle, ALPM_LOG_DEBUG, "check targets vs targets\n");
		deps = _alpm_innerconflicts(handle, trans->add);

		for(i = deps; i; i = i->next) {
			alpm_conflict_t *conflict = i->data;
			alpm_pkg_t *rsync, *sync, *sync1, *sync2;

			/* have we already removed one of the conflicting targets? */
			sync1 = _alpm_pkg_find(trans->add, conflict->package1);
			sync2 = _alpm_pkg_find(trans->add, conflict->package2);
			if(!sync1 || !sync2) {
				continue;
			}

			_alpm_log(handle, ALPM_LOG_DEBUG, "conflicting packages in the sync list: '%s' <-> '%s'\n",
					conflict->package1, conflict->package2);

			/* if sync1 provides sync2, we remove sync2 from the targets, and vice versa */
			alpm_depend_t *dep1 = _alpm_splitdep(conflict->package1);
			alpm_depend_t *dep2 = _alpm_splitdep(conflict->package2);
			if(_alpm_depcmp(sync1, dep2)) {
				rsync = sync2;
				sync = sync1;
			} else if(_alpm_depcmp(sync2, dep1)) {
				rsync = sync1;
				sync = sync2;
			} else {
				_alpm_log(handle, ALPM_LOG_ERROR, _("unresolvable package conflicts detected\n"));
				handle->pm_errno = ALPM_ERR_CONFLICTING_DEPS;
				ret = -1;
				if(data) {
					alpm_conflict_t *newconflict = _alpm_conflict_dup(conflict);
					if(newconflict) {
						*data = alpm_list_add(*data, newconflict);
					}
				}
				alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_conflict_free);
				alpm_list_free(deps);
				_alpm_dep_free(dep1);
				_alpm_dep_free(dep2);
				goto cleanup;
			}
			_alpm_dep_free(dep1);
			_alpm_dep_free(dep2);

			/* Prints warning */
			_alpm_log(handle, ALPM_LOG_WARNING,
					_("removing '%s' from target list because it conflicts with '%s'\n"),
					rsync->name, sync->name);
			trans->add = alpm_list_remove(trans->add, rsync, _alpm_pkg_cmp, NULL);
			_alpm_pkg_free_trans(rsync); /* rsync is not transaction target anymore */
			continue;
		}

		alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_conflict_free);
		alpm_list_free(deps);
		deps = NULL;

		/* 2. we check for target vs db conflicts (and resolve)*/
		_alpm_log(handle, ALPM_LOG_DEBUG, "check targets vs db and db vs targets\n");
		deps = _alpm_outerconflicts(handle->db_local, trans->add);

		for(i = deps; i; i = i->next) {
			alpm_conflict_t *conflict = i->data;

			/* if conflict->package2 (the local package) is not elected for removal,
			   we ask the user */
			int found = 0;
			for(j = trans->add; j && !found; j = j->next) {
				alpm_pkg_t *spkg = j->data;
				if(_alpm_pkg_find(spkg->removes, conflict->package2)) {
					found = 1;
				}
			}
			if(found) {
				continue;
			}

			_alpm_log(handle, ALPM_LOG_DEBUG, "package '%s' conflicts with '%s'\n",
					conflict->package1, conflict->package2);

			alpm_pkg_t *sync = _alpm_pkg_find(trans->add, conflict->package1);
			alpm_pkg_t *local = _alpm_db_get_pkgfromcache(handle->db_local, conflict->package2);
			int doremove = 0;
			QUESTION(trans, ALPM_TRANS_CONV_CONFLICT_PKG, conflict->package1,
							conflict->package2, conflict->reason, &doremove);
			if(doremove) {
				/* append to the removes list */
				_alpm_log(handle, ALPM_LOG_DEBUG, "electing '%s' for removal\n", conflict->package2);
				sync->removes = alpm_list_add(sync->removes, local);
			} else { /* abort */
				_alpm_log(handle, ALPM_LOG_ERROR, _("unresolvable package conflicts detected\n"));
				handle->pm_errno = ALPM_ERR_CONFLICTING_DEPS;
				ret = -1;
				if(data) {
					alpm_conflict_t *newconflict = _alpm_conflict_dup(conflict);
					if(newconflict) {
						*data = alpm_list_add(*data, newconflict);
					}
				}
				alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_conflict_free);
				alpm_list_free(deps);
				goto cleanup;
			}
		}
		EVENT(trans, ALPM_TRANS_EVT_INTERCONFLICTS_DONE, NULL, NULL);
		alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_conflict_free);
		alpm_list_free(deps);
	}

	/* Build trans->remove list */
	for(i = trans->add; i; i = i->next) {
		alpm_pkg_t *spkg = i->data;
		for(j = spkg->removes; j; j = j->next) {
			alpm_pkg_t *rpkg = j->data;
			if(!_alpm_pkg_find(trans->remove, rpkg->name)) {
				_alpm_log(handle, ALPM_LOG_DEBUG, "adding '%s' to remove list\n", rpkg->name);
				trans->remove = alpm_list_add(trans->remove, _alpm_pkg_dup(rpkg));
			}
		}
	}

	if(!(trans->flags & ALPM_TRANS_FLAG_NODEPS)) {
		_alpm_log(handle, ALPM_LOG_DEBUG, "checking dependencies\n");
		deps = alpm_checkdeps(handle, _alpm_db_get_pkgcache(handle->db_local),
				trans->remove, trans->add, 1);
		if(deps) {
			handle->pm_errno = ALPM_ERR_UNSATISFIED_DEPS;
			ret = -1;
			if(data) {
				*data = deps;
			} else {
				alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_depmiss_free);
				alpm_list_free(deps);
			}
			goto cleanup;
		}
	}
	for(i = trans->add; i; i = i->next) {
		/* update download size field */
		alpm_pkg_t *spkg = i->data;
		if(compute_download_size(spkg) != 0) {
			ret = -1;
			goto cleanup;
		}
	}

cleanup:
	alpm_list_free(unresolvable);
	alpm_list_free(remove);

	return ret;
}