Merged purge code in remove, configurable transaction regpkgdb flushing.

See the NEWS file for info.
This commit is contained in:
Juan RP 2011-12-24 01:05:26 +01:00
parent d7a32a7eca
commit 3b7491d29b
32 changed files with 613 additions and 818 deletions

23
NEWS
View File

@ -1,4 +1,25 @@
xbps-0.11.1 (???):
xbps-0.12.0 (???):
* Renamed some options in xbps.conf to not have dashes, such as:
fetch-timeout-connection -> FetchTimeoutConnection
fetch-cache-connections-host -> FetchCacheConnections
fetch-cache-connections-per-host -> FetchCacheConnectionsPerHost
* Implemented memory caching for regpkgdb and configurarable transaction
flushing. Can be changed in xbps.conf with "TransactionFrequencyFlusing".
By default set to 5. That means that every 5 packages processed in
a transaction there will be a regpkgdb plist flush to disk.
Setting it to 0 enables automatic mode which will only flush in
two required points. Setting it to 1 makes the behaviour used in XBPS<=0.11,
which flushed it on every package.
That feature provides a 25% (and in some cases even more!) of performance
when executing a transaction.
* Merged purge code into remove. It wasn't necessary to have this splitted,
so it now has been merged into xbps_remove_pkg(). That also means that
'-p' flag in xbps-bin(8) and xbps-repo(8) doesn't exist anymore.
* xbps-repo(8): the 'find-files' target accepts multiple patterns, such as:
$ xbps-repo find-files /bin/cat '/bin/f*' ...

View File

@ -35,44 +35,6 @@
#include <xbps_api.h>
#include "defs.h"
static int
write_pkgd_to_regpkgdb(prop_dictionary_t pkgd,
prop_array_t regpkgs,
const char *pkgn)
{
struct xbps_handle *xhp = xbps_handle_get();
char *path;
int rv;
rv = xbps_array_replace_dict_by_name(regpkgs, pkgd, pkgn);
if (rv != 0) {
xbps_error_printf("%s: failed to replace pkgd: %s\n",
pkgn, strerror(rv));
return -1;
}
if (!prop_dictionary_set(xhp->regpkgdb_dictionary,
"packages", regpkgs)) {
xbps_error_printf("%s: failed to set new regpkgdb "
"packages array: %s", pkgn, strerror(errno));
return -1;
}
path = xbps_xasprintf("%s/%s/%s", xhp->rootdir,
XBPS_META_PATH, XBPS_REGPKGDB);
if (path == NULL)
return -1;
if (!prop_dictionary_externalize_to_zfile(
xhp->regpkgdb_dictionary, path)) {
xbps_error_printf("%s: failed to write regpkgdb plist:"
" %s\n", pkgn, strerror(errno));
free(path);
return -1;
}
free(path);
return 0;
}
/*
* Checks package integrity of an installed package.
* The following task is accomplished in this file:
@ -94,6 +56,8 @@ check_pkg_requiredby(prop_dictionary_t pkgd_regpkgdb,
struct xbps_handle *xhp = xbps_handle_get();
const char *curpkgn, *pkgname, *pkgver;
size_t i;
int rv;
bool pkg_fixed = false;
(void)pkg_propsd;
(void)pkg_filesd;
@ -101,7 +65,7 @@ check_pkg_requiredby(prop_dictionary_t pkgd_regpkgdb,
prop_dictionary_get_cstring_nocopy(pkgd_regpkgdb, "pkgname", &pkgname);
prop_dictionary_get_cstring_nocopy(pkgd_regpkgdb, "pkgver", &pkgver);
regpkgs = prop_dictionary_get(xhp->regpkgdb_dictionary, "packages");
regpkgs = prop_dictionary_get(xhp->regpkgdb, "packages");
for (i = 0; i < prop_array_count(regpkgs); i++) {
obj = prop_array_get(regpkgs, i);
@ -181,13 +145,30 @@ check_pkg_requiredby(prop_dictionary_t pkgd_regpkgdb,
*/
prop_array_add(reqby, curpkgver);
prop_dictionary_set(pkgd_regpkgdb, "requiredby", reqby);
if (write_pkgd_to_regpkgdb(pkgd_regpkgdb, regpkgs, pkgname) != 0)
rv = xbps_array_replace_dict_by_name(regpkgs, obj, curpkgn);
if (rv != 0) {
xbps_error_printf("%s: failed to replace pkgd: %s\n",
curpkgn, strerror(rv));
return -1;
}
if (!prop_dictionary_set(xhp->regpkgdb, "packages", regpkgs)) {
xbps_error_printf("%s: failed to set new regpkgdb "
"packages array: %s", curpkgn, strerror(errno));
return -1;
}
pkg_fixed = true;
printf("%s: added requiredby entry for %s.\n",
pkgver, prop_string_cstring_nocopy(curpkgver));
prop_object_release(curpkg_propsd);
}
if (pkg_fixed == false)
return rv;
return 0;
if ((rv = xbps_regpkgdb_update(xhp, true)) != 0) {
xbps_error_printf("failed to write regpkgdb plist: "
" %s\n", strerror(rv));
return rv;
}
return rv;
}

View File

@ -47,9 +47,9 @@ struct list_pkgver_cb {
/* from transaction.c */
int install_new_pkg(const char *, bool);
int update_pkg(const char *);
int remove_pkg(const char *, bool, bool);
int remove_pkg(const char *, bool);
int autoupdate_pkgs(bool, bool);
int autoremove_pkgs(bool, bool);
int autoremove_pkgs(bool);
int exec_transaction(bool, bool);
/* from remove.c */

View File

@ -68,17 +68,17 @@ main(int argc, char **argv)
struct sigaction sa;
const char *rootdir, *cachedir, *conffile, *option;
int i, c, flags, rv;
bool yes, purge, debug, reqby_force, force_rm_with_deps, recursive_rm;
bool yes, debug, reqby_force, force_rm_with_deps, recursive_rm;
bool install_auto, install_manual, show_download_pkglist_url;
bool reinstall;
rootdir = cachedir = conffile = option = NULL;
flags = rv = 0;
reqby_force = yes = purge = force_rm_with_deps = false;
reqby_force = yes = force_rm_with_deps = false;
recursive_rm = debug = reinstall = false;
install_auto = install_manual = show_download_pkglist_url = false;
while ((c = getopt(argc, argv, "AC:c:dDFfMo:pRr:Vvy")) != -1) {
while ((c = getopt(argc, argv, "AC:c:dDFfMo:Rr:Vvy")) != -1) {
switch (c) {
case 'A':
install_auto = true;
@ -109,9 +109,6 @@ main(int argc, char **argv)
case 'o':
option = optarg;
break;
case 'p':
purge = true;
break;
case 'R':
recursive_rm = true;
break;
@ -147,15 +144,6 @@ main(int argc, char **argv)
exit(EXIT_FAILURE);
}
/*
* Register a signal handler to clean up resources used by libxbps.
*/
memset(&sa, 0, sizeof(sa));
sa.sa_handler = cleanup;
sigaction(SIGINT, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
sigaction(SIGQUIT, &sa, NULL);
/*
* Initialize libxbps.
*/
@ -185,6 +173,14 @@ main(int argc, char **argv)
exit(EXIT_FAILURE);
}
/*
* Register a signal handler to clean up resources used by libxbps.
*/
memset(&sa, 0, sizeof(sa));
sa.sa_handler = cleanup;
sigaction(SIGINT, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
if (strcasecmp(argv[0], "list") == 0) {
/* Lists packages currently registered in database. */
if (argc < 1 || argc > 2)
@ -199,12 +195,12 @@ main(int argc, char **argv)
lpc.state = XBPS_PKG_STATE_HALF_UNPACKED;
else if (strcmp(argv[1], "unpacked") == 0)
lpc.state = XBPS_PKG_STATE_UNPACKED;
else if (strcmp(argv[1], "config-files") == 0)
lpc.state = XBPS_PKG_STATE_CONFIG_FILES;
else if (strcmp(argv[1], "half-removed") == 0)
lpc.state = XBPS_PKG_STATE_HALF_REMOVED;
else {
fprintf(stderr,
"E: invalid state `%s'. Accepted values: "
"config-files, unpacked, "
"half-removed, unpacked, half-unpacked, "
"installed [default]\n", argv[1]);
rv = -1;
goto out;
@ -249,7 +245,7 @@ main(int argc, char **argv)
usage(xhp);
for (i = 1; i < argc; i++) {
rv = remove_pkg(argv[i], purge, recursive_rm);
rv = remove_pkg(argv[i], recursive_rm);
if (rv == 0)
continue;
else if (rv != EEXIST)
@ -323,19 +319,7 @@ main(int argc, char **argv)
if (argc != 1)
usage(xhp);
rv = autoremove_pkgs(yes, purge);
} else if (strcasecmp(argv[0], "purge") == 0) {
/*
* Purge a package completely.
*/
if (argc != 2)
usage(xhp);
if (strcasecmp(argv[1], "all") == 0)
rv = xbps_purge_packages();
else
rv = xbps_purge_pkg(argv[1], true);
rv = autoremove_pkgs(yes);
} else if (strcasecmp(argv[0], "reconfigure") == 0) {
/*

View File

@ -66,9 +66,6 @@ state_cb(const struct xbps_state_cb_data *xscd, void *cbdata)
case XBPS_STATE_REMOVE:
printf("Removing `%s-%s' ...\n", xscd->pkgname, xscd->version);
break;
case XBPS_STATE_PURGE:
printf("Purging `%s-%s' ...\n", xscd->pkgname, xscd->version);
break;
case XBPS_STATE_CONFIGURE:
printf("Configuring `%s-%s' ...\n", xscd->pkgname,
xscd->version);
@ -125,21 +122,12 @@ state_cb(const struct xbps_state_cb_data *xscd, void *cbdata)
"(rootdir: %s).", xscd->pkgname, xscd->version,
xhp->rootdir);
break;
case XBPS_STATE_PURGE_DONE:
printf("Purged `%s-%s' successfully.\n",
xscd->pkgname, xscd->version);
if (xhp->syslog_enabled)
syslog(LOG_NOTICE, "Purged `%s-%s' successfully "
"(rootdir: %s).", xscd->pkgname, xscd->version,
xhp->rootdir);
break;
/* errors */
case XBPS_STATE_UNPACK_FAIL:
case XBPS_STATE_UPDATE_FAIL:
case XBPS_STATE_CONFIGURE_FAIL:
case XBPS_STATE_REGISTER_FAIL:
case XBPS_STATE_UNREGISTER_FAIL:
case XBPS_STATE_PURGE_FAIL:
case XBPS_STATE_REMOVE_FAIL:
case XBPS_STATE_VERIFY_FAIL:
case XBPS_STATE_DOWNLOAD_FAIL:

View File

@ -222,11 +222,11 @@ autoupdate_pkgs(bool yes, bool show_download_pkglist_url)
}
int
autoremove_pkgs(bool yes, bool purge)
autoremove_pkgs(bool yes)
{
int rv = 0;
if ((rv = xbps_transaction_autoremove_pkgs(purge)) != 0) {
if ((rv = xbps_transaction_autoremove_pkgs()) != 0) {
if (rv == ENOENT) {
printf("No package orphans were found.\n");
return 0;
@ -328,7 +328,7 @@ update_pkg(const char *pkgname)
}
int
remove_pkg(const char *pkgname, bool purge, bool recursive)
remove_pkg(const char *pkgname, bool recursive)
{
prop_dictionary_t pkgd;
prop_array_t reqby;
@ -336,7 +336,7 @@ remove_pkg(const char *pkgname, bool purge, bool recursive)
size_t x;
int rv;
rv = xbps_transaction_remove_pkg(pkgname, purge, recursive);
rv = xbps_transaction_remove_pkg(pkgname, recursive);
if (rv == EEXIST) {
/* pkg has revdeps */
pkgd = xbps_find_pkg_dict_installed(pkgname, false);

View File

@ -1,4 +1,4 @@
.Dd December 22, 2011
.Dd December 23, 2011
.Os Void GNU/Linux
.Dt xbps-bin 8
.Sh NAME
@ -60,7 +60,6 @@ depending on it, i.e package is a dependency of any other installed package.
.It Fl f
Used currently in the
.Em install ,
.Em purge ,
.Em reconfigure
and
.Em remove
@ -69,10 +68,8 @@ targets. If set, package(s) will be reconfigured regardless of its state in
target, or to
.Em force
removal of package files even if its hash does not match in the
.Em purge
and
.Em remove
targets. If set, package(s) will be reinstalled even if its state is
target. If set, package(s) will be reinstalled even if its state is
.Em installed
when used with the
.Em install
@ -95,13 +92,6 @@ Used currently in the
target. Prints the value of specified key(s) from
package's properties dictionary. Multiple keys can be specified delimited by
the comma character.
.It Fl p
Used currently in the
.Em remove
and
.Em autoremove
targets. If enabled, after removing
a package it is also purged.
.It Fl R
Used currently in the
.Em remove
@ -175,28 +165,14 @@ to list only packages with the specified
By default only packages fully installed will be listed if
.Em state
has not been specified. Accepted states are:
.Em config-files ,
.Em half-removed ,
.Em half-unpacked ,
.Em unpacked ,
.Em installed
and
.Em installed .
.Em unpacked .
.It Sy list-manual
Lists packages that were installed manually by the user, i.e not as dependencies
of any other package.
.It Sy purge Ar pkgname | Ar all
Purge an installed package:
.Em pkgname
or
.Em all
packages. The purge stage runs the post-remove action set in the REMOVE script
in its metadata directory
.Pa (/var/db/xbps/metadata/pkgname)
and will remove configuration (if they were not modified by the user) and
metadata files. The package will be fully removed from the system once it
has been purged. If
.Ql -f
option is used, configuration files that have been
.Em modified WILL BE REMOVED. BEWARE WITH THIS!
.It Sy reconfigure Ar pkgname | Ar all
Reconfigure an unpacked package. Packages in this state are not fully installed,
because they were not configured for whatever reason. The configure stage will
@ -209,16 +185,7 @@ option is used, the package will be reconfigured even if its state is already in
.It Sy remove Ar pkgname(s)
Removes the installed package
.Em pkgname(s) .
Its files will be removed and its state will be changed to
.Em config-files
in the package database. Configuration files, its metadata directory/files and its
information in the package database are preserved. To fully remove a package in
.Em config-files
state, it must be purged with the
.Em purge
command or alternatively use the
.Ql -p
flag. If
Files not matching the original SHA256 hash will be preserved. If
.Ql -f
option is used, package files will be
.Em removed even if its SHA256 hash don't match .
@ -257,10 +224,9 @@ target that will update all currently installed packages.
A package can be in a different state while it is being
.Em installed ,
.Em removed ,
.Em unpacked ,
.Em configured
.Em unpacked
or
.Em purged .
.Em configured .
The following states are available:
.Bl -tag -width ident
.It Sy installed
@ -271,11 +237,13 @@ The package was being unpacked but didn't finish properly for unknown reasons.
The package has been unpacked in destination root directory, but it is not fully
installed because it was not yet configured. Please note that some packages will
do not work if they are only unpacked.
.It Sy config-files
The package has been removed but configuration files and its metadata directory
are still available (and it is still registered in the package database).
You can purge safely packages that are in this state, modified configuration
files will be preserved.
.It Sy half-remove
The package removal did not finish for unknown reasons (power outage, process killed, etc).
The
.Em purge
action in its metadata REMOVE script has not been yet executed. The package
metadata directory is still available and it is registered in package database.
Packages in this state can be still removed.
.Sh FILES
.Bl -tag -width /var/db/xbps/metadata/<pkgname>/props.plist -compact
.It Pa /etc/xbps/xbps.conf

View File

@ -94,6 +94,7 @@ die(const char *fmt, ...)
vfprintf(stderr, fmt, ap);
fprintf(stderr, " (%s)\n", strerror(save_errno));
va_end(ap);
xbps_end(xbps_handle_get());
exit(EXIT_FAILURE);
}

View File

@ -215,6 +215,9 @@ main(int argc, char **argv)
in_chroot ? "[chroot] " : "" , argv[1], argv[2],
strerror(rv), MSG_RESET);
} else {
if ((rv = xbps_regpkgdb_update(xhp, true)) != 0)
exit(EXIT_FAILURE);
printf("%s%s=> %s-%s registered successfully.%s\n",
MSG_NORMAL, in_chroot ? "[chroot] " : "",
argv[1], argv[2], MSG_RESET);

View File

@ -17,11 +17,13 @@ digraph regpkgdb_dictionary {
pkgdict -> pkgver [label="string"];
pkgdict -> state [label="string"];
state -> state_inst [label="value"];
state -> state_cffiles [label="value"];
state -> state_hfuned [label="value"];
state -> state_unpack [label="value"];
state -> state_hfrmed [label="value"];
state_inst [style=filled,fillcolor="yellowgreen",label="installed"];
state_cffiles [style=filled,fillcolor="yellowgreen",label="config-files"];
state_hfuned [style=filled,fillcolor="yellowgreen",label="half-unpacked"];
state_unpack [style=filled,fillcolor="yellowgreen",label="unpacked"];
state_hfrmed [style=filled,fillcolor="yellowgreen",label="half-removed"];
pkgdict -> automatic [label="bool"];
automatic [label="automatic-install"];
pkgdict -> short_desc [label="string"]

BIN
etc/.xbps.conf.swp Normal file

Binary file not shown.

View File

@ -2,24 +2,30 @@
# ============================
#
# Root directory.
#rootdir = /
#RootDir = /
#
# Cache directory to store downloaded binary packages.
# If string begins with '/' it will be treated as full path,
# otherwise it will be treated as relative to the root-directory.
#cachedir = var/cache/xbps
#CacheDir = var/cache/xbps
#
# Default global limit of cached connections when fetching files.
#fetch-cache-connections = 10
#FetchCacheConnection = 10
#
# Default per-host limit of cached connections when fetching files.
#fetch-cache-connections-per-host = 3
#FetchCacheConnectionPerHost = 3
#
# Default timeout limit for connections, in seconds.
#fetch-timeout-connection = 30
#FetchTimeoutConnection = 30
#
# Enable syslog messages, set the value to false or 0 to disable.
#syslog = true
#Syslog = true
# Number of packages to be processed in a transaction to trigger
# a flush to the master package database. Set it to 0 to make it
# only flush at required points.
#
#TransactionFrequencyFlush = 25
# Repositories.
#

View File

@ -56,7 +56,7 @@
*/
#define XBPS_PKGINDEX_VERSION "1.3"
#define XBPS_API_VERSION "20111223"
#define XBPS_API_VERSION "20111224"
#define XBPS_VERSION "0.12"
/**
@ -159,6 +159,13 @@
*/
#define XBPS_FETCH_TIMEOUT 30
/**
* @def XBPS_TRANS_FLUSH
* Default number of packages to be processed in a transaction to
* trigger a flush to the master package database XBPS_REGPKGDB.
*/
#define XBPS_TRANS_FLUSH 5
__BEGIN_DECLS
void xbps_dbg_printf(const char *, ...);
@ -187,8 +194,6 @@ void xbps_warn_printf(const char *, ...);
* XBPS_STATE_REMOVE_DONE: a package has been removed successfully.
* XBPS_STATE_REMOVE_FILE: a package file is being removed.
* XBPS_STATE_REMOVE_OBSOLETE: an obsolete package file is being removed.
* XBPS_STATE_PURGE: a package is being purged.
* XBPS_STATE_PURGE_DONE: a package has been purged successfully.
* XBPS_STATE_REPLACE: a package is being replaced.
* XBPS_STATE_INSTALL: a package is being installed.
* XBPS_STATE_INSTALL_DONE: a package has been installed successfully.
@ -209,7 +214,6 @@ void xbps_warn_printf(const char *, ...);
* its hash has failed.
* XBPS_STATE_REMOVE_FILE_OBSOLETE_FAIL: an obsolete package file
* removal has failed.
* XBPS_STATE_PURGE_FAIL: package purge has failed.
* XBPS_STATE_CONFIGURE_FAIL: package configure has failed.
* XBPS_STATE_CONFIG_FILE_FAIL: package configuration file operation
* has failed.
@ -419,12 +423,12 @@ struct xbps_handle {
*/
cfg_t *cfg;
/**
* @private regpkgdb_dictionary.
* @private regpkgdb.
*
* Internalized proplib dictionary with the registed package database
* stored in XBPS_META_PATH/XBPS_REGPKGDB.
*/
prop_dictionary_t regpkgdb_dictionary;
prop_dictionary_t regpkgdb;
/**
* @private
*
@ -498,13 +502,20 @@ struct xbps_handle {
*/
const char *conffile;
/**
* @private fetch_timeout
* @var fetch_timeout
*
* Unsigned integer to specify libfetch's timeout limit.
* If not set, it defaults to 30 (in seconds). This is set internally
* by the API from a setting in configuration file.
*/
uint16_t fetch_timeout;
/**
* @var transaction_frequency_flush
*
* Number of packages to be processed in a transaction to
* trigger a flush to the master databases.
*/
uint16_t transaction_frequency_flush;
/**
* @var flags
*
@ -554,8 +565,8 @@ struct xbps_handle {
* - Set default cache connections for libfetch.
* - Parse configuration file.
*
* @param[in] xhp Pointer to an xbps_handle structure, as returned by
* \a xbps_handle_alloc().
* @param[in] xhp The xbps_handle structure previously allocated
* by \a xbps_handle_alloc().
* @note It's assumed that \a xhp is a valid pointer.
*
* @return 0 on success, an errno value otherwise.
@ -797,6 +808,32 @@ int xbps_regpkgdb_foreach_reverse_pkg_cb(
int (*fn)(prop_object_t, void *, bool *),
void *arg);
/**
* Returns a package dictionary from regpkgdb plist, matching pkgname or
* pkgver specified in \a pkg.
*
* @param[in] pkg Package name or name-version tuple to match.
* @param[in] bypattern If false \a pkg must be a pkgname, otherwise a pkgver.
*
* @return The matching proplib package dictionary from regpkgdb copied
* with \a prop_dictionary_copy() so it must be released when not required
* anymore with prop_object_release().
*/
prop_dictionary_t xbps_regpkgdb_get_pkgd(const char *pkg, bool bypattern);
/**
* Updates the regpkgdb plist with new contents from disk to the cached copy
* in memory.
*
* @param[in] xhp Pointer to our xbps_handle struct, as returned by
* \a xbps_handle_get() or xbps_handle_alloc().
* @param[in] flush If true the regpkgdb plist contents in memory will
* be flushed atomically to disk.
*
* @return 0 on success, otherwise an errno value.
*/
int xbps_regpkgdb_update(struct xbps_handle *xhp, bool flush);
/**
* Finds the proplib's dictionary associated with a package, by looking
* it via its name in a proplib dictionary.
@ -1097,30 +1134,6 @@ int xbps_array_replace_dict_by_name(prop_array_t array,
/*@}*/
/** @addtogroup purge */
/*@{*/
/**
* Purge an installed package.
*
* @param[in] pkgname Package name to match.
* @param[in] check_state Set it to true to check that package
* is in XBPS_PKG_STATE_CONFIG_FILES state.
*
* @return 0 on success, otherwise an errno value.
*/
int xbps_purge_pkg(const char *pkgname, bool check_state);
/**
* Purge all installed packages. Packages that aren't in
* XBPS_PKG_STATE_CONFIG_FILES state will be ignored.
*
* @return 0 on success, otherwise an errno value.
*/
int xbps_purge_packages(void);
/*@}*/
/** @addtogroup pkg_register */
/*@{*/
@ -1220,7 +1233,6 @@ int xbps_transaction_update_packages(void);
* be added into the transaction dictionary.
*
* @param[in] pkgname Package name to be removed.
* @param[in] purge If true package will also be purged.
* @param[in] recursive If true, all packages that are currently depending
* on the package to be removed, and if they are orphans, will be added.
*
@ -1229,19 +1241,16 @@ int xbps_transaction_update_packages(void);
* process.
*/
int xbps_transaction_remove_pkg(const char *pkgname,
bool purge,
bool recursive);
/**
* Finds all package orphans currently installed and adds them into
* the transaction dictionary.
*
* @param[in] purge If true packages will also be purged.
*
* @return 0 on succcess, ENOENT if no package orphans were found, ENXIO
* or EINVAL if a problem ocurred in the process.
*/
int xbps_transaction_autoremove_pkgs(bool purge);
int xbps_transaction_autoremove_pkgs(void);
/**
* Returns the transaction dictionary, as shown above in the image.
@ -1452,8 +1461,9 @@ int xbps_repository_sync_pkg_index(const char *uri);
*
* <b>XBPS_PKG_STATE_BROKEN</b>: not yet used.
*
* <b>XBPS_PKG_STATE_CONFIG_FILES</b>: Package has been removed but not
* yet purged.
* <b>XBPS_PKG_STATE_HALF_REMOVED</b>: Package has been removed but not
* completely: the purge action in REMOVE script wasn't executed, pkg
* metadata directory still exists and is registered in package database.
*
* <b>XBPS_PKG_STATE_NOT_INSTALLED</b>: Package going to be installed in
* a transaction dictionary but that has not been yet unpacked.
@ -1462,7 +1472,7 @@ typedef enum pkg_state {
XBPS_PKG_STATE_UNPACKED = 1,
XBPS_PKG_STATE_INSTALLED,
XBPS_PKG_STATE_BROKEN,
XBPS_PKG_STATE_CONFIG_FILES,
XBPS_PKG_STATE_HALF_REMOVED,
XBPS_PKG_STATE_NOT_INSTALLED,
XBPS_PKG_STATE_HALF_UNPACKED
} pkg_state_t;

View File

@ -128,7 +128,7 @@ int HIDDEN xbps_repository_find_pkg_deps(prop_dictionary_t,
* @private
* From lib/package_requiredby.c
*/
int HIDDEN xbps_requiredby_pkg_add(prop_array_t, prop_dictionary_t);
int HIDDEN xbps_requiredby_pkg_add(struct xbps_handle *, prop_dictionary_t);
int HIDDEN xbps_requiredby_pkg_remove(const char *);
/**

View File

@ -44,7 +44,7 @@ EXTOBJS += external/match.o external/mkpath.o
OBJS = package_configure.o package_config_files.o package_orphans.o
OBJS += package_remove.o package_remove_obsoletes.o package_state.o
OBJS += package_unpack.o package_requiredby.o package_register.o
OBJS += package_purge.o transaction_commit.o transaction_package_replace.o
OBJS += transaction_commit.o transaction_package_replace.o
OBJS += transaction_dictionary.o transaction_sortdeps.o transaction_ops.o
OBJS += download.o initend.o
OBJS += plist.o plist_archive_entry.o plist_find.o plist_match.o

View File

@ -88,12 +88,14 @@ xbps_init(struct xbps_handle *xh)
CFG_STR(__UNCONST("rootdir"), __UNCONST("/"), CFGF_NONE),
CFG_STR(__UNCONST("cachedir"),
__UNCONST(XBPS_CACHE_PATH), CFGF_NONE),
CFG_INT(__UNCONST("fetch-cache-connections"),
CFG_INT(__UNCONST("FetchCacheConnections"),
XBPS_FETCH_CACHECONN, CFGF_NONE),
CFG_INT(__UNCONST("fetch-cache-connections-per-host"),
CFG_INT(__UNCONST("FetchCacheConnectionsPerHost"),
XBPS_FETCH_CACHECONN_HOST, CFGF_NONE),
CFG_INT(__UNCONST("fetch-timeout-connection"),
CFG_INT(__UNCONST("FetchTimeoutConnection"),
XBPS_FETCH_TIMEOUT, CFGF_NONE),
CFG_INT(__UNCONST("TransactionFrequencyFlush"),
XBPS_TRANS_FLUSH, CFGF_NONE),
CFG_BOOL(__UNCONST("syslog"), true, CFGF_NONE),
CFG_STR_LIST(__UNCONST("repositories"), NULL, CFGF_MULTI),
CFG_SEC(__UNCONST("virtual-package"),
@ -161,22 +163,27 @@ xbps_init(struct xbps_handle *xh)
if (xhp->cfg == NULL) {
xhp->syslog_enabled = true;
xhp->fetch_timeout = XBPS_FETCH_TIMEOUT;
xhp->transaction_frequency_flush = XBPS_TRANS_FLUSH;
cc = XBPS_FETCH_CACHECONN;
cch = XBPS_FETCH_CACHECONN_HOST;
} else {
xhp->syslog_enabled = cfg_getbool(xhp->cfg, "syslog");
xhp->fetch_timeout = cfg_getint(xhp->cfg, "fetch-timeout-connection");
cc = cfg_getint(xhp->cfg, "fetch-cache-connections");
cch = cfg_getint(xhp->cfg, "fetch-cache-connections-per-host");
xhp->fetch_timeout = cfg_getint(xhp->cfg, "FetchTimeoutConnection");
cc = cfg_getint(xhp->cfg, "FetchCacheConnections");
cch = cfg_getint(xhp->cfg, "FetchCacheConnectionsPerHost");
xhp->transaction_frequency_flush =
cfg_getint(xhp->cfg, "TransactionFrequencyFlush");
}
xbps_fetch_set_cache_connection(cc, cch);
xbps_dbg_printf("rootdir=%s\n", xhp->rootdir);
xbps_dbg_printf("cachedir=%s\n", xhp->cachedir);
xbps_dbg_printf("fetch-timeout=%u\n", xhp->fetch_timeout);
xbps_dbg_printf("fetch-cacheconn=%u\n", cc);
xbps_dbg_printf("fetch-cacheconn-host=%u\n", cch);
xbps_dbg_printf("syslog=%u\n", xhp->syslog_enabled);
xbps_dbg_printf("Rootdir=%s\n", xhp->rootdir);
xbps_dbg_printf("Cachedir=%s\n", xhp->cachedir);
xbps_dbg_printf("FetchTimeout=%u\n", xhp->fetch_timeout);
xbps_dbg_printf("FetchCacheconn=%u\n", cc);
xbps_dbg_printf("FetchCacheconnHost=%u\n", cch);
xbps_dbg_printf("Syslog=%u\n", xhp->syslog_enabled);
xbps_dbg_printf("TransactionFrequencyFlush=%u\n",
xhp->transaction_frequency_flush);
return 0;
}

View File

@ -86,8 +86,7 @@ xbps_configure_pkg(const char *pkgname,
rv = xbps_pkg_state_installed(pkgname, &state);
if (rv == ENOENT) {
/*
* package not installed or has been removed
* (must be purged) so ignore it.
* package not installed or has been removed.
*/
return 0;
} else if (rv != 0) {

View File

@ -90,9 +90,10 @@ find_orphan_pkg(prop_object_t obj, void *arg, bool *loop_done)
if ((rv = xbps_pkg_state_dictionary(obj, &state)) != 0)
return rv;
/*
* Skip packages that aren't fully installed.
* Skip packages that aren't fully installed or half removed.
*/
if (state != XBPS_PKG_STATE_INSTALLED)
if (state != XBPS_PKG_STATE_INSTALLED &&
state != XBPS_PKG_STATE_HALF_REMOVED)
return 0;
reqby = prop_dictionary_get(obj, "requiredby");

View File

@ -1,233 +0,0 @@
/*-
* Copyright (c) 2009-2011 Juan Romero Pardines.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <dirent.h>
#include "xbps_api_impl.h"
/**
* @file lib/package_purge.c
* @brief Package purging routines
* @defgroup purge Package purging functions
*
* These functions will purge an specified package or all packages.
* Only packages in XBPS_PKG_STATE_CONFIG_FILES state will be processed
* (unless overriden). Package purging steps:
*
* - Unmodified configuration files will be removed.
* - The purge action in the REMOVE script will be executed (if found).
* - Metadata files will be removed and package will be unregistered
* with xbps_unregister_pkg().
*/
static int
remove_pkg_metadata(const char *pkgname,
const char *version,
const char *pkgver,
const char *rootdir)
{
struct dirent *dp;
DIR *dirp;
char *metadir, *path;
int rv = 0;
assert(pkgname != NULL);
assert(rootdir != NULL);
metadir = xbps_xasprintf("%s/%s/metadata/%s", rootdir,
XBPS_META_PATH, pkgname);
if (metadir == NULL)
return ENOMEM;
dirp = opendir(metadir);
if (dirp == NULL) {
free(metadir);
return errno;
}
while ((dp = readdir(dirp)) != NULL) {
if ((strcmp(dp->d_name, ".") == 0) ||
(strcmp(dp->d_name, "..") == 0))
continue;
path = xbps_xasprintf("%s/%s", metadir, dp->d_name);
if (path == NULL) {
(void)closedir(dirp);
free(metadir);
return ENOMEM;
}
if (unlink(path) == -1) {
xbps_set_cb_state(XBPS_STATE_PURGE_FAIL,
errno, pkgname, version,
"%s: [purge] failed to remove metafile `%s': %s",
pkgver, path, strerror(errno));
}
free(path);
}
(void)closedir(dirp);
rv = rmdir(metadir);
free(metadir);
return rv;
}
static int
purge_pkgs_cb(prop_object_t obj, void *arg, bool *done)
{
const char *pkgname;
(void)arg;
(void)done;
prop_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname);
return xbps_purge_pkg(pkgname, true);
}
int
xbps_purge_packages(void)
{
return xbps_regpkgdb_foreach_pkg_cb(purge_pkgs_cb, NULL);
}
int
xbps_purge_pkg(const char *pkgname, bool check_state)
{
struct xbps_handle *xhp;
prop_dictionary_t dict, pkgd;
const char *version, *pkgver;
char *buf;
int rv = 0;
pkg_state_t state;
assert(pkgname != NULL);
xhp = xbps_handle_get();
/*
* Firstly let's get the pkg dictionary from regpkgdb.
*/
pkgd = xbps_find_pkg_in_dict_by_name(xhp->regpkgdb_dictionary,
"packages", pkgname);
if (pkgd == NULL) {
xbps_dbg_printf("[purge] %s: missing pkg dictionary (%s)\n",
pkgname, strerror(errno));
return errno;
}
prop_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver);
prop_dictionary_get_cstring_nocopy(pkgd, "version", &version);
xbps_set_cb_state(XBPS_STATE_PURGE, 0, pkgname, version, NULL);
if (check_state) {
/*
* Skip packages that aren't in "config-files" state.
*/
if ((rv = xbps_pkg_state_dictionary(pkgd, &state)) != 0)
return rv;
if (state != XBPS_PKG_STATE_CONFIG_FILES) {
xbps_dbg_printf("[purge] %s not in config-files "
"state.\n", pkgname);
return rv;
}
}
/*
* Remove unmodified configuration files.
*/
dict = xbps_dictionary_from_metadata_plist(pkgname, XBPS_PKGFILES);
if (dict == NULL) {
xbps_set_cb_state(XBPS_STATE_PURGE_FAIL,
errno, pkgname, version,
"%s: [purge] failed to read metafile `%s': %s",
pkgver, XBPS_PKGFILES, strerror(errno));
if (errno != ENOENT)
return errno;
} else {
if (prop_dictionary_get(dict, "conf_files")) {
rv = xbps_remove_pkg_files(dict, "conf_files", pkgver);
if (rv != 0) {
prop_object_release(dict);
xbps_set_cb_state(XBPS_STATE_PURGE_FAIL,
rv, pkgname, version,
"%s: [purge] failed to remove "
"configuration files: %s",
pkgver, strerror(rv));
return rv;
}
}
prop_object_release(dict);
}
/*
* Execute the purge action in REMOVE script (if found).
*/
if (chdir(xhp->rootdir) == -1) {
rv = errno;
xbps_set_cb_state(XBPS_STATE_PURGE_FAIL,
rv, pkgname, version,
"%s: [purge] failed to chdir to rootdir `%s': %s",
pkgver, xhp->rootdir, strerror(rv));
return rv;
}
buf = xbps_xasprintf("%s/metadata/%s/REMOVE", XBPS_META_PATH, pkgname);
if (buf == NULL) {
rv = ENOMEM;
return rv;
}
if (access(buf, X_OK) == 0) {
rv = xbps_file_exec(buf, "purge", pkgname, version,
"no", xhp->conffile, NULL);
if (rv != 0) {
free(buf);
if (errno && errno != ENOENT) {
xbps_set_cb_state(XBPS_STATE_PURGE_FAIL,
errno, pkgname, version,
"%s: [purge] REMOVE script failed to "
"execute purge ACTION: %s",
pkgver, strerror(errno));
return rv;
}
}
}
free(buf);
/*
* Remove metadata dir and unregister package.
*/
if ((rv = remove_pkg_metadata(pkgname, version, pkgver,
xhp->rootdir)) != 0) {
xbps_set_cb_state(XBPS_STATE_PURGE_FAIL,
rv, pkgname, version,
"%s: [purge] failed to remove metadata files: %s",
pkgver, strerror(rv));
if (rv != ENOENT)
return rv;
}
if ((rv = xbps_unregister_pkg(pkgname, version)) != 0)
return rv;
xbps_set_cb_state(XBPS_STATE_PURGE_DONE, 0, pkgname, version, NULL);
return rv;
}

View File

@ -43,20 +43,15 @@ int
xbps_register_pkg(prop_dictionary_t pkgrd)
{
struct xbps_handle *xhp;
prop_dictionary_t dict, pkgd;
prop_array_t array, provides = NULL, reqby;
prop_dictionary_t pkgd;
prop_array_t provides, reqby, array;
const char *pkgname, *version, *desc, *pkgver;
char *plist;
int rv = 0;
bool autoinst = false;
assert(prop_object_type(pkgrd) == PROP_TYPE_DICTIONARY);
xhp = xbps_handle_get();
plist = xbps_xasprintf("%s/%s/%s", xhp->rootdir,
XBPS_META_PATH, XBPS_REGPKGDB);
if (plist == NULL)
return ENOMEM;
prop_dictionary_get_cstring_nocopy(pkgrd, "pkgname", &pkgname);
prop_dictionary_get_cstring_nocopy(pkgrd, "version", &version);
@ -72,80 +67,72 @@ xbps_register_pkg(prop_dictionary_t pkgrd)
assert(version != NULL);
assert(desc != NULL);
assert(pkgver != NULL);
assert(xhp->regpkgdb != NULL);
if ((dict = prop_dictionary_internalize_from_zfile(plist)) != NULL) {
pkgd = xbps_find_pkg_in_dict_by_name(dict,
"packages", pkgname);
if (pkgd == NULL) {
rv = errno;
goto out;
}
if (!prop_dictionary_set_cstring_nocopy(pkgd,
"version", version)) {
prop_object_release(pkgd);
rv = EINVAL;
goto out;
}
if (!prop_dictionary_set_cstring_nocopy(pkgd,
"pkgver", pkgver)) {
prop_object_release(pkgd);
rv = EINVAL;
goto out;
}
if (!prop_dictionary_set_cstring_nocopy(pkgd,
"short_desc", desc)) {
prop_object_release(pkgd);
rv = EINVAL;
goto out;
}
if (reqby && !prop_dictionary_set(pkgd, "requiredby", reqby)) {
prop_object_release(pkgd);
rv = EINVAL;
goto out;
}
prop_dictionary_get_bool(pkgd, "automatic-install", &autoinst);
if (xhp->install_reason_auto)
autoinst = true;
else if (xhp->install_reason_manual)
autoinst = false;
if (!prop_dictionary_set_bool(pkgd,
"automatic-install", autoinst)) {
prop_object_release(pkgd);
rv = EINVAL;
goto out;
}
if (provides) {
if (!prop_dictionary_set(pkgd, "provides", provides)) {
prop_object_release(pkgd);
rv = EINVAL;
goto out;
}
}
/*
* Add the requiredby objects for dependent packages.
*/
if (pkgrd && xbps_pkg_has_rundeps(pkgrd)) {
array = prop_dictionary_get(dict, "packages");
if (array == NULL) {
prop_object_release(pkgd);
rv = EINVAL;
goto out;
}
if ((rv = xbps_requiredby_pkg_add(array, pkgrd)) != 0)
goto out;
}
/*
* Write plist file to storage.
*/
if (!prop_dictionary_externalize_to_zfile(dict, plist)) {
rv = errno;
goto out;
}
} else {
free(plist);
return ENOENT;
pkgd = xbps_regpkgdb_get_pkgd(pkgname, false);
if (pkgd == NULL) {
rv = ENOENT;
goto out;
}
if (!prop_dictionary_set_cstring_nocopy(pkgd,
"version", version)) {
prop_object_release(pkgd);
rv = EINVAL;
goto out;
}
if (!prop_dictionary_set_cstring_nocopy(pkgd,
"pkgver", pkgver)) {
prop_object_release(pkgd);
rv = EINVAL;
goto out;
}
if (!prop_dictionary_set_cstring_nocopy(pkgd,
"short_desc", desc)) {
prop_object_release(pkgd);
rv = EINVAL;
goto out;
}
if (reqby && !prop_dictionary_set(pkgd, "requiredby", reqby)) {
prop_object_release(pkgd);
rv = EINVAL;
goto out;
}
prop_dictionary_get_bool(pkgd, "automatic-install", &autoinst);
if (xhp->install_reason_auto)
autoinst = true;
else if (xhp->install_reason_manual)
autoinst = false;
if (!prop_dictionary_set_bool(pkgd,
"automatic-install", autoinst)) {
prop_object_release(pkgd);
rv = EINVAL;
goto out;
}
if (provides) {
if (!prop_dictionary_set(pkgd, "provides", provides)) {
prop_object_release(pkgd);
rv = EINVAL;
goto out;
}
}
array = prop_dictionary_get(xhp->regpkgdb, "packages");
rv = xbps_array_replace_dict_by_name(array, pkgd, pkgname);
if (rv != 0) {
prop_object_release(pkgd);
goto out;
}
/*
* Add the requiredby objects for dependent packages.
*/
if (pkgrd && xbps_pkg_has_rundeps(pkgrd)) {
if ((rv = xbps_requiredby_pkg_add(xhp, pkgrd)) != 0) {
prop_object_release(pkgd);
goto out;
}
}
prop_object_release(pkgd);
out:
if (rv != 0) {
xbps_set_cb_state(XBPS_STATE_REGISTER_FAIL,
@ -153,8 +140,6 @@ out:
"%s: failed to register package: %s",
pkgver, strerror(rv));
}
prop_object_release(dict);
free(plist);
return rv;
}
@ -163,31 +148,24 @@ int
xbps_unregister_pkg(const char *pkgname, const char *version)
{
struct xbps_handle *xhp;
char *plist;
int rv = 0;
int rv;
assert(pkgname != NULL);
xhp = xbps_handle_get();
if ((rv = xbps_regpkgdb_dictionary_init(xhp)) != 0)
return rv;
xbps_set_cb_state(XBPS_STATE_UNREGISTER, 0, pkgname, version, NULL);
xhp = xbps_handle_get();
plist = xbps_xasprintf("%s/%s/%s", xhp->rootdir,
XBPS_META_PATH, XBPS_REGPKGDB);
if (plist == NULL) {
rv = ENOMEM;
goto out;
}
if (!xbps_remove_pkg_dict_from_plist_by_name(pkgname, plist)) {
rv = errno;
goto out;
}
out:
if (rv != 0) {
if (!xbps_remove_pkg_from_dict_by_name(xhp->regpkgdb,
"packages", pkgname)) {
xbps_set_cb_state(XBPS_STATE_UNREGISTER_FAIL,
rv, pkgname, version,
errno, pkgname, version,
"%s: failed to unregister package: %s",
pkgname, strerror(rv));
pkgname, strerror(errno));
return errno;
}
free(plist);
return rv;
return 0;
}

View File

@ -42,14 +42,18 @@
* files. Package removal steps:
* -# Its <b>pre-remove</b> target specified in the REMOVE script
* will be executed.
* -# Its files, dirs and links will be removed. Modified files (not
* matching its sha256 hash) are preserved, unless
* -# Its links, files, conf_files and dirs will be removed.
* Modified files (not matchings its sha256 hash) are preserved, unless
* XBPS_FLAG_FORCE_REMOVE_FILES flag is set via xbps_init::flags member.
* -# Its <b>post-remove</b> target specified in the REMOVE script
* will be executed.
* -# Its requiredby objects will be removed from the installed packages
* database.
* -# Its state will be changed to XBPS_PKG_STATE_CONFIG_FILES.
* -# Its state will be changed to XBPS_PKG_STATE_HALF_UNPACKED.
* -# Its <b>purge-remove</b> target specified in the REMOVE script
* will be executed.
* -# Its package metadata directory will be removed.
* -# Package will be unregistered from package database.
*
* @note
* -# If a package is going to be updated, only steps <b>1</b> and <b>4</b>
@ -69,6 +73,58 @@
* Text inside of white boxes are the key associated with the object, its
* data type is specified on its edge, i.e string, array, integer, dictionary.
*/
static int
remove_pkg_metadata(const char *pkgname,
const char *version,
const char *pkgver,
const char *rootdir)
{
struct dirent *dp;
DIR *dirp;
char *metadir, *path;
int rv = 0;
assert(pkgname != NULL);
assert(rootdir != NULL);
metadir = xbps_xasprintf("%s/%s/metadata/%s", rootdir,
XBPS_META_PATH, pkgname);
if (metadir == NULL)
return ENOMEM;
dirp = opendir(metadir);
if (dirp == NULL) {
free(metadir);
return errno;
}
while ((dp = readdir(dirp)) != NULL) {
if ((strcmp(dp->d_name, ".") == 0) ||
(strcmp(dp->d_name, "..") == 0))
continue;
path = xbps_xasprintf("%s/%s", metadir, dp->d_name);
if (path == NULL) {
(void)closedir(dirp);
free(metadir);
return ENOMEM;
}
if (unlink(path) == -1) {
xbps_set_cb_state(XBPS_STATE_PURGE_FAIL,
errno, pkgname, version,
"%s: [purge] failed to remove metafile `%s': %s",
pkgver, path, strerror(errno));
}
free(path);
}
(void)closedir(dirp);
rv = rmdir(metadir);
free(metadir);
return rv;
}
int
xbps_remove_pkg_files(prop_dictionary_t dict,
const char *key,
@ -87,9 +143,8 @@ xbps_remove_pkg_files(prop_dictionary_t dict,
xhp = xbps_handle_get();
array = prop_dictionary_get(dict, key);
if (array == NULL)
return EINVAL;
else if (prop_array_count(array) == 0)
if ((prop_object_type(array) != PROP_TYPE_ARRAY) ||
prop_array_count(array) == 0)
return 0;
iter = xbps_array_iter_from_dict(dict, key);
@ -174,6 +229,7 @@ xbps_remove_pkg_files(prop_dictionary_t dict,
errno, pkgname, version,
"%s: failed to remove %s `%s': %s", pkgver,
curobj, file, strerror(errno));
errno = 0;
} else {
/* success */
xbps_set_cb_state(XBPS_STATE_REMOVE_FILE,
@ -193,47 +249,47 @@ int
xbps_remove_pkg(const char *pkgname, const char *version, bool update)
{
struct xbps_handle *xhp;
prop_dictionary_t dict;
char *buf, *pkgver;
prop_dictionary_t pkgd = NULL;
char *buf = NULL, *pkgver = NULL;
int rv = 0;
bool rmfile_exists = false;
pkg_state_t state = 0;
assert(pkgname != NULL);
assert(version != NULL);
xhp = xbps_handle_get();
/*
* Check if pkg is installed before anything else.
*/
if (!xbps_check_is_installed_pkg_by_name(pkgname))
return ENOENT;
pkgver = xbps_xasprintf("%s-%s", pkgname, version);
if (pkgver == NULL)
return ENOMEM;
if (!update)
xbps_set_cb_state(XBPS_STATE_REMOVE, 0, pkgname, version, NULL);
buf = xbps_xasprintf("%s/metadata/%s/REMOVE",
XBPS_META_PATH, pkgname);
if (buf == NULL) {
rv = ENOMEM;
free(pkgver);
return rv;
goto out;
}
pkgver = xbps_xasprintf("%s-%s", pkgname, version);
if (pkgver == NULL) {
rv = ENOMEM;
goto out;
}
if ((rv = xbps_pkg_state_installed(pkgname, &state)) != 0)
goto out;
if (!update)
xbps_set_cb_state(XBPS_STATE_REMOVE, 0, pkgname, version, NULL);
if (chdir(xhp->rootdir) == -1) {
rv = errno;
xbps_set_cb_state(XBPS_STATE_REMOVE_FAIL,
rv, pkgname, version,
"%s: [remove] failed to chdir to rootdir `%s': %s",
pkgver, xhp->rootdir, strerror(rv));
free(buf);
free(pkgver);
return rv;
goto out;
}
/* If package was "half-removed", remove it fully. */
if (state == XBPS_PKG_STATE_HALF_REMOVED)
goto purge;
/*
* Run the pre remove action.
*/
@ -246,18 +302,15 @@ xbps_remove_pkg(const char *pkgname, const char *version, bool update)
"%s: [remove] REMOVE script failed to "
"execute pre ACTION: %s",
pkgver, strerror(errno));
free(pkgver);
free(buf);
return errno;
rv = errno;
goto out;
}
} else {
if (errno != ENOENT) {
free(pkgver);
free(buf);
return errno;
rv = errno;
goto out;
}
}
/*
* If updating a package, we just need to execute the current
* pre-remove action target, unregister its requiredby entries and
@ -269,38 +322,26 @@ xbps_remove_pkg(const char *pkgname, const char *version, bool update)
return xbps_requiredby_pkg_remove(pkgname);
}
/*
* Remove links, files and dirs.
*/
dict = xbps_dictionary_from_metadata_plist(pkgname, XBPS_PKGFILES);
if (dict == NULL) {
free(pkgver);
free(buf);
return errno;
pkgd = xbps_dictionary_from_metadata_plist(pkgname, XBPS_PKGFILES);
if (pkgd == NULL) {
rv = errno;
goto out;
}
/* Remove links */
if ((rv = xbps_remove_pkg_files(dict, "links", pkgver)) != 0) {
prop_object_release(dict);
free(buf);
free(pkgver);
return rv;
}
if ((rv = xbps_remove_pkg_files(pkgd, "links", pkgver)) != 0)
goto out;
/* Remove regular files */
if ((rv = xbps_remove_pkg_files(dict, "files", pkgver)) != 0) {
prop_object_release(dict);
free(buf);
free(pkgver);
return rv;
}
if ((rv = xbps_remove_pkg_files(pkgd, "files", pkgver)) != 0)
goto out;
/* Remove configuration files */
if ((rv = xbps_remove_pkg_files(pkgd, "conf_files", pkgver)) != 0)
goto out;
/* Remove dirs */
if ((rv = xbps_remove_pkg_files(dict, "dirs", pkgver)) != 0) {
prop_object_release(dict);
free(buf);
free(pkgver);
return rv;
}
prop_object_release(dict);
if ((rv = xbps_remove_pkg_files(pkgd, "dirs", pkgver)) != 0)
goto out;
/*
* Execute the post REMOVE action if file exists and we aren't
@ -313,12 +354,9 @@ xbps_remove_pkg(const char *pkgname, const char *version, bool update)
errno, pkgname, version,
"%s: [remove] REMOVE script failed to execute "
"post ACTION: %s", pkgver, strerror(errno));
free(buf);
free(pkgver);
return errno;
rv = errno;
goto out;
}
free(buf);
/*
* Update the requiredby array of all required dependencies.
*/
@ -327,25 +365,64 @@ xbps_remove_pkg(const char *pkgname, const char *version, bool update)
rv, pkgname, version,
"%s: [remove] failed to remove requiredby entries: %s",
pkgver, strerror(rv));
free(pkgver);
return rv;
goto out;
}
/*
* Set package state to "config-files".
* Set package state to "half-removed".
*/
rv = xbps_set_pkg_state_installed(pkgname, version, pkgver,
XBPS_PKG_STATE_CONFIG_FILES);
XBPS_PKG_STATE_HALF_REMOVED);
if (rv != 0) {
xbps_set_cb_state(XBPS_STATE_REMOVE_FAIL,
rv, pkgname, version,
"%s: [remove] failed to set state to config-files: %s",
"%s: [remove] failed to set state to half-removed: %s",
pkgver, strerror(rv));
} else {
xbps_set_cb_state(XBPS_STATE_REMOVE_DONE,
0, pkgname, version, NULL);
goto out;
}
free(pkgver);
purge:
/*
* Execute the purge REMOVE action if file exists.
*/
if (access(buf, X_OK) == 0) {
if (xbps_file_exec(buf, "purge", pkgname, version, "no",
xhp->conffile, NULL) != 0) {
rv = errno;
xbps_set_cb_state(XBPS_STATE_REMOVE_FAIL,
errno, pkgname, version,
"%s: REMOVE script failed to execute "
"purge ACTION: %s", pkgver, strerror(errno));
goto out;
}
}
/*
* Remove package metadata directory.
*/
rv = remove_pkg_metadata(pkgname, version, pkgver, xhp->rootdir);
if (rv != 0) {
xbps_set_cb_state(XBPS_STATE_REMOVE_FAIL,
rv, pkgname, version,
"%s: failed to remove metadata files: %s",
pkgver, strerror(rv));
if (rv != ENOENT)
goto out;
}
/*
* Unregister package from regpkgdb.
*/
if ((rv = xbps_unregister_pkg(pkgname, version)) != 0)
goto out;
xbps_set_cb_state(XBPS_STATE_REMOVE_DONE,
0, pkgname, version, NULL);
out:
if (buf != NULL)
free(buf);
if (pkgver != NULL)
free(pkgver);
if (pkgd != NULL)
prop_object_release(pkgd);
return rv;
}

View File

@ -91,9 +91,10 @@ remove_pkg_from_reqby(prop_object_t obj, void *arg, bool *loop_done)
if (reqby == NULL || prop_array_count(reqby) == 0)
return 0;
if (xbps_match_pkgname_in_array(reqby, pkgname))
if (xbps_match_pkgname_in_array(reqby, pkgname)) {
if (!xbps_remove_pkgname_from_array(reqby, pkgname))
return EINVAL;
}
return 0;
}
@ -101,46 +102,12 @@ remove_pkg_from_reqby(prop_object_t obj, void *arg, bool *loop_done)
int HIDDEN
xbps_requiredby_pkg_remove(const char *pkgname)
{
struct xbps_handle *xhp;
prop_dictionary_t dict;
char *plist;
int rv = 0;
assert(pkgname != NULL);
xhp = xbps_handle_get();
plist = xbps_xasprintf("%s/%s/%s", xhp->rootdir,
XBPS_META_PATH, XBPS_REGPKGDB);
if (plist == NULL)
return ENOMEM;
if ((dict = prop_dictionary_internalize_from_zfile(plist)) == NULL) {
free(plist);
xbps_dbg_printf("[reqby-rm] cannot internalize "
"regpkgdb plist for '%s': %s\n", pkgname, strerror(errno));
return errno;
}
rv = xbps_callback_array_iter_in_dict(dict, "packages",
remove_pkg_from_reqby, __UNCONST(pkgname));
if (rv != 0)
goto out;
if (!prop_dictionary_externalize_to_zfile(dict, plist)) {
xbps_dbg_printf("[reqby-rm] cannot externalize plist for "
"'%s': %s\n", pkgname, strerror(errno));
rv = errno;
}
out:
prop_object_release(dict);
free(plist);
return rv;
return xbps_regpkgdb_foreach_pkg_cb(remove_pkg_from_reqby, __UNCONST(pkgname));
}
int HIDDEN
xbps_requiredby_pkg_add(prop_array_t pkgs_array, prop_dictionary_t pkgd)
xbps_requiredby_pkg_add(struct xbps_handle *xhp, prop_dictionary_t pkgd)
{
prop_array_t pkg_rdeps;
prop_object_t obj, pkgd_regpkgdb;
@ -148,7 +115,6 @@ xbps_requiredby_pkg_add(prop_array_t pkgs_array, prop_dictionary_t pkgd)
const char *pkgver, *str;
int rv = 0;
assert(prop_object_type(pkgs_array) == PROP_TYPE_ARRAY);
assert(prop_object_type(pkgd) == PROP_TYPE_DICTIONARY);
prop_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver);
@ -166,8 +132,8 @@ xbps_requiredby_pkg_add(prop_array_t pkgs_array, prop_dictionary_t pkgd)
rv = EINVAL;
break;
}
pkgd_regpkgdb =
xbps_find_virtualpkg_in_array_by_pattern(pkgs_array, str);
pkgd_regpkgdb = xbps_find_virtualpkg_in_dict_by_pattern(
xhp->regpkgdb, "packages", str);
if (pkgd_regpkgdb == NULL)
return EINVAL;

View File

@ -40,7 +40,7 @@ static const struct state states[] = {
{ "unpacked", XBPS_PKG_STATE_UNPACKED },
{ "installed", XBPS_PKG_STATE_INSTALLED },
{ "broken", XBPS_PKG_STATE_BROKEN },
{ "config-files", XBPS_PKG_STATE_CONFIG_FILES },
{ "half-removed", XBPS_PKG_STATE_HALF_REMOVED },
{ "not-installed", XBPS_PKG_STATE_NOT_INSTALLED },
{ "half-unpacked", XBPS_PKG_STATE_HALF_UNPACKED },
{ NULL, 0 }
@ -68,7 +68,7 @@ set_new_state(prop_dictionary_t dict, pkg_state_t state)
break;
if (stp->string == NULL)
return -1;
return EINVAL;
if (!prop_dictionary_set_cstring_nocopy(dict, "state", stp->string))
return EINVAL;
@ -110,7 +110,7 @@ xbps_pkg_state_installed(const char *pkgname, pkg_state_t *state)
assert(pkgname != NULL);
assert(state != NULL);
pkgd = xbps_find_pkg_dict_installed(pkgname, false);
pkgd = xbps_regpkgdb_get_pkgd(pkgname, false);
if (pkgd == NULL)
return ENOENT;
@ -170,127 +170,80 @@ xbps_set_pkg_state_installed(const char *pkgname,
pkg_state_t state)
{
struct xbps_handle *xhp;
prop_dictionary_t dict = NULL, pkgd;
prop_dictionary_t pkgd;
prop_array_t array;
char *metadir, *plist;
int rv = 0;
bool newpkg = false;
int rv;
assert(pkgname != NULL);
xhp = xbps_handle_get();
metadir = xbps_xasprintf("%s/%s", xhp->rootdir, XBPS_META_PATH);
if (metadir == NULL)
return ENOMEM;
plist = xbps_xasprintf("%s/%s", metadir, XBPS_REGPKGDB);
if (plist == NULL) {
free(metadir);
return ENOMEM;
}
if ((dict = prop_dictionary_internalize_from_zfile(plist)) == NULL) {
dict = prop_dictionary_create();
if (dict == NULL) {
rv = ENOMEM;
goto out;
}
if (xhp->regpkgdb == NULL) {
xhp->regpkgdb = prop_dictionary_create();
if (xhp->regpkgdb == NULL)
return ENOMEM;
array = prop_array_create();
if (array == NULL) {
rv = ENOMEM;
goto out;
}
if (array == NULL)
return ENOMEM;
pkgd = prop_dictionary_create();
if (pkgd == NULL) {
rv = ENOMEM;
prop_object_release(array);
goto out;
return ENOMEM;
}
if ((rv = set_pkg_objs(pkgd, pkgname, version, pkgver)) != 0) {
prop_object_release(array);
prop_object_release(pkgd);
goto out;
return rv;
}
if ((rv = set_new_state(pkgd, state)) != 0) {
prop_object_release(array);
prop_object_release(pkgd);
goto out;
return rv;
}
if (!xbps_add_obj_to_array(array, pkgd)) {
rv = EINVAL;
prop_object_release(array);
prop_object_release(pkgd);
goto out;
return EINVAL;
}
if (!xbps_add_obj_to_dict(dict, array, "packages")) {
rv = EINVAL;
if (!xbps_add_obj_to_dict(xhp->regpkgdb, array, "packages")) {
prop_object_release(array);
goto out;
return EINVAL;
}
} else {
pkgd = xbps_find_pkg_in_dict_by_name(dict,
"packages", pkgname);
pkgd = xbps_regpkgdb_get_pkgd(pkgname, false);
if (pkgd == NULL) {
if (errno && errno != ENOENT) {
rv = errno;
goto out;
}
newpkg = true;
pkgd = prop_dictionary_create();
if ((rv = set_pkg_objs(pkgd, pkgname,
version, pkgver)) != 0) {
prop_object_release(pkgd);
goto out;
}
}
array = prop_dictionary_get(dict, "packages");
if (array == NULL) {
array = prop_array_create();
if (!prop_dictionary_set(dict, "packages", array)) {
rv = EINVAL;
if (newpkg)
prop_object_release(pkgd);
goto out;
return rv;
}
}
if ((rv = set_new_state(pkgd, state)) != 0) {
if (newpkg)
prop_object_release(pkgd);
goto out;
return rv;
}
if (newpkg && !xbps_add_obj_to_array(array, pkgd)) {
rv = EINVAL;
prop_object_release(pkgd);
goto out;
}
}
/* Create metadir if doesn't exist */
if (access(metadir, X_OK) == -1) {
if (errno == ENOENT) {
if (xbps_mkpath(metadir, 0755) != 0) {
xbps_dbg_printf("[pkgstate] failed to create "
"metadir %s: %s\n", metadir,
strerror(errno));
rv = errno;
goto out;
array = prop_dictionary_get(xhp->regpkgdb, "packages");
if (newpkg) {
if (!xbps_add_obj_to_array(array, pkgd)) {
prop_object_release(pkgd);
return EINVAL;
}
}
}
/* Externalize regpkgdb plist file */
if (!prop_dictionary_externalize_to_zfile(dict, plist)) {
rv = errno;
xbps_dbg_printf("[pkgstate] cannot write plist '%s': %s\n",
plist, strerror(errno));
}
} else {
if ((rv = xbps_array_replace_dict_by_name(array,
pkgd, pkgname)) != 0)
return rv;
out:
if (prop_object_type(dict) == PROP_TYPE_DICTIONARY)
prop_object_release(dict);
if (metadir)
free(metadir);
if (plist)
free(plist);
prop_object_release(pkgd);
}
if (!prop_dictionary_set(xhp->regpkgdb, "packages", array))
return EINVAL;
}
return rv;
}

View File

@ -192,7 +192,16 @@ unpack_archive(prop_dictionary_t pkg_repod, struct archive *ar)
xucd->entry_extract_count = 0;
xucd->entry_total_count = 0;
}
if (access(xhp->rootdir, R_OK) == -1) {
if (errno != ENOENT) {
rv = errno;
goto out;
}
if (xbps_mkpath(xhp->rootdir, 0750) == -1) {
rv = errno;
goto out;
}
}
if (chdir(xhp->rootdir) == -1) {
xbps_set_cb_state(XBPS_STATE_UNPACK_FAIL,
errno, pkgname, version,

View File

@ -231,7 +231,7 @@ xbps_dictionary_from_metadata_plist(const char *pkgname,
if (access(plistf, R_OK) == -1) {
pkgd = xbps_find_virtualpkg_dict_installed(pkgname, false);
if (pkgd) {
if (prop_object_type(pkgd) == PROP_TYPE_DICTIONARY) {
free(plistf);
prop_dictionary_get_cstring_nocopy(pkgd,
"pkgname", &savedpkgname);

View File

@ -336,15 +336,15 @@ find_pkgd_installed(const char *str, bool bypattern, bool virtual)
/* try normal pkg */
if (virtual == false) {
pkgd = find_pkg_in_dict(xhp->regpkgdb_dictionary,
pkgd = find_pkg_in_dict(xhp->regpkgdb,
"packages", str, bypattern, false);
} else {
/* virtual pkg set by user in conf */
pkgd = find_virtualpkg_user_in_dict(xhp->regpkgdb_dictionary,
pkgd = find_virtualpkg_user_in_dict(xhp->regpkgdb,
"packages", str, bypattern);
if (pkgd == NULL) {
/* any virtual pkg in dictionary matching pattern */
pkgd = find_pkg_in_dict(xhp->regpkgdb_dictionary,
pkgd = find_pkg_in_dict(xhp->regpkgdb,
"packages", str, bypattern, true);
}
}

View File

@ -42,16 +42,20 @@
static bool
remove_string_from_array(prop_array_t array, const char *str, int mode)
{
prop_object_iterator_t iter;
prop_object_t obj;
const char *curname, *pkgdep;
char *curpkgname;
size_t i, idx = 0;
size_t idx = 0;
bool found = false;
assert(prop_object_type(array) == PROP_TYPE_ARRAY);
for (i = 0; i < prop_array_count(array); i++) {
obj = prop_array_get(array, i);
iter = prop_array_iterator(array);
if (iter == NULL)
return false;
while ((obj = prop_object_iterator_next(iter))) {
if (mode == 0) {
/* exact match, obj is a string */
if (prop_string_equals_cstring(obj, str)) {
@ -81,8 +85,12 @@ remove_string_from_array(prop_array_t array, const char *str, int mode)
}
idx++;
}
if (!found)
prop_object_iterator_release(iter);
if (!found) {
errno = ENOENT;
return false;
}
prop_array_remove(array, idx);
return true;
@ -121,7 +129,10 @@ xbps_remove_pkg_from_dict_by_name(prop_dictionary_t dict,
if (array == NULL)
return false;
return xbps_remove_pkg_from_array_by_name(array, pkgname);
if (!xbps_remove_pkg_from_array_by_name(array, pkgname))
return false;
return prop_dictionary_set(dict, key, array);
}
bool

View File

@ -56,45 +56,94 @@
* dictionary.
*/
static bool regpkgdb_initialized;
int HIDDEN
xbps_regpkgdb_dictionary_init(struct xbps_handle *xhp)
{
char *plist;
int rv;
if (regpkgdb_initialized)
assert(xhp != NULL);
if (xhp->regpkgdb != NULL)
return 0;
rv = xbps_regpkgdb_update(xhp, false);
if (rv != 0) {
if (rv != ENOENT)
xbps_dbg_printf("[regpkgdb] cannot internalize "
"regpkgdb dictionary: %s\n", strerror(rv));
return rv;
}
xbps_dbg_printf("[regpkgdb] initialized ok.\n");
return 0;
}
int
xbps_regpkgdb_update(struct xbps_handle *xhp, bool flush)
{
char *plist, *metadir;
int rv = 0;
plist = xbps_xasprintf("%s/%s/%s", xhp->rootdir,
XBPS_META_PATH, XBPS_REGPKGDB);
if (plist == NULL)
return ENOMEM;
xhp->regpkgdb_dictionary =
prop_dictionary_internalize_from_zfile(plist);
if (xhp->regpkgdb_dictionary == NULL) {
free(plist);
if (errno != ENOENT)
xbps_dbg_printf("[regpkgdb] cannot internalize "
"regpkgdb dictionary: %s\n", strerror(errno));
return errno;
if (xhp->regpkgdb != NULL && flush) {
metadir = xbps_xasprintf("%s/%s", xhp->rootdir,
XBPS_META_PATH);
if (metadir == NULL) {
free(plist);
return ENOMEM;
}
/* Create metadir if doesn't exist */
if (access(metadir, X_OK) == -1) {
if (errno == ENOENT) {
if (xbps_mkpath(metadir, 0755) != 0) {
xbps_dbg_printf("[regpkgdb] failed to "
"create metadir %s: %s\n", metadir,
strerror(errno));
rv = errno;
free(metadir);
free(plist);
return rv;
}
} else {
free(plist);
return errno;
}
}
free(metadir);
/* flush dictionary to storage */
if (!prop_dictionary_externalize_to_zfile(xhp->regpkgdb,
plist)) {
free(plist);
return errno;
}
prop_object_release(xhp->regpkgdb);
xhp->regpkgdb = NULL;
}
free(plist);
regpkgdb_initialized = true;
xbps_dbg_printf("[regpkgdb] initialized ok.\n");
/* update copy in memory */
xhp->regpkgdb = prop_dictionary_internalize_from_zfile(plist);
if (xhp->regpkgdb == NULL)
rv = errno;
return 0;
free(plist);
return rv;
}
void HIDDEN
xbps_regpkgdb_dictionary_release(struct xbps_handle *xhp)
{
if (!regpkgdb_initialized)
assert(xhp != NULL);
if (xhp->regpkgdb == NULL)
return;
prop_object_release(xhp->regpkgdb_dictionary);
regpkgdb_initialized = false;
prop_object_release(xhp->regpkgdb);
xhp->regpkgdb = NULL;
xbps_dbg_printf("[regpkgdb] released ok.\n");
}
@ -103,36 +152,19 @@ foreach_pkg_cb(int (*fn)(prop_object_t, void *, bool *),
void *arg,
bool reverse)
{
prop_array_t array;
prop_object_t obj;
struct xbps_handle *xhp = xbps_handle_get();
size_t i, cnt;
int rv;
bool done = false;
/* initialize regpkgdb */
if ((rv = xbps_regpkgdb_dictionary_init(xhp)) != 0)
return rv;
array = prop_dictionary_get(xhp->regpkgdb_dictionary, "packages");
if (prop_object_type(array) != PROP_TYPE_ARRAY)
return EINVAL;
cnt = prop_array_count(array);
if (reverse) {
while (cnt--) {
obj = prop_array_get(array, cnt);
rv = (*fn)(obj, arg, &done);
if (rv != 0 || done)
break;
}
rv = xbps_callback_array_iter_reverse_in_dict(
xhp->regpkgdb, "packages", fn, arg);
} else {
for (i = 0; i < cnt; i++) {
obj = prop_array_get(array, i);
rv = (*fn)(obj, arg, &done);
if (rv != 0 || done)
break;
}
rv = xbps_callback_array_iter_in_dict(
xhp->regpkgdb, "packages", fn, arg);
}
return rv;
}
@ -150,3 +182,22 @@ xbps_regpkgdb_foreach_pkg_cb(int (*fn)(prop_object_t, void *, bool *),
{
return foreach_pkg_cb(fn, arg, false);
}
prop_dictionary_t
xbps_regpkgdb_get_pkgd(const char *pkg, bool bypattern)
{
struct xbps_handle *xhp = xbps_handle_get();
prop_dictionary_t pkgd = NULL;
if (xbps_regpkgdb_dictionary_init(xhp) != 0)
return NULL;
if (bypattern)
pkgd = xbps_find_pkg_in_dict_by_pattern(xhp->regpkgdb,
"packages", pkg);
else
pkgd = xbps_find_pkg_in_dict_by_name(xhp->regpkgdb,
"packages", pkg);
return prop_dictionary_copy(pkgd);
}

View File

@ -164,13 +164,14 @@ xbps_transaction_commit(prop_dictionary_t transd)
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, purge;
bool update, install;
assert(prop_object_type(transd) == PROP_TYPE_DICTIONARY);
update = install = purge = false;
update = install = false;
xhp = xbps_handle_get();
iter = xbps_array_iter_from_dict(transd, "packages");
if (iter == NULL)
@ -193,7 +194,16 @@ xbps_transaction_commit(prop_dictionary_t transd)
*/
xbps_set_cb_state(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_regpkgdb_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);
@ -201,22 +211,15 @@ xbps_transaction_commit(prop_dictionary_t transd)
prop_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver);
if (strcmp(tract, "remove") == 0) {
purge = update = false;
update = false;
/*
* Remove and optionally also purge package.
* Remove package.
*/
prop_dictionary_get_bool(obj, "remove-and-update",
&update);
prop_dictionary_get_bool(obj, "remove-and-purge",
&purge);
rv = xbps_remove_pkg(pkgname, version, update);
if (rv != 0)
goto out;
if (update || !purge)
continue;
if ((rv = xbps_purge_pkg(pkgname, false)) != 0)
goto out;
} else if (strcmp(tract, "configure") == 0) {
/*
* Reconfigure pending package.
@ -269,6 +272,10 @@ xbps_transaction_commit(prop_dictionary_t transd)
}
prop_object_iterator_reset(iter);
/* force a flush now packages were removed/unpacked */
if ((rv = xbps_regpkgdb_update(xhp, true)) != 0)
goto out;
/* if there are no packages to install or update we are done */
if (!update && !install)
goto out;
@ -277,11 +284,21 @@ xbps_transaction_commit(prop_dictionary_t transd)
*/
xbps_set_cb_state(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_regpkgdb_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;
@ -304,6 +321,8 @@ xbps_transaction_commit(prop_dictionary_t transd)
}
}
/* Force a flush now that packages are configured */
rv = xbps_regpkgdb_update(xhp, true);
out:
prop_object_iterator_release(iter);

View File

@ -178,6 +178,8 @@ compute_transaction_stats(void)
pkg_metad =
xbps_dictionary_from_metadata_plist(pkgname,
XBPS_PKGPROPS);
if (pkg_metad == NULL)
continue;
prop_dictionary_get_uint64(pkg_metad,
"installed_size", &tsize);
prop_object_release(pkg_metad);

View File

@ -227,7 +227,7 @@ xbps_transaction_install_pkg(const char *pkgpattern)
}
int
xbps_transaction_remove_pkg(const char *pkgname, bool purge, bool recursive)
xbps_transaction_remove_pkg(const char *pkgname, bool recursive)
{
prop_dictionary_t transd, pkgd;
prop_array_t mdeps, orphans, orphans_pkg, unsorted, reqby;
@ -238,11 +238,9 @@ xbps_transaction_remove_pkg(const char *pkgname, bool purge, bool recursive)
assert(pkgname != NULL);
pkgd = xbps_find_pkg_dict_installed(pkgname, false);
if (prop_object_type(pkgd) != PROP_TYPE_DICTIONARY) {
if ((pkgd = xbps_regpkgdb_get_pkgd(pkgname, false)) == NULL) {
/* pkg not installed */
rv = ENOENT;
goto out;
return ENOENT;
}
/*
* Prepare transaction dictionary and missing deps array.
@ -267,6 +265,7 @@ xbps_transaction_remove_pkg(const char *pkgname, bool purge, bool recursive)
rv = ENOMEM;
goto out;
}
prop_array_set_cstring_nocopy(orphans_pkg, 0, pkgname);
orphans = xbps_find_pkg_orphans(orphans_pkg);
prop_object_release(orphans_pkg);
@ -274,13 +273,12 @@ xbps_transaction_remove_pkg(const char *pkgname, bool purge, bool recursive)
rv = EINVAL;
goto out;
}
count = prop_array_count(orphans);
while (count--) {
obj = prop_array_get(orphans, count);
prop_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver);
prop_dictionary_set_cstring_nocopy(obj, "transaction", "remove");
if (purge)
prop_dictionary_set_bool(obj, "remove-and-purge", true);
prop_array_add(unsorted, obj);
xbps_dbg_printf("%s: added into transaction (remove).\n", pkgver);
}
@ -291,8 +289,6 @@ rmpkg:
*/
prop_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver);
prop_dictionary_set_cstring_nocopy(pkgd, "transaction", "remove");
if (purge)
prop_dictionary_set_bool(pkgd, "remove-and-purge", true);
prop_array_add(unsorted, pkgd);
xbps_dbg_printf("%s: added into transaction (remove).\n", pkgver);
reqby = prop_dictionary_get(pkgd, "requiredby");
@ -303,15 +299,15 @@ rmpkg:
if ((prop_object_type(reqby) == PROP_TYPE_ARRAY) &&
(prop_array_count(reqby) > 0))
rv = EEXIST;
out:
if (prop_object_type(pkgd) == PROP_TYPE_DICTIONARY)
prop_object_release(pkgd);
prop_object_release(pkgd);
return rv;
}
int
xbps_transaction_autoremove_pkgs(bool purge)
xbps_transaction_autoremove_pkgs(void)
{
prop_dictionary_t transd;
prop_array_t orphans, mdeps, unsorted;
@ -350,8 +346,6 @@ xbps_transaction_autoremove_pkgs(bool purge)
prop_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver);
prop_dictionary_set_cstring_nocopy(obj,
"transaction", "remove");
if (purge)
prop_dictionary_set_bool(obj, "remove-and-purge", true);
prop_array_add(unsorted, obj);
xbps_dbg_printf("%s: added into transaction (remove).\n",
pkgver);

View File

@ -121,8 +121,7 @@ xbps_transaction_package_replace(prop_dictionary_t transd)
* If new package is providing a virtual package to the
* package that we want to replace we should respect
* its requiredby and automatic-install objects, so copy
* them to the pkg's dictionary in transaction. Also
* make sure that replaced package is also purged.
* them to the pkg's dictionary in transaction.
*/
if (xbps_match_virtual_pkg_in_dict(pkg_repod,
pattern, true) ||
@ -135,8 +134,6 @@ xbps_transaction_package_replace(prop_dictionary_t transd)
}
prop_dictionary_set_bool(pkg_repod,
"automatic-install", instd_auto);
prop_dictionary_set_bool(instd,
"remove-and-purge", true);
}
/*
* Add package dictionary into the transaction and mark