Пример #1
0
static bool
check_remove_pkg_files(struct xbps_handle *xhp,
	xbps_dictionary_t pkgd, const char *pkgver, uid_t euid)
{
	struct stat st;
	xbps_array_t array;
	xbps_object_iterator_t iter;
	xbps_object_t obj;
	const char *objs[] = { "files", "conf_files", "links", "dirs" };
	const char *file;
	char path[PATH_MAX];
	bool fail = false;

	for (uint8_t i = 0; i < __arraycount(objs); i++) {
		array = xbps_dictionary_get(pkgd, objs[i]);
		if (array == NULL || xbps_array_count(array) == 0)
			continue;

		iter = xbps_array_iter_from_dict(pkgd, objs[i]);
		if (iter == NULL)
			continue;

		while ((obj = xbps_object_iterator_next(iter))) {
			xbps_dictionary_get_cstring_nocopy(obj, "file", &file);
			snprintf(path, sizeof(path), "%s/%s", xhp->rootdir, file);
			/*
			 * Check if effective user ID owns the file; this is
			 * enough to ensure the user has write permissions
			 * on the directory.
			 */
			if (euid == 0 || (!lstat(path, &st) && euid == st.st_uid)) {
				/* success */
				continue;
			}
			if (errno != ENOENT) {
				/*
				 * only bail out if something else than ENOENT
				 * is returned.
				 */
				int rv = errno;
				if (rv == 0) {
					/* lstat succeeds but euid != uid */
					rv = EPERM;
				}
				fail = true;
				xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FILE_FAIL,
				    rv, pkgver,
				    "%s: cannot remove `%s': %s",
				    pkgver, file, strerror(rv));
			}
			errno = 0;
		}
		xbps_object_iterator_release(iter);
	}

	return fail;
}
Пример #2
0
int HIDDEN
xbps_remove_pkg_files(struct xbps_handle *xhp,
		      xbps_dictionary_t dict,
		      const char *key,
		      const char *pkgver)
{
	struct stat st;
	xbps_array_t array;
	xbps_object_iterator_t iter;
	xbps_object_t obj;
	const char *file, *sha256, *curobj = NULL;
	char *path = NULL, *pkgname = NULL;
	char buf[PATH_MAX];
	int rv = 0;

	assert(xbps_object_type(dict) == XBPS_TYPE_DICTIONARY);
	assert(key != NULL);

	array = xbps_dictionary_get(dict, key);
	if (xbps_array_count(array) == 0)
		return 0;

	iter = xbps_array_iter_from_dict(dict, key);
	if (iter == NULL)
		return ENOMEM;

	if (strcmp(key, "files") == 0)
		curobj = "file";
	else if (strcmp(key, "conf_files") == 0)
		curobj = "configuration file";
	else if (strcmp(key, "links") == 0)
		curobj = "link";
	else if (strcmp(key, "dirs") == 0)
		curobj = "directory";

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

	while ((obj = xbps_object_iterator_next(iter))) {
		xbps_dictionary_get_cstring_nocopy(obj, "file", &file);
		path = xbps_xasprintf("%s/%s", xhp->rootdir, file);

		if ((strcmp(key, "files") == 0) ||
		    (strcmp(key, "conf_files") == 0)) {
			/*
			 * Check SHA256 hash in regular files and
			 * configuration files.
			 */
			xbps_dictionary_get_cstring_nocopy(obj,
			    "sha256", &sha256);
			rv = xbps_file_hash_check(path, sha256);
			if (rv == ENOENT) {
				/* missing file, ignore it */
				xbps_set_cb_state(xhp,
				    XBPS_STATE_REMOVE_FILE_HASH_FAIL,
				    rv, pkgver,
				    "%s: failed to check hash for %s `%s': %s",
				    pkgver, curobj, file, strerror(rv));
				free(path);
				rv = 0;
				continue;
			} else if (rv == ERANGE) {
				rv = 0;
				if ((xhp->flags &
				    XBPS_FLAG_FORCE_REMOVE_FILES) == 0) {
					xbps_set_cb_state(xhp,
					    XBPS_STATE_REMOVE_FILE_HASH_FAIL,
					    0, pkgver,
					    "%s: %s `%s' SHA256 mismatch, "
					    "preserving file", pkgver,
					    curobj, file);
					free(path);
					continue;
				} else {
					xbps_set_cb_state(xhp,
					    XBPS_STATE_REMOVE_FILE_HASH_FAIL,
					    0, pkgver,
					    "%s: %s `%s' SHA256 mismatch, "
					    "forcing removal", pkgver,
					    curobj, file);
				}
			} else if (rv != 0 && rv != ERANGE) {
				xbps_set_cb_state(xhp,
				    XBPS_STATE_REMOVE_FILE_HASH_FAIL,
				    rv, pkgver,
				    "%s: [remove] failed to check hash for "
				    "%s `%s': %s", pkgver, curobj, file,
				    strerror(rv));
				free(path);
				break;
			}
		} else if (strcmp(key, "links") == 0) {
			/*
			 * All regular files from package were removed at this
			 * point, so we will only remove dangling symlinks.
			 */
			if (realpath(path, buf) == NULL) {
				if (errno != ENOENT && errno != ELOOP) {
					free(path);
					rv = errno;
					break;
				}
			}
			if (stat(buf, &st) == 0) {
				free(path);
				continue;
			}
		}
		/*
		 * Remove the object if possible.
		 */
		if (remove(path) == -1) {
			xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FILE_FAIL,
			    errno, pkgver,
			    "%s: failed to remove %s `%s': %s", pkgver,
			    curobj, file, strerror(errno));
			errno = 0;
		} else {
			/* success */
			xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FILE,
			    0, pkgver, "Removed %s `%s'", curobj, file);
		}
		free(path);
	}
	xbps_object_iterator_release(iter);
	free(pkgname);

	return rv;
}
Пример #3
0
/*
 * Returns 1 if entry should be installed, 0 if don't or -1 on error.
 */
int HIDDEN
xbps_entry_install_conf_file(struct xbps_handle *xhp,
			     xbps_dictionary_t filesd,
			     struct archive_entry *entry,
			     const char *entry_pname,
			     const char *pkgver,
			     const char *pkgname)
{
	xbps_dictionary_t forigd;
	xbps_object_t obj, obj2;
	xbps_object_iterator_t iter, iter2;
	const char *cffile, *sha256_new = NULL;
	char *buf, *sha256_cur = NULL, *sha256_orig = NULL;
	int rv = 0;

	assert(xbps_object_type(filesd) == XBPS_TYPE_DICTIONARY);
	assert(entry != NULL);
	assert(entry_pname != NULL);
	assert(pkgver != NULL);

	iter = xbps_array_iter_from_dict(filesd, "conf_files");
	if (iter == NULL)
		return -1;

	/*
	 * Get original hash for the file from current
	 * installed package.
	 */
	xbps_dbg_printf(xhp, "%s: processing conf_file %s\n",
	    pkgver, entry_pname);

	forigd = xbps_pkgdb_get_pkg_metadata(xhp, pkgname);
	if (forigd == NULL) {
		xbps_dbg_printf(xhp, "%s: conf_file %s not currently "
		    "installed\n", pkgver, entry_pname);
		rv = 1;
		goto out;
	}

	iter2 = xbps_array_iter_from_dict(forigd, "conf_files");
	if (iter2 != NULL) {
		while ((obj2 = xbps_object_iterator_next(iter2))) {
			xbps_dictionary_get_cstring_nocopy(obj2,
			    "file", &cffile);
			buf = xbps_xasprintf(".%s", cffile);
			if (strcmp(entry_pname, buf) == 0) {
				xbps_dictionary_get_cstring(obj2, "sha256",
				    &sha256_orig);
				free(buf);
				break;
			}
			free(buf);
			buf = NULL;
		}
		xbps_object_iterator_release(iter2);
	}
	/*
	 * First case: original hash not found, install new file.
	 */
	if (sha256_orig == NULL) {
		xbps_dbg_printf(xhp, "%s: conf_file %s not installed\n",
		    pkgver, entry_pname);
		rv = 1;
		goto out;
	}

	/*
	 * Compare original, installed and new hash for current file.
	 */
	while ((obj = xbps_object_iterator_next(iter))) {
		xbps_dictionary_get_cstring_nocopy(obj, "file", &cffile);
		buf = xbps_xasprintf(".%s", cffile);
		if (strcmp(entry_pname, buf)) {
			free(buf);
			buf = NULL;
			continue;
		}
		sha256_cur = xbps_file_hash(buf);
		free(buf);
		xbps_dictionary_get_cstring_nocopy(obj, "sha256", &sha256_new);
		if (sha256_cur == NULL) {
			if (errno == ENOENT) {
				/*
				 * File not installed, install new one.
				 */
				xbps_dbg_printf(xhp, "%s: conf_file %s not "
				    "installed\n", pkgver, entry_pname);
				rv = 1;
				break;
			} else {
				rv = -1;
				break;
			}
		}
		/*
		 * Orig = X, Curr = X, New = X
		 *
		 * Keep file as is (no changes).
		 */
		if ((strcmp(sha256_orig, sha256_cur) == 0) &&
		    (strcmp(sha256_orig, sha256_new) == 0) &&
		    (strcmp(sha256_cur, sha256_new) == 0)) {
			xbps_dbg_printf(xhp, "%s: conf_file %s orig = X, "
			    "cur = X, new = X\n", pkgver, entry_pname);
			rv = 0;
			break;
		/*
		 * Orig = X, Curr = X, New = Y
		 *
		 * Install new file (installed file hasn't been modified).
		 */
		} else if ((strcmp(sha256_orig, sha256_cur) == 0) &&
			   (strcmp(sha256_orig, sha256_new)) &&
			   (strcmp(sha256_cur, sha256_new))) {
			xbps_set_cb_state(xhp, XBPS_STATE_CONFIG_FILE,
			    0, pkgver,
			    "Updating configuration file `%s' provided "
			    "by `%s'.", cffile, pkgver);
			rv = 1;
			break;
		/*
		 * Orig = X, Curr = Y, New = X
		 *
		 * Keep installed file as is because it has been modified,
		 * but new package doesn't contain new changes compared
		 * to the original version.
		 */
		} else if ((strcmp(sha256_orig, sha256_new) == 0) &&
			   (strcmp(sha256_cur, sha256_new)) &&
			   (strcmp(sha256_orig, sha256_cur))) {
			xbps_set_cb_state(xhp, XBPS_STATE_CONFIG_FILE,
			    0, pkgver,
			    "Keeping modified configuration file `%s'.",
			    cffile);
			rv = 0;
			break;
		/*
		 * Orig = X, Curr = Y, New = Y
		 *
		 * Keep file as is because changes made are compatible
		 * with new version.
		 */
		} else if ((strcmp(sha256_cur, sha256_new) == 0) &&
			   (strcmp(sha256_orig, sha256_new)) &&
			   (strcmp(sha256_orig, sha256_cur))) {
			xbps_dbg_printf(xhp, "%s: conf_file %s orig = X, "
			    "cur = Y, new = Y\n", pkgver, entry_pname);
			rv = 0;
			break;
		/*
		 * Orig = X, Curr = Y, New = Z
		 *
		 * Install new file as <file>.new-<version>
		 */
		} else  if ((strcmp(sha256_orig, sha256_cur)) &&
			    (strcmp(sha256_cur, sha256_new)) &&
			    (strcmp(sha256_orig, sha256_new))) {
			const char *version;

			version = xbps_pkg_version(pkgver);
			assert(version);
			buf = xbps_xasprintf(".%s.new-%s",
			    cffile, version);
			xbps_set_cb_state(xhp, XBPS_STATE_CONFIG_FILE,
			    0, pkgver,
			    "Installing new configuration file to "
			    "`%s.new-%s'.", cffile, version);
			archive_entry_set_pathname(entry, buf);
			free(buf);
			rv = 1;
			break;
		}
	}

out:
	if (sha256_orig)
		free(sha256_orig);
	if (sha256_cur)
		free(sha256_cur);

	xbps_object_iterator_release(iter);

	xbps_dbg_printf(xhp, "%s: conf_file %s returned %d\n",
	    pkgver, entry_pname, rv);

	return rv;
}
Пример #4
0
static int
remove_pkg_files(struct xbps_handle *xhp,
		 xbps_dictionary_t dict,
		 const char *key,
		 const char *pkgver)
{
	xbps_array_t array;
	xbps_object_iterator_t iter;
	xbps_object_t obj;
	const char *curobj = NULL;
	/* These are symlinks in Void and must not be removed */
	const char *basesymlinks[] = {
		"/bin",
		"/sbin",
		"/usr/sbin",
		"/lib",
		"/lib32",
		"/lib64",
		"/usr/lib32",
		"/usr/lib64",
		"/var/run",
	};
	int rv = 0;

	assert(xbps_object_type(dict) == XBPS_TYPE_DICTIONARY);
	assert(key != NULL);

	array = xbps_dictionary_get(dict, key);
	if (xbps_array_count(array) == 0)
		return 0;

	iter = xbps_array_iter_from_dict(dict, key);
	if (iter == NULL)
		return ENOMEM;

	if (strcmp(key, "files") == 0)
		curobj = "file";
	else if (strcmp(key, "conf_files") == 0)
		curobj = "configuration file";
	else if (strcmp(key, "links") == 0)
		curobj = "link";
	else if (strcmp(key, "dirs") == 0)
		curobj = "directory";

	xbps_object_iterator_reset(iter);

	while ((obj = xbps_object_iterator_next(iter))) {
		const char *file, *sha256;
		char path[PATH_MAX];
		bool found;

		xbps_dictionary_get_cstring_nocopy(obj, "file", &file);
		snprintf(path, sizeof(path), "%s/%s", xhp->rootdir, file);

		if ((strcmp(key, "files") == 0) ||
		    (strcmp(key, "conf_files") == 0)) {
			/*
			 * Check SHA256 hash in regular files and
			 * configuration files.
			 */
			xbps_dictionary_get_cstring_nocopy(obj,
			    "sha256", &sha256);
			rv = xbps_file_hash_check(path, sha256);
			if (rv == ENOENT) {
				/* missing file, ignore it */
				xbps_set_cb_state(xhp,
				    XBPS_STATE_REMOVE_FILE_HASH_FAIL,
				    rv, pkgver,
				    "%s: failed to check hash for %s `%s': %s",
				    pkgver, curobj, file, strerror(rv));
				rv = 0;
				continue;
			} else if (rv == ERANGE) {
				rv = 0;
				if ((xhp->flags &
				    XBPS_FLAG_FORCE_REMOVE_FILES) == 0) {
					xbps_set_cb_state(xhp,
					    XBPS_STATE_REMOVE_FILE_HASH_FAIL,
					    0, pkgver,
					    "%s: %s `%s' SHA256 mismatch, "
					    "preserving file", pkgver,
					    curobj, file);
					continue;
				} else {
					xbps_set_cb_state(xhp,
					    XBPS_STATE_REMOVE_FILE_HASH_FAIL,
					    0, pkgver,
					    "%s: %s `%s' SHA256 mismatch, "
					    "forcing removal", pkgver,
					    curobj, file);
				}
			} else if (rv != 0 && rv != ERANGE) {
				xbps_set_cb_state(xhp,
				    XBPS_STATE_REMOVE_FILE_HASH_FAIL,
				    rv, pkgver,
				    "%s: [remove] failed to check hash for "
				    "%s `%s': %s", pkgver, curobj, file,
				    strerror(rv));
				break;
			}
		}
		/*
		 * Make sure to not remove any symlink of root directory.
		 */
		found = false;
		for (uint8_t i = 0; i < __arraycount(basesymlinks); i++) {
			if (strcmp(file, basesymlinks[i]) == 0) {
				found = true;
				xbps_dbg_printf(xhp, "[remove] %s ignoring "
				    "%s removal\n", pkgver, file);
				break;
			}
		}
		if (found) {
			continue;
		}
		if (strcmp(key, "links") == 0) {
			const char *target = NULL;
			char *lnk;

			xbps_dictionary_get_cstring_nocopy(obj, "target", &target);
			assert(target);
			lnk = xbps_symlink_target(xhp, path, target);
			if (lnk == NULL) {
				xbps_dbg_printf(xhp, "[remove] %s "
				    "symlink_target: %s\n", path, strerror(errno));
				continue;
			}
			if (strcmp(lnk, target)) {
				xbps_dbg_printf(xhp, "[remove] %s symlink "
				    "modified (stored %s current %s)\n", path,
				    target, lnk);
				if ((xhp->flags & XBPS_FLAG_FORCE_REMOVE_FILES) == 0) {
					free(lnk);
					continue;
				}
			}
			free(lnk);
		}
		/*
		 * Remove the object if possible.
		 */
		if (remove(path) == -1) {
			xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FILE_FAIL,
			    errno, pkgver,
			    "%s: failed to remove %s `%s': %s", pkgver,
			    curobj, file, strerror(errno));
		} else {
			/* success */
			xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FILE,
			    0, pkgver, "Removed %s `%s'", curobj, file);
		}
	}
	xbps_object_iterator_release(iter);

	return rv;
}
Пример #5
0
int
exec_transaction(struct xbps_handle *xhp, int maxcols, bool yes, bool drun)
{
	xbps_array_t array;
	struct transaction *trans;
	uint64_t fsize = 0, isize = 0;
	char freesize[8], instsize[8];
	int rv = 0;

	trans = calloc(1, sizeof(*trans));
	if (trans == NULL)
		return ENOMEM;

	if ((rv = xbps_transaction_prepare(xhp)) != 0) {
		if (rv == ENODEV) {
			array = xbps_dictionary_get(xhp->transd, "missing_deps");
			if (xbps_array_count(array)) {
				/* missing dependencies */
				print_array(array);
				fprintf(stderr, "Transaction aborted due to unresolved dependencies.\n");
			}
		} else if (rv == ENOEXEC) {
			array = xbps_dictionary_get(xhp->transd, "missing_shlibs");
			if (xbps_array_count(array)) {
				/* missing shlibs */
				print_array(array);
				fprintf(stderr, "Transaction aborted due to unresolved shlibs.\n");
			}
		} else if (rv == EAGAIN) {
			/* conflicts */
			array = xbps_dictionary_get(xhp->transd, "conflicts");
			print_array(array);
			fprintf(stderr, "Transaction aborted due to conflicting packages.\n");
		} else if (rv == ENOSPC) {
			/* not enough free space */
			xbps_dictionary_get_uint64(xhp->transd,
			    "total-installed-size", &isize);
			if (xbps_humanize_number(instsize, (int64_t)isize) == -1) {
				xbps_error_printf("humanize_number2 returns "
					"%s\n", strerror(errno));
				return -1;
			}
			xbps_dictionary_get_uint64(xhp->transd,
			    "disk-free-size", &fsize);
			if (xbps_humanize_number(freesize, (int64_t)fsize) == -1) {
				xbps_error_printf("humanize_number2 returns "
					"%s\n", strerror(errno));
				return -1;
			}
			fprintf(stderr, "Transaction aborted due to insufficient disk "
			    "space (need %s, got %s free).\n", instsize, freesize);
		} else {
			xbps_dbg_printf(xhp, "Empty transaction dictionary: %s\n",
			    strerror(errno));
		}
		goto out;
	}
#ifdef FULL_DEBUG
	xbps_dbg_printf(xhp, "Dictionary before transaction happens:\n");
	xbps_dbg_printf_append(xhp, "%s",
	    xbps_dictionary_externalize(xhp->transd));
#endif

	trans->xhp = xhp;
	trans->d = xhp->transd;
	trans->iter = xbps_array_iter_from_dict(xhp->transd, "packages");
	assert(trans->iter);

	/*
	 * dry-run mode, show what would be done but don't run anything.
	 */
	if (drun) {
		show_actions(trans->iter);
		goto out;
	}
	/*
	 * Show download/installed size for the transaction.
	 */
	if ((rv = show_transaction_sizes(trans, maxcols)) != 0)
		goto out;
	/*
	 * Ask interactively (if -y not set).
	 */
	if (!yes && !yesno("Do you want to continue?")) {
		printf("Aborting!\n");
		goto out;
	}
	/*
	 * It's time to run the transaction!
	 */
	if ((rv = xbps_transaction_commit(xhp)) == 0) {
		printf("\n%u downloaded, %u installed, %u updated, "
		    "%u configured, %u removed.\n",
		    trans->dl_pkgcnt, trans->inst_pkgcnt,
		    trans->up_pkgcnt, trans->cf_pkgcnt + trans->inst_pkgcnt,
		    trans->rm_pkgcnt);
	}
out:
	if (trans->iter)
		xbps_object_iterator_release(trans->iter);
	if (trans)
		free(trans);
	return rv;
}
Пример #6
0
int
xbps_transaction_commit(struct xbps_handle *xhp)
{
    prop_object_t obj;
    prop_object_iterator_t iter;
    size_t i;
    const char *pkgname, *version, *pkgver, *tract;
    int rv = 0;
    bool update, install, sr;

    assert(prop_object_type(xhp->transd) == PROP_TYPE_DICTIONARY);

    update = install = false;
    iter = xbps_array_iter_from_dict(xhp->transd, "packages");
    if (iter == NULL)
        return EINVAL;
    /*
     * Download binary packages (if they come from a remote repository).
     */
    xbps_set_cb_state(xhp, XBPS_STATE_TRANS_DOWNLOAD, 0, NULL, NULL, NULL);
    if ((rv = download_binpkgs(xhp, iter)) != 0)
        goto out;
    /*
     * Check SHA256 hashes for binary packages in transaction.
     */
    xbps_set_cb_state(xhp, XBPS_STATE_TRANS_VERIFY, 0, NULL, NULL, NULL);
    if ((rv = check_binpkgs_hash(xhp, iter)) != 0)
        goto out;
    /*
     * Install, update, configure or remove packages as specified
     * in the transaction dictionary.
     */
    xbps_set_cb_state(xhp, XBPS_STATE_TRANS_RUN, 0, NULL, NULL, NULL);

    i = 0;
    while ((obj = prop_object_iterator_next(iter)) != NULL) {
        if ((xhp->transaction_frequency_flush > 0) &&
                (++i >= xhp->transaction_frequency_flush)) {
            rv = xbps_pkgdb_update(xhp, true);
            if (rv != 0 && rv != ENOENT)
                goto out;

            i = 0;
        }
        update = false;
        prop_dictionary_get_cstring_nocopy(obj, "transaction", &tract);
        prop_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname);
        prop_dictionary_get_cstring_nocopy(obj, "version", &version);
        prop_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver);

        if (strcmp(tract, "remove") == 0) {
            update = false;
            sr = false;
            /*
             * Remove package.
             */
            prop_dictionary_get_bool(obj, "remove-and-update",
                                     &update);
            prop_dictionary_get_bool(obj, "softreplace", &sr);
            rv = xbps_remove_pkg(xhp, pkgname, version, update, sr);
            if (rv != 0)
                goto out;
        } else if (strcmp(tract, "configure") == 0) {
            /*
             * Reconfigure pending package.
             */
            rv = xbps_configure_pkg(xhp, pkgname, false, false, false);
            if (rv != 0)
                goto out;
        } else {
            /*
             * Install or update a package.
             */
            if (strcmp(tract, "update") == 0)
                update = true;
            else
                install = true;

            if (update) {
                /*
                 * Update a package: execute pre-remove
                 * action if found before unpacking.
                 */
                xbps_set_cb_state(xhp, XBPS_STATE_UPDATE, 0,
                                  pkgname, version, NULL);
                rv = xbps_remove_pkg(xhp, pkgname, version,
                                     true, false);
                if (rv != 0) {
                    xbps_set_cb_state(xhp,
                                      XBPS_STATE_UPDATE_FAIL,
                                      rv, pkgname, version,
                                      "%s: [trans] failed to update "
                                      "package to `%s': %s", pkgver,
                                      version, strerror(rv));
                    goto out;
                }
            } else {
                /* Install a package */
                xbps_set_cb_state(xhp, XBPS_STATE_INSTALL,
                                  0, pkgname, version, NULL);
            }
            /*
             * Unpack binary package.
             */
            if ((rv = xbps_unpack_binary_pkg(xhp, obj)) != 0)
                goto out;
            /*
             * Register package.
             */
            if ((rv = xbps_register_pkg(xhp, obj, false)) != 0)
                goto out;
        }
    }
    prop_object_iterator_reset(iter);

    /* force a flush now packages were removed/unpacked */
    if ((rv = xbps_pkgdb_update(xhp, true)) != 0)
        goto out;

    /* if there are no packages to install or update we are done */
    if (!update && !install)
        goto out;
    /*
     * Configure all unpacked packages.
     */
    xbps_set_cb_state(xhp, XBPS_STATE_TRANS_CONFIGURE, 0, NULL, NULL, NULL);

    i = 0;
    while ((obj = prop_object_iterator_next(iter)) != NULL) {
        if (xhp->transaction_frequency_flush > 0 &&
                ++i >= xhp->transaction_frequency_flush) {
            if ((rv = xbps_pkgdb_update(xhp, true)) != 0)
                goto out;

            i = 0;
        }

        prop_dictionary_get_cstring_nocopy(obj, "transaction", &tract);
        if ((strcmp(tract, "remove") == 0) ||
                (strcmp(tract, "configure") == 0))
            continue;

        prop_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname);
        prop_dictionary_get_cstring_nocopy(obj, "version", &version);
        update = false;
        if (strcmp(tract, "update") == 0)
            update = true;

        rv = xbps_configure_pkg(xhp, pkgname, false, update, false);
        if (rv != 0)
            goto out;
        /*
         * Notify client callback when a package has been
         * installed or updated.
         */
        if (update) {
            xbps_set_cb_state(xhp, XBPS_STATE_UPDATE_DONE, 0,
                              pkgname, version, NULL);
        } else {
            xbps_set_cb_state(xhp, XBPS_STATE_INSTALL_DONE, 0,
                              pkgname, version, NULL);
        }
    }

    /* Force a flush now that packages are configured */
    rv = xbps_pkgdb_update(xhp, true);
out:
    prop_object_iterator_release(iter);

    return rv;
}
Пример #7
0
int
exec_transaction(struct xbps_handle *xhp, int maxcols, bool yes, bool drun)
{
	xbps_array_t mdeps, cflicts;
	struct transaction *trans;
	int rv = 0;

	trans = calloc(1, sizeof(*trans));
	if (trans == NULL)
		return ENOMEM;

	if ((rv = xbps_transaction_prepare(xhp)) != 0) {
		if (rv == ENODEV) {
			mdeps =
			    xbps_dictionary_get(xhp->transd, "missing_deps");
			/* missing packages */
			show_missing_deps(mdeps);
			fprintf(stderr, "Transaction aborted due to missing/conflicting packages.\n");
			goto out;
		} else if (rv == EAGAIN) {
			/* conflicts */
			cflicts = xbps_dictionary_get(xhp->transd, "conflicts");
			show_conflicts(cflicts);
			fprintf(stderr, "Transaction aborted due to missing/conflicting packages.\n");
			goto out;
		}
		xbps_dbg_printf(xhp, "Empty transaction dictionary: %s\n",
		    strerror(errno));
		return rv;
	}
	xbps_dbg_printf(xhp, "Dictionary before transaction happens:\n");
	xbps_dbg_printf_append(xhp, "%s",
	    xbps_dictionary_externalize(xhp->transd));

	trans->d = xhp->transd;
	trans->iter = xbps_array_iter_from_dict(xhp->transd, "packages");
	assert(trans->iter);

	/*
	 * dry-run mode, show what would be done but don't run anything.
	 */
	if (drun) {
		show_actions(trans->iter);
		goto out;
	}
	/*
	 * Show download/installed size for the transaction.
	 */
	if ((rv = show_transaction_sizes(trans, maxcols)) != 0)
		goto out;
	/*
	 * Ask interactively (if -y not set).
	 */
	if (!yes && !yesno("Do you want to continue?")) {
		printf("Aborting!\n");
		goto out;
	}
	/*
	 * It's time to run the transaction!
	 */
	if ((rv = xbps_transaction_commit(xhp)) == 0) {
		printf("\n%u installed, %u updated, "
		    "%u configured, %u removed.\n", trans->inst_pkgcnt,
		    trans->up_pkgcnt, trans->cf_pkgcnt + trans->inst_pkgcnt,
		    trans->rm_pkgcnt);
	}
out:
	if (trans->iter)
		xbps_object_iterator_release(trans->iter);
	if (trans)
		free(trans);
	return rv;
}
Пример #8
0
static int
compute_transaction_stats(struct xbps_handle *xhp)
{
	xbps_dictionary_t pkg_metad;
	xbps_object_iterator_t iter;
	xbps_object_t obj;
	struct statvfs svfs;
	uint64_t rootdir_free_size, tsize, dlsize, instsize, rmsize;
	uint32_t inst_pkgcnt, up_pkgcnt, cf_pkgcnt, rm_pkgcnt, dl_pkgcnt;
	const char *tract, *pkgver, *repo;

	inst_pkgcnt = up_pkgcnt = cf_pkgcnt = rm_pkgcnt = dl_pkgcnt = 0;
	rootdir_free_size = tsize = dlsize = instsize = rmsize = 0;

	iter = xbps_array_iter_from_dict(xhp->transd, "packages");
	if (iter == NULL)
		return EINVAL;

	while ((obj = xbps_object_iterator_next(iter)) != NULL) {
		bool preserve = false;
		/*
		 * Count number of pkgs to be removed, configured,
		 * installed and updated.
		 */
		xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver);
		xbps_dictionary_get_cstring_nocopy(obj, "transaction", &tract);
		xbps_dictionary_get_cstring_nocopy(obj, "repository", &repo);
		xbps_dictionary_get_bool(obj, "preserve", &preserve);

		if (strcmp(tract, "configure") == 0) {
			cf_pkgcnt++;
			continue;
		} else if (strcmp(tract, "install") == 0) {
			inst_pkgcnt++;
		} else if (strcmp(tract, "update") == 0) {
			up_pkgcnt++;
		} else if (strcmp(tract, "remove") == 0) {
			rm_pkgcnt++;
		}

		tsize = 0;
		if ((strcmp(tract, "install") == 0) ||
		    (strcmp(tract, "update") == 0)) {
			xbps_dictionary_get_uint64(obj,
			    "installed_size", &tsize);
			instsize += tsize;
			if (xbps_repository_is_remote(repo) &&
			    !xbps_binpkg_exists(xhp, obj)) {
				xbps_dictionary_get_uint64(obj,
				    "filename-size", &tsize);
				/* signature file: 512 bytes */
				tsize += 512;
				dlsize += tsize;
				instsize += tsize;
				dl_pkgcnt++;
				xbps_dictionary_set_bool(obj, "download", true);
			}
		}
		/*
		 * If removing or updating a package, get installed_size
		 * from pkg's metadata dictionary.
		 */
		if ((strcmp(tract, "remove") == 0) ||
		    ((strcmp(tract, "update") == 0) && !preserve)) {
			char *pkgname;

			pkgname = xbps_pkg_name(pkgver);
			assert(pkgname);
			pkg_metad = xbps_pkgdb_get_pkg(xhp, pkgname);
			free(pkgname);
			if (pkg_metad == NULL)
				continue;
			xbps_dictionary_get_uint64(pkg_metad,
			    "installed_size", &tsize);
			rmsize += tsize;
		}
	}
	xbps_object_iterator_release(iter);

	if (instsize > rmsize) {
		instsize -= rmsize;
		rmsize = 0;
	} else if (rmsize > instsize) {
		rmsize -= instsize;
		instsize = 0;
	} else {
		instsize = rmsize = 0;
	}

	if (!xbps_dictionary_set_uint32(xhp->transd,
				"total-install-pkgs", inst_pkgcnt))
		return EINVAL;
	if (!xbps_dictionary_set_uint32(xhp->transd,
				"total-update-pkgs", up_pkgcnt))
		return EINVAL;
	if (!xbps_dictionary_set_uint32(xhp->transd,
				"total-configure-pkgs", cf_pkgcnt))
		return EINVAL;
	if (!xbps_dictionary_set_uint32(xhp->transd,
				"total-remove-pkgs", rm_pkgcnt))
		return EINVAL;
	if (!xbps_dictionary_set_uint32(xhp->transd,
				"total-download-pkgs", dl_pkgcnt))
		return EINVAL;
	if (!xbps_dictionary_set_uint64(xhp->transd,
				"total-installed-size", instsize))
		return EINVAL;
	if (!xbps_dictionary_set_uint64(xhp->transd,
				"total-download-size", dlsize))
		return EINVAL;
	if (!xbps_dictionary_set_uint64(xhp->transd,
				"total-removed-size", rmsize))
		return EINVAL;

	/* Get free space from target rootdir: return ENOSPC if there's not enough space */
	if (statvfs(xhp->rootdir, &svfs) == -1) {
		xbps_dbg_printf(xhp, "%s: statvfs failed: %s\n", __func__, strerror(errno));
		return 0;
	}
	/* compute free space on disk */
	rootdir_free_size = svfs.f_bfree * svfs.f_bsize;

	if (!xbps_dictionary_set_uint64(xhp->transd,
				"disk-free-size", rootdir_free_size))
		return EINVAL;

	if (instsize > rootdir_free_size)
		return ENOSPC;

	return 0;
}