Пример #1
0
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);
}
Пример #2
0
/**
 * @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;
}
Пример #3
0
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;
}
Пример #4
0
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;
}
Пример #5
0
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;
}
Пример #6
0
/* 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;
}
Пример #7
0
/**
 * 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);
}
Пример #8
0
/**
 * @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;
}
Пример #9
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);
}
Пример #10
0
/**
 * @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);
}
Пример #11
0
/**
 * @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;
}