static alpm_pkghash_t *pkghash_add_pkg(alpm_pkghash_t *hash, alpm_pkg_t *pkg, int sorted) { alpm_list_t *ptr; unsigned int position; if(pkg == NULL || hash == NULL) { return hash; } if(hash->entries >= hash->limit) { hash = rehash(hash); } position = get_hash_position(pkg->name_hash, hash); ptr = malloc(sizeof(alpm_list_t)); if(ptr == NULL) { return hash; } ptr->data = pkg; ptr->prev = ptr; ptr->next = NULL; hash->hash_table[position] = ptr; if(!sorted) { hash->list = alpm_list_join(hash->list, ptr); } else { hash->list = alpm_list_mmerge(hash->list, ptr, _alpm_pkg_cmp); } hash->entries += 1; return hash; }
static alpm_list_t *search_packages(alpm_list_t *dbs, alpm_list_t *targets) { alpm_list_t *i, *packages = NULL; for (i = dbs; i; i = i->next) { packages = alpm_list_join(packages, alpm_db_search(i->data, targets)); } return packages; }
static alpm_list_t *all_packages(alpm_list_t *dbs) { alpm_list_t *i, *packages = NULL; for (i = dbs; i; i = i->next) { packages = alpm_list_join(packages, alpm_list_copy(alpm_db_get_pkgcache(i->data))); } return packages; }
static alpm_list_t *search_groups(alpm_list_t *dbs, alpm_list_t *groupnames) { alpm_list_t *i, *j, *packages = NULL; for (i = groupnames; i; i = i->next) { for (j = dbs; j; j = j->next) { alpm_group_t *grp = alpm_db_get_group(j->data, i->data); if (grp != NULL) { packages = alpm_list_join(packages, alpm_list_copy(grp->packages)); } } } return packages; }
alpm_list_t *alpm_all_backups(int everything) /* {{{ */ { alpm_list_t *backups = NULL; const alpm_list_t *i; alpm_db_t *db = alpm_get_localdb(pmhandle); alpm_list_t *targets = cfg.targets ? alpm_db_search(db, cfg.targets) : alpm_db_get_pkgcache(db); for (i = targets; i; i = i->next) { alpm_list_t *pkg_backups = alpm_find_backups(i->data, everything); backups = alpm_list_join(backups, pkg_backups); } return backups; } /* }}} */
/** Search for packages to upgrade and add them to the transaction. */ int SYMEXPORT alpm_sync_sysupgrade(alpm_handle_t *handle, int enable_downgrade) { alpm_list_t *i, *j; alpm_trans_t *trans; CHECK_HANDLE(handle, return -1); trans = handle->trans; ASSERT(trans != NULL, RET_ERR(handle, ALPM_ERR_TRANS_NULL, -1)); ASSERT(trans->state == STATE_INITIALIZED, RET_ERR(handle, ALPM_ERR_TRANS_NOT_INITIALIZED, -1)); _alpm_log(handle, ALPM_LOG_DEBUG, "checking for package upgrades\n"); for(i = _alpm_db_get_pkgcache(handle->db_local); i; i = i->next) { alpm_pkg_t *lpkg = i->data; if(alpm_pkg_find(trans->add, lpkg->name)) { _alpm_log(handle, ALPM_LOG_DEBUG, "%s is already in the target list -- skipping\n", lpkg->name); continue; } /* Search for literal then replacers in each sync database. */ for(j = handle->dbs_sync; j; j = j->next) { alpm_db_t *sdb = j->data; /* Check sdb */ alpm_pkg_t *spkg = _alpm_db_get_pkgfromcache(sdb, lpkg->name); int literal_upgrade = 0; if(spkg) { literal_upgrade = check_literal(handle, lpkg, spkg, enable_downgrade); if(literal_upgrade) { trans->add = alpm_list_add(trans->add, spkg); } /* jump to next local package */ break; } else { alpm_list_t *replacers; replacers = check_replacers(handle, lpkg, sdb); if(replacers) { trans->add = alpm_list_join(trans->add, replacers); } } } } return 0; }
static alpm_list_t *check_replacers(alpm_handle_t *handle, alpm_pkg_t *lpkg, alpm_db_t *sdb) { /* 2. search for replacers in sdb */ alpm_list_t *replacers = NULL; alpm_list_t *k; _alpm_log(handle, ALPM_LOG_DEBUG, "searching for replacements for %s in %s\n", lpkg->name, sdb->treename); for(k = _alpm_db_get_pkgcache(sdb); k; k = k->next) { int found = 0; alpm_pkg_t *spkg = k->data; alpm_list_t *l; for(l = alpm_pkg_get_replaces(spkg); l; l = l->next) { alpm_depend_t *replace = l->data; /* we only want to consider literal matches at this point. */ if(_alpm_depcmp_literal(lpkg, replace)) { found = 1; break; } } if(found) { alpm_question_replace_t question = { .type = ALPM_QUESTION_REPLACE_PKG, .replace = 0, .oldpkg = lpkg, .newpkg = spkg, .newdb = sdb }; alpm_pkg_t *tpkg; /* check IgnorePkg/IgnoreGroup */ if(alpm_pkg_should_ignore(handle, spkg) || alpm_pkg_should_ignore(handle, lpkg)) { _alpm_log(handle, ALPM_LOG_WARNING, _("ignoring package replacement (%s-%s => %s-%s)\n"), lpkg->name, lpkg->version, spkg->name, spkg->version); continue; } QUESTION(handle, &question); if(!question.replace) { continue; } /* If spkg is already in the target list, we append lpkg to spkg's * removes list */ tpkg = alpm_pkg_find(handle->trans->add, spkg->name); if(tpkg) { /* sanity check, multiple repos can contain spkg->name */ if(tpkg->origin_data.db != sdb) { _alpm_log(handle, ALPM_LOG_WARNING, _("cannot replace %s by %s\n"), lpkg->name, spkg->name); continue; } _alpm_log(handle, ALPM_LOG_DEBUG, "appending %s to the removes list of %s\n", lpkg->name, tpkg->name); tpkg->removes = alpm_list_add(tpkg->removes, lpkg); /* check the to-be-replaced package's reason field */ if(alpm_pkg_get_reason(lpkg) == ALPM_PKG_REASON_EXPLICIT) { tpkg->reason = ALPM_PKG_REASON_EXPLICIT; } } else { /* add spkg to the target list */ /* copy over reason */ spkg->reason = alpm_pkg_get_reason(lpkg); spkg->removes = alpm_list_add(NULL, lpkg); _alpm_log(handle, ALPM_LOG_DEBUG, "adding package %s-%s to the transaction targets\n", spkg->name, spkg->version); replacers = alpm_list_add(replacers, spkg); } } } return replacers; } /** Search for packages to upgrade and add them to the transaction. */ int SYMEXPORT alpm_sync_sysupgrade(alpm_handle_t *handle, int enable_downgrade) { alpm_list_t *i, *j; alpm_trans_t *trans; CHECK_HANDLE(handle, return -1); trans = handle->trans; ASSERT(trans != NULL, RET_ERR(handle, ALPM_ERR_TRANS_NULL, -1)); ASSERT(trans->state == STATE_INITIALIZED, RET_ERR(handle, ALPM_ERR_TRANS_NOT_INITIALIZED, -1)); _alpm_log(handle, ALPM_LOG_DEBUG, "checking for package upgrades\n"); for(i = _alpm_db_get_pkgcache(handle->db_local); i; i = i->next) { alpm_pkg_t *lpkg = i->data; if(alpm_pkg_find(trans->remove, lpkg->name)) { _alpm_log(handle, ALPM_LOG_DEBUG, "%s is marked for removal -- skipping\n", lpkg->name); continue; } if(alpm_pkg_find(trans->add, lpkg->name)) { _alpm_log(handle, ALPM_LOG_DEBUG, "%s is already in the target list -- skipping\n", lpkg->name); continue; } /* Search for replacers then literal (if no replacer) in each sync database. */ for(j = handle->dbs_sync; j; j = j->next) { alpm_db_t *sdb = j->data; alpm_list_t *replacers; if(!(sdb->usage & ALPM_DB_USAGE_UPGRADE)) { continue; } /* Check sdb */ replacers = check_replacers(handle, lpkg, sdb); if(replacers) { trans->add = alpm_list_join(trans->add, replacers); /* jump to next local package */ break; } else { alpm_pkg_t *spkg = _alpm_db_get_pkgfromcache(sdb, lpkg->name); if(spkg) { if(check_literal(handle, lpkg, spkg, enable_downgrade)) { trans->add = alpm_list_add(trans->add, spkg); } /* jump to next local package */ break; } } } } return 0; }
/** Checks dependencies and returns missing ones in a list. * Dependencies can include versions with depmod operators. * @param handle the context handle * @param pkglist the list of local packages * @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) * @param reversedeps handles the backward dependencies * @return an alpm_list_t* of pmdepmissing_t pointers. */ alpm_list_t SYMEXPORT *alpm_checkdeps(pmhandle_t *handle, alpm_list_t *pkglist, alpm_list_t *remove, alpm_list_t *upgrade, int reversedeps) { alpm_list_t *i, *j; alpm_list_t *targets, *dblist = NULL, *modified = NULL; alpm_list_t *baddeps = NULL; int nodepversion; CHECK_HANDLE(handle, return NULL); targets = alpm_list_join(alpm_list_copy(remove), alpm_list_copy(upgrade)); for(i = pkglist; i; i = i->next) { pmpkg_t *pkg = i->data; if(_alpm_pkg_find(targets, pkg->name)) { modified = alpm_list_add(modified, pkg); } else { dblist = alpm_list_add(dblist, pkg); } } alpm_list_free(targets); nodepversion = no_dep_version(handle); /* look for unsatisfied dependencies of the upgrade list */ for(i = upgrade; i; i = i->next) { pmpkg_t *tp = i->data; _alpm_log(handle, 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; depend = filtered_depend(depend, nodepversion); /* 1. we check the upgrade list */ /* 2. we check database for untouched satisfying packages */ if(!find_dep_satisfier(upgrade, depend) && !find_dep_satisfier(dblist, depend)) { /* Unsatisfied dependency in the upgrade list */ pmdepmissing_t *miss; char *missdepstring = alpm_dep_compute_string(depend); _alpm_log(handle, PM_LOG_DEBUG, "checkdeps: missing dependency '%s' for package '%s'\n", missdepstring, alpm_pkg_get_name(tp)); free(missdepstring); miss = depmiss_new(alpm_pkg_get_name(tp), depend, NULL); baddeps = alpm_list_add(baddeps, miss); } release_filtered_depend(depend, nodepversion); } } if(reversedeps) { /* reversedeps handles the backwards dependencies, ie, * the packages listed in the requiredby field. */ 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; depend = filtered_depend(depend, nodepversion); pmpkg_t *causingpkg = find_dep_satisfier(modified, depend); /* 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(causingpkg && !find_dep_satisfier(upgrade, depend) && !find_dep_satisfier(dblist, depend)) { pmdepmissing_t *miss; char *missdepstring = alpm_dep_compute_string(depend); _alpm_log(handle, PM_LOG_DEBUG, "checkdeps: transaction would break '%s' dependency of '%s'\n", missdepstring, alpm_pkg_get_name(lp)); free(missdepstring); miss = depmiss_new(lp->name, depend, alpm_pkg_get_name(causingpkg)); baddeps = alpm_list_add(baddeps, miss); } release_filtered_depend(depend, nodepversion); } } } alpm_list_free(modified); alpm_list_free(dblist); return baddeps; }
/* Normal -S, install packages from AUR * returns 0 on success, -1 on failure */ static int sync_targets(CURL *curl, alpm_list_t *targets) { struct pw_hashdb *hashdb = build_hashdb(); struct pkgpair pkgpair; struct pkgpair *pkgpair_ptr; struct aurpkg_t *aurpkg; alpm_pkg_t *lpkg; alpm_list_t *i; alpm_list_t *reinstall, *new_packages, *upgrade, *downgrade, *not_aur; alpm_list_t *aurpkg_list, *final_targets; int vercmp; int joined = 0, ret = 0; reinstall = new_packages = upgrade = downgrade = aurpkg_list = not_aur = NULL; final_targets = NULL; if (!hashdb) { pw_fprintf(PW_LOG_ERROR, stderr, "Failed to create hashdb\n"); goto cleanup; } for (i = targets; i; i = i->next) { aurpkg_list = query_aur(curl, i->data, AUR_QUERY_INFO); if (!aurpkg_list) { not_aur = alpm_list_add(not_aur, i->data); goto free_aurpkg; } /* Check version string */ pkgpair.pkgname = i->data; pkgpair_ptr = hash_search(hashdb->aur, &pkgpair); /* Locally installed AUR */ if (pkgpair_ptr) { aurpkg = aurpkg_list->data; lpkg = pkgpair_ptr->pkg; vercmp = alpm_pkg_vercmp(aurpkg->version, alpm_pkg_get_version(lpkg)); if (vercmp > 0) { upgrade = alpm_list_add(upgrade, i->data); } else if (vercmp == 0) { reinstall = alpm_list_add(reinstall, i->data); } else { downgrade = alpm_list_add(downgrade, i->data); } } else { new_packages = alpm_list_add(new_packages, i->data); } free_aurpkg: alpm_list_free_inner(aurpkg_list, (alpm_list_fn_free) aurpkg_free); alpm_list_free(aurpkg_list); } if (not_aur) { printf("\n%sThese packages are not from the AUR:%s\n", color.bred, color.nocolor); print_list(not_aur); } if (downgrade) { printf("\n%sLocally installed but newer than AUR, ignoring:%s\n", color.bcyan, color.nocolor); print_list(downgrade); } if (reinstall) { printf("\n%sReinstalling:%s\n", color.byellow, color.nocolor); print_list(reinstall); } if (upgrade) { printf("\n%sUpgrading:%s\n", color.bblue, color.nocolor); print_list(upgrade); } if (new_packages) { printf("\n%sSyncing:%s\n", color.bmag, color.nocolor); print_list(new_packages); } printf("\n"); if (config->noconfirm || yesno("Do you wish to proceed?")) { final_targets = alpm_list_join(reinstall, upgrade); final_targets = alpm_list_join(final_targets, new_packages); joined = 1; ret = upgrade_pkgs(final_targets, hashdb); } cleanup: hashdb_free(hashdb); alpm_list_free(downgrade); alpm_list_free(not_aur); if (joined) { alpm_list_free(final_targets); } else { alpm_list_free(reinstall); alpm_list_free(new_packages); alpm_list_free(upgrade); } return ret; }
/** * pacman_list_concat: * @first: A #PacmanList. * @second: A #PacmanList. * * Creates a new list by appending @second to @first. * * Returns: A #PacmanList composed of @first and @second. Do not use or free @first or @second afterwards. */ PacmanList *pacman_list_concat (PacmanList *first, PacmanList *second) { return alpm_list_join (first, second); }
/** * @brief Remove a package's files, optionally skipping its replacement's * files. * * @param handle the context handle * @param oldpkg package to remove * @param newpkg package to replace \a oldpkg (optional) * @param targ_count current index within the transaction (1-based) * @param pkg_count the number of packages affected by the transaction * * @return 0 on success, -1 if alpm lacks permission to delete some of the * files, >0 the number of files alpm was unable to delete */ static int remove_package_files(alpm_handle_t *handle, alpm_pkg_t *oldpkg, alpm_pkg_t *newpkg, size_t targ_count, size_t pkg_count) { alpm_list_t *skip_remove; alpm_filelist_t *filelist; size_t i; int err = 0; int nosave = handle->trans->flags & ALPM_TRANS_FLAG_NOSAVE; if(newpkg) { alpm_filelist_t *newfiles; alpm_list_t *b; skip_remove = alpm_list_join( alpm_list_strdup(handle->trans->skip_remove), alpm_list_strdup(handle->noupgrade)); /* Add files in the NEW backup array to the skip_remove array * so this removal operation doesn't kill them */ /* old package backup list */ newfiles = alpm_pkg_get_files(newpkg); for(b = alpm_pkg_get_backup(newpkg); b; b = b->next) { const alpm_backup_t *backup = b->data; /* safety check (fix the upgrade026 pactest) */ if(!alpm_filelist_contains(newfiles, backup->name)) { continue; } _alpm_log(handle, ALPM_LOG_DEBUG, "adding %s to the skip_remove array\n", backup->name); skip_remove = alpm_list_add(skip_remove, strdup(backup->name)); } } else { skip_remove = alpm_list_strdup(handle->trans->skip_remove); } filelist = alpm_pkg_get_files(oldpkg); for(i = 0; i < filelist->count; i++) { alpm_file_t *file = filelist->files + i; if(!can_remove_file(handle, file, skip_remove)) { _alpm_log(handle, ALPM_LOG_DEBUG, "not removing package '%s', can't remove all files\n", oldpkg->name); FREELIST(skip_remove); RET_ERR(handle, ALPM_ERR_PKG_CANT_REMOVE, -1); } } _alpm_log(handle, ALPM_LOG_DEBUG, "removing %zd files\n", filelist->count); if(!newpkg) { /* init progress bar, but only on true remove transactions */ PROGRESS(handle, ALPM_PROGRESS_REMOVE_START, oldpkg->name, 0, pkg_count, targ_count); } /* iterate through the list backwards, unlinking files */ for(i = filelist->count; i > 0; i--) { alpm_file_t *file = filelist->files + i - 1; if(unlink_file(handle, oldpkg, newpkg, file, skip_remove, nosave) < 0) { err++; } if(!newpkg) { /* update progress bar after each file */ int percent = ((filelist->count - i) * 100) / filelist->count; PROGRESS(handle, ALPM_PROGRESS_REMOVE_START, oldpkg->name, percent, pkg_count, targ_count); } } FREELIST(skip_remove); if(!newpkg) { /* set progress to 100% after we finish unlinking files */ PROGRESS(handle, ALPM_PROGRESS_REMOVE_START, oldpkg->name, 100, pkg_count, targ_count); } return err; }