Example #1
0
File: util.c Project: bougyman/xbps
int
xbps_pkg_is_installed(struct xbps_handle *xhp, const char *pkg)
{
	xbps_dictionary_t dict;
	pkg_state_t state;

	assert(xhp);
	assert(pkg);

	if (((dict = xbps_pkgdb_get_virtualpkg(xhp, pkg)) == NULL) &&
	    ((dict = xbps_pkgdb_get_pkg(xhp, pkg)) == NULL))
		return 0; /* not installed */
	/*
	 * Check that package state is fully installed, not
	 * unpacked or something else.
	 */
	if (xbps_pkg_state_dictionary(dict, &state) != 0)
		return -1; /* error */
	if (state == XBPS_PKG_STATE_INSTALLED || state == XBPS_PKG_STATE_UNPACKED)
		return 1;

	return 0; /* not fully installed */
}
Example #2
0
static int
find_repo_deps(struct xbps_handle *xhp,
	       xbps_array_t unsorted,		/* array of unsorted deps */
	       xbps_array_t pkg_rdeps_array,	/* current pkg rundeps array  */
	       xbps_array_t pkg_provides,	/* current pkg provides array */
	       const char *curpkg,		/* current pkgver */
	       unsigned short *depth)		/* max recursion depth */
{
	xbps_dictionary_t curpkgd = NULL;
	xbps_object_t obj;
	xbps_object_iterator_t iter;
	xbps_array_t curpkgrdeps = NULL, curpkgprovides = NULL;
	pkg_state_t state;
	const char *reqpkg, *pkgver_q, *reason = NULL;
	char *pkgname, *reqpkgname;
	int rv = 0;
	bool foundvpkg;

	if (*depth >= MAX_DEPTH)
		return ELOOP;

	/*
	 * Iterate over the list of required run dependencies for
	 * current package.
	 */
	iter = xbps_array_iterator(pkg_rdeps_array);
	assert(iter);

	while ((obj = xbps_object_iterator_next(iter))) {
		foundvpkg = false;
		reqpkg = xbps_string_cstring_nocopy(obj);
		if (xhp->flags & XBPS_FLAG_DEBUG) {
			xbps_dbg_printf(xhp, "%s", "");
			for (unsigned short x = 0; x < *depth; x++) {
				xbps_dbg_printf_append(xhp, " ");
			}
			xbps_dbg_printf_append(xhp, "%s: requires dependency '%s': ", curpkg ? curpkg : " ", reqpkg);
		}
		if (((pkgname = xbps_pkgpattern_name(reqpkg)) == NULL) &&
		    ((pkgname = xbps_pkg_name(reqpkg)) == NULL)) {
			xbps_dbg_printf(xhp, "%s: can't guess pkgname for dependency: %s\n", curpkg, reqpkg);
			xbps_set_cb_state(xhp, XBPS_STATE_INVALID_DEP, ENXIO, NULL,
			    "%s: can't guess pkgname for dependency '%s'", curpkg, reqpkg);
			rv = ENXIO;
			break;
		}
		/*
		 * Pass 1: check if required dependency is provided as virtual
		 * package via "provides", if true ignore dependency.
		 */
		if (pkg_provides && xbps_match_virtual_pkg_in_array(pkg_provides, reqpkg)) {
			xbps_dbg_printf_append(xhp, "%s is a vpkg provided by %s, ignored.\n", pkgname, curpkg);
			free(pkgname);
			continue;
		}
		/*
		 * Pass 2: check if required dependency has been already
		 * added in the transaction dictionary.
		 */
		if ((curpkgd = xbps_find_pkg_in_array(unsorted, reqpkg, NULL)) ||
		    (curpkgd = xbps_find_virtualpkg_in_array(xhp, unsorted, reqpkg, NULL))) {
			xbps_dictionary_get_cstring_nocopy(curpkgd, "pkgver", &pkgver_q);
			xbps_dbg_printf_append(xhp, " (%s queued)\n", pkgver_q);
			free(pkgname);
			continue;
		}
		/*
		 * Pass 3: check if required dependency is already installed
		 * and its version is fully matched.
		 */
		if ((curpkgd = xbps_pkgdb_get_pkg(xhp, pkgname)) == NULL) {
			if ((curpkgd = xbps_pkgdb_get_virtualpkg(xhp, pkgname))) {
				foundvpkg = true;
			}
		}
		if (curpkgd == NULL) {
			if (errno && errno != ENOENT) {
				/* error */
				rv = errno;
				xbps_dbg_printf(xhp, "failed to find installed pkg for `%s': %s\n", reqpkg, strerror(rv));
				free(pkgname);
				break;
			}
			free(pkgname);
			/* Required dependency not installed */
			xbps_dbg_printf_append(xhp, "not installed.\n");
			reason = "install";
			state = XBPS_PKG_STATE_NOT_INSTALLED;
		} else {
			/*
			 * Required dependency is installed, check if its version can
			 * satisfy the requirements.
			 */
			xbps_dictionary_get_cstring_nocopy(curpkgd, "pkgver", &pkgver_q);

			/* Check its state */
			if ((rv = xbps_pkg_state_dictionary(curpkgd, &state)) != 0) {
				free(pkgname);
				break;
			}

			if (foundvpkg && xbps_match_virtual_pkg_in_dict(curpkgd, reqpkg)) {
				/*
				 * Check if required dependency is a virtual package and is satisfied
				 * by an installed package.
				 */
				xbps_dbg_printf_append(xhp, "[virtual] satisfied by `%s'.\n", pkgver_q);
				free(pkgname);
				continue;
			}
			rv = xbps_pkgpattern_match(pkgver_q, reqpkg);
			if (rv == 0) {
				char *curpkgname;
				/*
				 * The version requirement is not satisfied.
				 */
				curpkgname = xbps_pkg_name(pkgver_q);
				assert(curpkgname);
				if (strcmp(pkgname, curpkgname)) {
					xbps_dbg_printf_append(xhp, "not installed `%s (vpkg)'", pkgver_q);
					if (xbps_dictionary_get(curpkgd, "hold")) {
						xbps_dbg_printf_append(xhp, " on hold state! ignoring package.\n");
					} else {
						xbps_dbg_printf_append(xhp, "\n");
						reason = "install";
					}
				} else {
					xbps_dbg_printf_append(xhp, "installed `%s', must be updated", pkgver_q);
					if (xbps_dictionary_get(curpkgd, "hold")) {
						xbps_dbg_printf_append(xhp, " on hold state! ignoring package.\n");
					} else {
						xbps_dbg_printf_append(xhp, "\n");
						reason = "update";
					}
				}
				free(curpkgname);
				free(pkgname);
			} else if (rv == 1) {
				/*
				 * The version requirement is satisfied.
				 */
				free(pkgname);
				rv = 0;
				if (state == XBPS_PKG_STATE_UNPACKED) {
					/*
					 * Package matches the dependency pattern but was only unpacked,
					 * configure pkg.
					 */
					xbps_dbg_printf_append(xhp, "installed `%s', must be configured.\n", pkgver_q);
					reason = "configure";
				} else if (state == XBPS_PKG_STATE_INSTALLED) {
					/*
					 * Package matches the dependency pattern and is fully installed,
					 * skip to next one.
					 */
					xbps_dbg_printf_append(xhp, "installed `%s'.\n", pkgver_q);
					continue;
				}
			} else {
				/* error matching pkgpattern */
				xbps_dbg_printf(xhp, "failed to match pattern %s with %s\n", reqpkg, pkgver_q);
				free(pkgname);
				break;
			}
		}
		if (xbps_dictionary_get(curpkgd, "hold")) {
			xbps_dbg_printf(xhp, "%s on hold state! ignoring package.\n", curpkg);
			continue;
		}
		/*
		 * Pass 4: find required dependency in repository pool.
		 * If dependency does not match add pkg into the missing
		 * deps array and pass to next one.
		 */
		if (((curpkgd = xbps_rpool_get_pkg(xhp, reqpkg)) == NULL) &&
		    ((curpkgd = xbps_rpool_get_virtualpkg(xhp, reqpkg)) == NULL)) {
			/* pkg not found, there was some error */
			if (errno && errno != ENOENT) {
				xbps_dbg_printf(xhp, "failed to find pkg for `%s' in rpool: %s\n", reqpkg, strerror(errno));
				rv = errno;
				break;
			}
			rv = add_missing_reqdep(xhp, reqpkg);
			if (rv != 0 && rv != EEXIST) {
				xbps_dbg_printf(xhp, "`%s': add_missing_reqdep failed\n", reqpkg);
				break;
			} else if (rv == EEXIST) {
				xbps_dbg_printf(xhp, "`%s' missing dep already added.\n", reqpkg);
				rv = 0;
				continue;
			} else {
				xbps_dbg_printf(xhp, "`%s' added into the missing deps array.\n", reqpkg);
				continue;
			}
		}
		xbps_dictionary_get_cstring_nocopy(curpkgd, "pkgver", &pkgver_q);
		reqpkgname = xbps_pkg_name(pkgver_q);
		assert(reqpkgname);
		/*
		 * Check dependency validity.
		 */
		pkgname = xbps_pkg_name(curpkg);
		assert(pkgname);
		if (strcmp(pkgname, reqpkgname) == 0) {
			xbps_dbg_printf_append(xhp, "[ignoring wrong dependency %s (depends on itself)]\n", reqpkg);
			xbps_remove_string_from_array(pkg_rdeps_array, reqpkg);
			free(pkgname);
			free(reqpkgname);
			continue;
		}
		free(pkgname);
		free(reqpkgname);
		/*
		 * If package doesn't have rundeps, pass to the next one.
		 */
		curpkgrdeps = xbps_dictionary_get(curpkgd, "run_depends");
		if (curpkgrdeps == NULL) {
			/*
			 * Package is on repo, add it into the transaction dictionary.
			 */
			xbps_dictionary_set_cstring_nocopy(curpkgd, "transaction", reason);
			rv = xbps_transaction_store(xhp, unsorted, curpkgd, reason, true);
			if (rv != 0) {
				xbps_dbg_printf(xhp, "xbps_transaction_store failed for `%s': %s\n", reqpkg, strerror(rv));
				break;
			}
			continue;
		}

		if (xhp->flags & XBPS_FLAG_DEBUG) {
			xbps_dbg_printf(xhp, "%s", "");
			for (unsigned short x = 0; x < *depth; x++) {
				xbps_dbg_printf_append(xhp, " ");
			}
			xbps_dbg_printf_append(xhp, "%s: finding dependencies:\n", pkgver_q);
		}
		/*
		 * Recursively find rundeps for current pkg dictionary.
		 */
		(*depth)++;
		curpkgprovides = xbps_dictionary_get(curpkgd, "provides");
		rv = find_repo_deps(xhp, unsorted, curpkgrdeps, curpkgprovides, pkgver_q, depth);
		if (rv != 0) {
			xbps_dbg_printf(xhp, "Error checking %s for rundeps: %s\n", reqpkg, strerror(rv));
			break;
		}
		/*
		 * Package is on repo, add it into the transaction dictionary.
		 */
		xbps_dictionary_set_cstring_nocopy(curpkgd, "transaction", reason);
		rv = xbps_transaction_store(xhp, unsorted, curpkgd, reason, true);
		if (rv != 0) {
			xbps_dbg_printf(xhp, "xbps_transaction_store failed for `%s': %s\n", reqpkg, strerror(rv));
			break;
		}
	}
	xbps_object_iterator_release(iter);
	(*depth)--;

	return rv;
}
Example #3
0
int HIDDEN
xbps_remove_pkg(struct xbps_handle *xhp, const char *pkgver, bool update)
{
	xbps_dictionary_t pkgd = NULL, pkgfilesd = NULL;
	char *pkgname, metafile[PATH_MAX];
	int rv = 0;
	pkg_state_t state = 0;
	uid_t euid;

	assert(xhp);
	assert(pkgver);

	pkgname = xbps_pkg_name(pkgver);
	assert(pkgname);

	euid = geteuid();

	if ((pkgd = xbps_pkgdb_get_pkg(xhp, pkgname)) == NULL) {
		rv = errno;
		xbps_dbg_printf(xhp, "[remove] cannot find %s in pkgdb: %s\n",
		    pkgver, strerror(rv));
		goto out;
	}
	if ((rv = xbps_pkg_state_dictionary(pkgd, &state)) != 0) {
		xbps_dbg_printf(xhp, "[remove] cannot find %s in pkgdb: %s\n",
		    pkgver, strerror(rv));
		goto out;
	}
	xbps_dbg_printf(xhp, "attempting to remove %s state %d\n", pkgver, state);

	if (!update)
		xbps_set_cb_state(xhp, XBPS_STATE_REMOVE, 0, pkgver, NULL);

	if (chdir(xhp->rootdir) == -1) {
		rv = errno;
		xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FAIL,
		    rv, pkgver,
		   "%s: [remove] failed to chdir to rootdir `%s': %s",
		    pkgver, xhp->rootdir, strerror(rv));
		goto out;
	}

	/* internalize pkg files dictionary from metadir */
	snprintf(metafile, sizeof(metafile), "%s/.%s-files.plist", xhp->metadir, pkgname);
	pkgfilesd = xbps_plist_dictionary_from_file(xhp, metafile);
	if (pkgfilesd == NULL)
		xbps_dbg_printf(xhp, "WARNING: metaplist for %s "
		    "doesn't exist!\n", pkgver);

	/* If package was "half-removed", remove it fully. */
	if (state == XBPS_PKG_STATE_HALF_REMOVED)
		goto purge;
	/*
	 * Run the pre remove action and show pre-remove message if exists.
	 */
	rv = xbps_pkg_exec_script(xhp, pkgd, "remove-script", "pre", update);
	if (rv != 0) {
		xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FAIL,
		    errno, pkgver,
		    "%s: [remove] REMOVE script failed to "
		    "execute pre ACTION: %s",
		    pkgver, strerror(rv));
		goto out;
	}
	/* show remove-msg if exists */
	if ((rv = xbps_cb_message(xhp, pkgd, "remove-msg")) != 0)
		goto out;

	/* unregister alternatives */
	if (update)
		xbps_dictionary_set_bool(pkgd, "alternatives-update", true);

	if ((rv = xbps_alternatives_unregister(xhp, pkgd)) != 0)
		goto out;

	/*
	 * If updating a package, we just need to execute the current
	 * pre-remove action target and we are done. Its files will be
	 * overwritten later in unpack phase.
	 */
	if (update) {
		free(pkgname);
		return 0;
	}

	if (pkgfilesd) {
		/*
		 * Do the removal in 2 phases:
		 * 	1- check if user has enough perms to remove all entries
		 * 	2- perform removal
		 */
		if (check_remove_pkg_files(xhp, pkgfilesd, pkgver, euid)) {
			rv = EPERM;
			goto out;
		}
		/* Remove links */
		if ((rv = remove_pkg_files(xhp, pkgfilesd, "links", pkgver)) != 0)
			goto out;
		/* Remove regular files */
		if ((rv = remove_pkg_files(xhp, pkgfilesd, "files", pkgver)) != 0)
			goto out;
		/* Remove configuration files */
		if ((rv = remove_pkg_files(xhp, pkgfilesd, "conf_files", pkgver)) != 0)
			goto out;
		/* Remove dirs */
		if ((rv = remove_pkg_files(xhp, pkgfilesd, "dirs", pkgver)) != 0)
			goto out;
	}
	/*
	 * Execute the post REMOVE action if file exists and we aren't
	 * updating the package.
	 */
	rv = xbps_pkg_exec_script(xhp, pkgd, "remove-script", "post", false);
	if (rv != 0) {
		xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FAIL,
		    rv, pkgver,
		    "%s: [remove] REMOVE script failed to execute "
		    "post ACTION: %s", pkgver, strerror(rv));
		goto out;
	}
	/*
	 * Set package state to "half-removed".
	 */
	rv = xbps_set_pkg_state_installed(xhp, pkgver,
	     XBPS_PKG_STATE_HALF_REMOVED);
	if (rv != 0) {
		xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FAIL,
		    rv, pkgver,
		    "%s: [remove] failed to set state to half-removed: %s",
		    pkgver, strerror(rv));
		goto out;
	}

purge:
	/*
	 * Execute the purge REMOVE action if file exists.
	 */
	rv = xbps_pkg_exec_script(xhp, pkgd, "remove-script", "purge", false);
	if (rv != 0) {
		xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FAIL,
		    rv, pkgver,
		    "%s: REMOVE script failed to execute "
		    "purge ACTION: %s", pkgver, strerror(rv));
		goto out;
	}
	/*
	 * Remove package metadata plist.
	 */
	if (remove(metafile) == -1) {
		if (errno != ENOENT) {
			xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FAIL,
			    rv, pkgver,
			    "%s: failed to remove metadata file: %s",
			    pkgver, strerror(errno));
		}
	}
	/*
	 * Unregister package from pkgdb.
	 */
	xbps_dictionary_remove(xhp->pkgdb, pkgname);
	xbps_dbg_printf(xhp, "[remove] unregister %s returned %d\n", pkgver, rv);
	xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_DONE, 0, pkgver, NULL);
out:
	if (pkgname != NULL)
		free(pkgname);
	if (rv != 0) {
		xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FAIL, rv, pkgver,
		    "%s: failed to remove package: %s", pkgver, strerror(rv));
	}

	return rv;
}
Example #4
0
File: list.c Project: xdave/xbps
int
list_pkgs_in_dict(struct xbps_handle *xhp,
		  prop_object_t obj,
		  void *arg,
		  bool *loop_done)
{
	struct list_pkgver_cb *lpc = arg;
	const char *pkgver, *short_desc, *arch;
	char *tmp = NULL, *out = NULL;
	pkg_state_t curstate;
	size_t i, len = 0;
	bool chkarch;

	(void)xhp;
	(void)loop_done;

	chkarch = prop_dictionary_get_cstring_nocopy(obj, "architecture", &arch);
	if (chkarch && !xbps_pkg_arch_match(xhp, arch, NULL))
		return 0;

	if (lpc->check_state) {
		if (xbps_pkg_state_dictionary(obj, &curstate))
			return EINVAL;
		if (lpc->state == 0) {
			/* Only list packages that are fully installed */
			if (curstate != XBPS_PKG_STATE_INSTALLED)
				return 0;
		} else {
			/* Only list packages with specified state */
			if (curstate != lpc->state)
				return 0;
		}
	}

	prop_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver);
	prop_dictionary_get_cstring_nocopy(obj, "short_desc", &short_desc);
	if (!pkgver && !short_desc)
		return EINVAL;

	tmp = calloc(1, lpc->pkgver_len + 1);
	assert(tmp);
	memcpy(tmp, pkgver, lpc->pkgver_len);
	for (i = strlen(tmp); i < lpc->pkgver_len; i++)
		tmp[i] = ' ';

	tmp[i] = '\0';
	len = strlen(tmp) + strlen(short_desc) + 1;
	if (len > lpc->maxcols) {
		out = malloc(lpc->maxcols);
		assert(out);
		snprintf(out, lpc->maxcols-2, "%s %s", tmp, short_desc);
		strncat(out, "...", lpc->maxcols);
		printf("%s\n", out);
		free(out);
	} else {
		printf("%s %s\n", tmp, short_desc);
	}
	free(tmp);

	return 0;
}