void display_targets(void) { alpm_list_t *i, *targets = NULL; alpm_db_t *db_local = alpm_get_localdb(config->handle); for(i = alpm_trans_get_add(config->handle); i; i = alpm_list_next(i)) { alpm_pkg_t *pkg = i->data; pm_target_t *targ = calloc(1, sizeof(pm_target_t)); if(!targ) return; targ->install = pkg; targ->remove = alpm_db_get_pkg(db_local, alpm_pkg_get_name(pkg)); if(alpm_list_find(config->explicit_adds, pkg, pkg_cmp)) { targ->is_explicit = 1; } targets = alpm_list_add(targets, targ); } for(i = alpm_trans_get_remove(config->handle); i; i = alpm_list_next(i)) { alpm_pkg_t *pkg = i->data; pm_target_t *targ = calloc(1, sizeof(pm_target_t)); if(!targ) return; targ->remove = pkg; if(alpm_list_find(config->explicit_removes, pkg, pkg_cmp)) { targ->is_explicit = 1; } targets = alpm_list_add(targets, targ); } targets = alpm_list_msort(targets, alpm_list_count(targets), target_cmp); _display_targets(targets, config->verbosepkglists); FREELIST(targets); }
/** * @brief Check if alpm can delete a file. * * @param handle the context handle * @param file file to be removed * @param skip_remove list of files that will not be removed * * @return 1 if the file can be deleted, 0 if it cannot be deleted */ static int can_remove_file(alpm_handle_t *handle, const alpm_file_t *file, alpm_list_t *skip_remove) { char filepath[PATH_MAX]; if(alpm_list_find(skip_remove, file->name, _alpm_fnmatch)) { /* return success because we will never actually remove this file */ return 1; } snprintf(filepath, PATH_MAX, "%s%s", handle->root, file->name); if(file->name[strlen(file->name) - 1] == '/' && dir_is_mountpoint(handle, filepath, NULL)) { /* we do not remove mountpoints */ return 1; } /* If we fail write permissions due to a read-only filesystem, abort. * Assume all other possible failures are covered somewhere else */ if(_alpm_access(handle, NULL, filepath, W_OK) == -1) { if(errno != EACCES && errno != ETXTBSY && access(filepath, F_OK) == 0) { /* only return failure if the file ACTUALLY exists and we can't write to * it - ignore "chmod -w" simple permission failures */ _alpm_log(handle, ALPM_LOG_ERROR, _("cannot remove file '%s': %s\n"), filepath, strerror(errno)); return 0; } } return 1; }
int target_arg_add (target_arg_t *t, const char *s, void *item) { int ret=1; if (t && config.just_one) { if ((t->cmp_fn && alpm_list_find (t->items, item, t->cmp_fn)) || (!t->cmp_fn && alpm_list_find_ptr (t->items, item))) ret = 0; else if (t->dup_fn) t->items = alpm_list_add (t->items, t->dup_fn (item)); else t->items = alpm_list_add (t->items, item); t->args = alpm_list_add (t->args, (void *) s); } return ret; }
bool target_arg_add (target_arg_t *t, const char *s, void *item) { bool ret = true; if (t && config.just_one) { if ((t->cmp_fn && alpm_list_find (t->items, item, t->cmp_fn)) || (!t->cmp_fn && alpm_list_find_ptr (t->items, item))) { ret = false; } else if (t->dup_fn) { t->items = alpm_list_add (t->items, t->dup_fn (item)); } else { t->items = alpm_list_add (t->items, item); } t->args = alpm_list_add (t->args, (void *) s); } return ret; }
static PkBackendConfigSection * pk_backend_config_enter_section (PkBackendConfig *config, const gchar *name) { PkBackendConfigSection *section; g_return_val_if_fail (config != NULL, NULL); g_return_val_if_fail (name != NULL, NULL); section = alpm_list_find (config->sections, name, pk_backend_config_section_match); if (section != NULL) { return section; } section = g_new0 (PkBackendConfigSection, 1); section->name = g_strdup (name); config->sections = alpm_list_add (config->sections, section); return section; }
/* Re-order a list of target packages with respect to their dependencies. * * Example (reverse == 0): * A depends on C * B depends on A * Target order is A,B,C,D * * Should be re-ordered to C,A,B,D * * packages listed in ignore will not be used to detect indirect dependencies * * if reverse is > 0, the dependency order will be reversed. * * This function returns the new alpm_list_t* target list. * */ alpm_list_t *_alpm_sortbydeps(alpm_handle_t *handle, alpm_list_t *targets, alpm_list_t *ignore, int reverse) { alpm_list_t *newtargs = NULL; alpm_list_t *vertices = NULL; alpm_list_t *vptr; alpm_graph_t *vertex; if(targets == NULL) { return NULL; } _alpm_log(handle, ALPM_LOG_DEBUG, "started sorting dependencies\n"); vertices = dep_graph_init(handle, targets, ignore); vptr = vertices; vertex = vertices->data; while(vptr) { /* mark that we touched the vertex */ vertex->state = -1; int found = 0; while(vertex->childptr && !found) { alpm_graph_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) { /* child is an ancestor of vertex */ alpm_graph_t *transvertex = vertex; if(!alpm_list_find(targets, nextchild->data, ptr_cmp)) { /* child is not part of the transaction, not a problem */ continue; } /* find the nearest parent that's part of the transaction */ while(transvertex) { if(alpm_list_find(targets, transvertex->data, ptr_cmp)) { break; } transvertex = transvertex->parent; } if(!transvertex || transvertex == nextchild) { /* no transaction package in our ancestry or the package has * a circular dependency with itself, not a problem */ } else { alpm_pkg_t *transpkg = transvertex->data; alpm_pkg_t *childpkg = nextchild->data; _alpm_log(handle, ALPM_LOG_WARNING, _("dependency cycle detected:\n")); if(reverse) { _alpm_log(handle, ALPM_LOG_WARNING, _("%s will be removed after its %s dependency\n"), transpkg->name, childpkg->name); } else { _alpm_log(handle, ALPM_LOG_WARNING, _("%s will be installed before its %s dependency\n"), transpkg->name, childpkg->name); } } } } if(!found) { if(alpm_list_find(targets, vertex->data, ptr_cmp)) { newtargs = alpm_list_add(newtargs, vertex->data); } /* mark that we've left this vertex */ vertex->state = 1; vertex = vertex->parent; if(!vertex) { /* top level vertex reached, move to the next unprocessed vertex */ for( vptr = vptr->next; vptr; vptr = vptr->next) { vertex = vptr->data; if(vertex->state == 0) { break; } } } } } _alpm_log(handle, ALPM_LOG_DEBUG, "sorting dependencies finished\n"); if(reverse) { /* reverse the order */ alpm_list_t *tmptargs = alpm_list_reverse(newtargs); /* free the old one */ alpm_list_free(newtargs); newtargs = tmptargs; } alpm_list_free_inner(vertices, _alpm_graph_free); alpm_list_free(vertices); return newtargs; }
/** * pacman_list_find: * @haystack: A #PacmanList. * @needle: An item to find. * @func: A #GCompareFunc function. * * Searches @haystack for an item equivalent to @needle (as determined by @func). * * Returns: A list item from @haystack, or %NULL if none were found. */ gpointer pacman_list_find (const PacmanList *haystack, gconstpointer needle, GCompareFunc func) { return alpm_list_find (haystack, needle, (alpm_list_fn_cmp) func); }
/** * @brief Unlink a package file, backing it up if necessary. * * @param handle the context handle * @param oldpkg the package being removed * @param newpkg the package replacing \a oldpkg * @param fileobj file to remove * @param skip_remove list of files that shouldn't be removed * @param nosave whether files should be backed up * * @return 0 on success, -1 if there was an error unlinking the file, 1 if the * file was skipped or did not exist */ static int unlink_file(alpm_handle_t *handle, alpm_pkg_t *oldpkg, alpm_pkg_t *newpkg, const alpm_file_t *fileobj, alpm_list_t *skip_remove, int nosave) { struct stat buf; char file[PATH_MAX]; snprintf(file, PATH_MAX, "%s%s", handle->root, fileobj->name); /* check the remove skip list before removing the file. * see the big comment block in db_find_fileconflicts() for an * explanation. */ if(alpm_list_find(skip_remove, fileobj->name, _alpm_fnmatch)) { _alpm_log(handle, ALPM_LOG_DEBUG, "%s is in skip_remove, skipping removal\n", file); return 1; } if(_alpm_lstat(file, &buf)) { _alpm_log(handle, ALPM_LOG_DEBUG, "file %s does not exist\n", file); return 1; } if(S_ISDIR(buf.st_mode)) { ssize_t files = _alpm_files_in_directory(handle, file, 0); /* if we have files, no need to remove the directory */ if(files > 0) { _alpm_log(handle, ALPM_LOG_DEBUG, "keeping directory %s (contains files)\n", file); } else if(files < 0) { _alpm_log(handle, ALPM_LOG_DEBUG, "keeping directory %s (could not count files)\n", file); } else if(newpkg && alpm_filelist_contains(alpm_pkg_get_files(newpkg), fileobj->name)) { _alpm_log(handle, ALPM_LOG_DEBUG, "keeping directory %s (in new package)\n", file); } else if(dir_is_mountpoint(handle, file, &buf)) { _alpm_log(handle, ALPM_LOG_DEBUG, "keeping directory %s (mountpoint)\n", file); } else { /* one last check- does any other package own this file? */ alpm_list_t *local, *local_pkgs; int found = 0; local_pkgs = _alpm_db_get_pkgcache(handle->db_local); for(local = local_pkgs; local && !found; local = local->next) { alpm_pkg_t *local_pkg = local->data; alpm_filelist_t *filelist; /* we duplicated the package when we put it in the removal list, so we * so we can't use direct pointer comparison here. */ if(oldpkg->name_hash == local_pkg->name_hash && strcmp(oldpkg->name, local_pkg->name) == 0) { continue; } filelist = alpm_pkg_get_files(local_pkg); if(alpm_filelist_contains(filelist, fileobj->name)) { _alpm_log(handle, ALPM_LOG_DEBUG, "keeping directory %s (owned by %s)\n", file, local_pkg->name); found = 1; } } if(!found) { if(rmdir(file)) { _alpm_log(handle, ALPM_LOG_DEBUG, "directory removal of %s failed: %s\n", file, strerror(errno)); return -1; } else { _alpm_log(handle, ALPM_LOG_DEBUG, "removed directory %s (no remaining owners)\n", file); } } } } else { /* if the file needs backup and has been modified, back it up to .pacsave */ alpm_backup_t *backup = _alpm_needbackup(fileobj->name, oldpkg); if(backup) { if(nosave) { _alpm_log(handle, ALPM_LOG_DEBUG, "transaction is set to NOSAVE, not backing up '%s'\n", file); } else { char *filehash = alpm_compute_md5sum(file); int cmp = filehash ? strcmp(filehash, backup->hash) : 0; FREE(filehash); if(cmp != 0) { char *newpath; size_t len = strlen(file) + 8 + 1; MALLOC(newpath, len, RET_ERR(handle, ALPM_ERR_MEMORY, -1)); shift_pacsave(handle, file); snprintf(newpath, len, "%s.pacsave", file); if(rename(file, newpath)) { _alpm_log(handle, ALPM_LOG_ERROR, _("could not rename %s to %s (%s)\n"), file, newpath, strerror(errno)); alpm_logaction(handle, ALPM_CALLER_PREFIX, "error: could not rename %s to %s (%s)\n", file, newpath, strerror(errno)); free(newpath); return -1; } _alpm_log(handle, ALPM_LOG_WARNING, _("%s saved as %s\n"), file, newpath); alpm_logaction(handle, ALPM_CALLER_PREFIX, "warning: %s saved as %s\n", file, newpath); free(newpath); return 0; } } } _alpm_log(handle, ALPM_LOG_DEBUG, "unlinking %s\n", file); if(unlink(file) == -1) { _alpm_log(handle, ALPM_LOG_ERROR, _("cannot remove %s (%s)\n"), file, strerror(errno)); alpm_logaction(handle, ALPM_CALLER_PREFIX, "error: cannot remove %s (%s)\n", file, strerror(errno)); return -1; } } return 0; }
/** * @brief Find a string in a list. * * @param needle the string to search for * @param haystack the list * * @return `needle` if found, NULL otherwise */ char SYMEXPORT *alpm_list_find_str(const alpm_list_t *haystack, const char *needle) { return (char *)alpm_list_find(haystack, (const void *)needle, (alpm_list_fn_cmp)strcmp); }
/** * @brief Find an item in a list. * * Search for the item whose data matches that of the `needle`. * * @param needle the data to search for (== comparison) * @param haystack the list * * @return `needle` if found, NULL otherwise */ void SYMEXPORT *alpm_list_find_ptr(const alpm_list_t *haystack, const void *needle) { return alpm_list_find(haystack, needle, ptr_cmp); }
/** * @brief Remove a specified list of packages. * * @param targets a list of packages (as strings) to remove from the system * * @return 0 on success, 1 on failure */ int pacman_remove(alpm_list_t *targets) { int retval = 0; alpm_list_t *i, *data = NULL; if(targets == NULL) { pm_printf(ALPM_LOG_ERROR, _("no targets specified (use -h for help)\n")); return 1; } /* Step 0: create a new transaction */ if(trans_init(config->flags, 0) == -1) { return 1; } /* Step 1: add targets to the created transaction */ for(i = targets; i; i = alpm_list_next(i)) { char *target = i->data; if(strncmp(target, "local/", 6) == 0) { target += 6; } if(remove_target(target) == -1) { retval = 1; } } if(retval == 1) { goto cleanup; } /* Step 2: prepare the transaction based on its type, targets and flags */ if(alpm_trans_prepare(config->handle, &data) == -1) { alpm_errno_t err = alpm_errno(config->handle); pm_printf(ALPM_LOG_ERROR, _("failed to prepare transaction (%s)\n"), alpm_strerror(err)); switch(err) { case ALPM_ERR_UNSATISFIED_DEPS: for(i = data; i; i = alpm_list_next(i)) { alpm_depmissing_t *miss = i->data; char *depstring = alpm_dep_compute_string(miss->depend); colon_printf(_("%s: requires %s\n"), miss->target, depstring); free(depstring); alpm_depmissing_free(miss); } break; default: break; } alpm_list_free(data); retval = 1; goto cleanup; } /* Search for holdpkg in target list */ int holdpkg = 0; for(i = alpm_trans_get_remove(config->handle); i; i = alpm_list_next(i)) { alpm_pkg_t *pkg = i->data; if(alpm_list_find(config->holdpkg, alpm_pkg_get_name(pkg), fnmatch_cmp)) { pm_printf(ALPM_LOG_WARNING, _("%s is designated as a HoldPkg.\n"), alpm_pkg_get_name(pkg)); holdpkg = 1; } } if(holdpkg && (noyes(_("HoldPkg was found in target list. Do you want to continue?")) == 0)) { retval = 1; goto cleanup; } /* Step 3: actually perform the removal */ alpm_list_t *pkglist = alpm_trans_get_remove(config->handle); if(pkglist == NULL) { printf(_(" there is nothing to do\n")); goto cleanup; /* we are done */ } if(config->print) { print_packages(pkglist); goto cleanup; } /* print targets and ask user confirmation */ display_targets(); printf("\n"); if(yesno(_("Do you want to remove these packages?")) == 0) { retval = 1; goto cleanup; } if(alpm_trans_commit(config->handle, &data) == -1) { pm_printf(ALPM_LOG_ERROR, _("failed to commit transaction (%s)\n"), alpm_strerror(alpm_errno(config->handle))); retval = 1; } FREELIST(data); /* Step 4: release transaction resources */ cleanup: if(trans_release() == -1) { retval = 1; } return retval; }