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(8): the 'find-files' target accepts multiple patterns, such as:
$ xbps-repo find-files /bin/cat '/bin/f*' ... $ xbps-repo find-files /bin/cat '/bin/f*' ...

View File

@ -35,44 +35,6 @@
#include <xbps_api.h> #include <xbps_api.h>
#include "defs.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. * Checks package integrity of an installed package.
* The following task is accomplished in this file: * 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(); struct xbps_handle *xhp = xbps_handle_get();
const char *curpkgn, *pkgname, *pkgver; const char *curpkgn, *pkgname, *pkgver;
size_t i; size_t i;
int rv;
bool pkg_fixed = false;
(void)pkg_propsd; (void)pkg_propsd;
(void)pkg_filesd; (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, "pkgname", &pkgname);
prop_dictionary_get_cstring_nocopy(pkgd_regpkgdb, "pkgver", &pkgver); 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++) { for (i = 0; i < prop_array_count(regpkgs); i++) {
obj = prop_array_get(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_array_add(reqby, curpkgver);
prop_dictionary_set(pkgd_regpkgdb, "requiredby", reqby); 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; 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", printf("%s: added requiredby entry for %s.\n",
pkgver, prop_string_cstring_nocopy(curpkgver)); pkgver, prop_string_cstring_nocopy(curpkgver));
prop_object_release(curpkg_propsd); 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 */ /* from transaction.c */
int install_new_pkg(const char *, bool); int install_new_pkg(const char *, bool);
int update_pkg(const char *); int update_pkg(const char *);
int remove_pkg(const char *, bool, bool); int remove_pkg(const char *, bool);
int autoupdate_pkgs(bool, bool); int autoupdate_pkgs(bool, bool);
int autoremove_pkgs(bool, bool); int autoremove_pkgs(bool);
int exec_transaction(bool, bool); int exec_transaction(bool, bool);
/* from remove.c */ /* from remove.c */

View File

@ -68,17 +68,17 @@ main(int argc, char **argv)
struct sigaction sa; struct sigaction sa;
const char *rootdir, *cachedir, *conffile, *option; const char *rootdir, *cachedir, *conffile, *option;
int i, c, flags, rv; 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 install_auto, install_manual, show_download_pkglist_url;
bool reinstall; bool reinstall;
rootdir = cachedir = conffile = option = NULL; rootdir = cachedir = conffile = option = NULL;
flags = rv = 0; 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; recursive_rm = debug = reinstall = false;
install_auto = install_manual = show_download_pkglist_url = 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) { switch (c) {
case 'A': case 'A':
install_auto = true; install_auto = true;
@ -109,9 +109,6 @@ main(int argc, char **argv)
case 'o': case 'o':
option = optarg; option = optarg;
break; break;
case 'p':
purge = true;
break;
case 'R': case 'R':
recursive_rm = true; recursive_rm = true;
break; break;
@ -147,15 +144,6 @@ main(int argc, char **argv)
exit(EXIT_FAILURE); 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. * Initialize libxbps.
*/ */
@ -185,6 +173,14 @@ main(int argc, char **argv)
exit(EXIT_FAILURE); 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) { if (strcasecmp(argv[0], "list") == 0) {
/* Lists packages currently registered in database. */ /* Lists packages currently registered in database. */
if (argc < 1 || argc > 2) if (argc < 1 || argc > 2)
@ -199,12 +195,12 @@ main(int argc, char **argv)
lpc.state = XBPS_PKG_STATE_HALF_UNPACKED; lpc.state = XBPS_PKG_STATE_HALF_UNPACKED;
else if (strcmp(argv[1], "unpacked") == 0) else if (strcmp(argv[1], "unpacked") == 0)
lpc.state = XBPS_PKG_STATE_UNPACKED; lpc.state = XBPS_PKG_STATE_UNPACKED;
else if (strcmp(argv[1], "config-files") == 0) else if (strcmp(argv[1], "half-removed") == 0)
lpc.state = XBPS_PKG_STATE_CONFIG_FILES; lpc.state = XBPS_PKG_STATE_HALF_REMOVED;
else { else {
fprintf(stderr, fprintf(stderr,
"E: invalid state `%s'. Accepted values: " "E: invalid state `%s'. Accepted values: "
"config-files, unpacked, " "half-removed, unpacked, half-unpacked, "
"installed [default]\n", argv[1]); "installed [default]\n", argv[1]);
rv = -1; rv = -1;
goto out; goto out;
@ -249,7 +245,7 @@ main(int argc, char **argv)
usage(xhp); usage(xhp);
for (i = 1; i < argc; i++) { for (i = 1; i < argc; i++) {
rv = remove_pkg(argv[i], purge, recursive_rm); rv = remove_pkg(argv[i], recursive_rm);
if (rv == 0) if (rv == 0)
continue; continue;
else if (rv != EEXIST) else if (rv != EEXIST)
@ -323,19 +319,7 @@ main(int argc, char **argv)
if (argc != 1) if (argc != 1)
usage(xhp); usage(xhp);
rv = autoremove_pkgs(yes, purge); rv = autoremove_pkgs(yes);
} 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);
} else if (strcasecmp(argv[0], "reconfigure") == 0) { } 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: case XBPS_STATE_REMOVE:
printf("Removing `%s-%s' ...\n", xscd->pkgname, xscd->version); printf("Removing `%s-%s' ...\n", xscd->pkgname, xscd->version);
break; break;
case XBPS_STATE_PURGE:
printf("Purging `%s-%s' ...\n", xscd->pkgname, xscd->version);
break;
case XBPS_STATE_CONFIGURE: case XBPS_STATE_CONFIGURE:
printf("Configuring `%s-%s' ...\n", xscd->pkgname, printf("Configuring `%s-%s' ...\n", xscd->pkgname,
xscd->version); xscd->version);
@ -125,21 +122,12 @@ state_cb(const struct xbps_state_cb_data *xscd, void *cbdata)
"(rootdir: %s).", xscd->pkgname, xscd->version, "(rootdir: %s).", xscd->pkgname, xscd->version,
xhp->rootdir); xhp->rootdir);
break; 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 */ /* errors */
case XBPS_STATE_UNPACK_FAIL: case XBPS_STATE_UNPACK_FAIL:
case XBPS_STATE_UPDATE_FAIL: case XBPS_STATE_UPDATE_FAIL:
case XBPS_STATE_CONFIGURE_FAIL: case XBPS_STATE_CONFIGURE_FAIL:
case XBPS_STATE_REGISTER_FAIL: case XBPS_STATE_REGISTER_FAIL:
case XBPS_STATE_UNREGISTER_FAIL: case XBPS_STATE_UNREGISTER_FAIL:
case XBPS_STATE_PURGE_FAIL:
case XBPS_STATE_REMOVE_FAIL: case XBPS_STATE_REMOVE_FAIL:
case XBPS_STATE_VERIFY_FAIL: case XBPS_STATE_VERIFY_FAIL:
case XBPS_STATE_DOWNLOAD_FAIL: case XBPS_STATE_DOWNLOAD_FAIL:

View File

@ -222,11 +222,11 @@ autoupdate_pkgs(bool yes, bool show_download_pkglist_url)
} }
int int
autoremove_pkgs(bool yes, bool purge) autoremove_pkgs(bool yes)
{ {
int rv = 0; int rv = 0;
if ((rv = xbps_transaction_autoremove_pkgs(purge)) != 0) { if ((rv = xbps_transaction_autoremove_pkgs()) != 0) {
if (rv == ENOENT) { if (rv == ENOENT) {
printf("No package orphans were found.\n"); printf("No package orphans were found.\n");
return 0; return 0;
@ -328,7 +328,7 @@ update_pkg(const char *pkgname)
} }
int int
remove_pkg(const char *pkgname, bool purge, bool recursive) remove_pkg(const char *pkgname, bool recursive)
{ {
prop_dictionary_t pkgd; prop_dictionary_t pkgd;
prop_array_t reqby; prop_array_t reqby;
@ -336,7 +336,7 @@ remove_pkg(const char *pkgname, bool purge, bool recursive)
size_t x; size_t x;
int rv; int rv;
rv = xbps_transaction_remove_pkg(pkgname, purge, recursive); rv = xbps_transaction_remove_pkg(pkgname, recursive);
if (rv == EEXIST) { if (rv == EEXIST) {
/* pkg has revdeps */ /* pkg has revdeps */
pkgd = xbps_find_pkg_dict_installed(pkgname, false); 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 .Os Void GNU/Linux
.Dt xbps-bin 8 .Dt xbps-bin 8
.Sh NAME .Sh NAME
@ -60,7 +60,6 @@ depending on it, i.e package is a dependency of any other installed package.
.It Fl f .It Fl f
Used currently in the Used currently in the
.Em install , .Em install ,
.Em purge ,
.Em reconfigure .Em reconfigure
and and
.Em remove .Em remove
@ -69,10 +68,8 @@ targets. If set, package(s) will be reconfigured regardless of its state in
target, or to target, or to
.Em force .Em force
removal of package files even if its hash does not match in the removal of package files even if its hash does not match in the
.Em purge
and
.Em remove .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 .Em installed
when used with the when used with the
.Em install .Em install
@ -95,13 +92,6 @@ Used currently in the
target. Prints the value of specified key(s) from target. Prints the value of specified key(s) from
package's properties dictionary. Multiple keys can be specified delimited by package's properties dictionary. Multiple keys can be specified delimited by
the comma character. 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 .It Fl R
Used currently in the Used currently in the
.Em remove .Em remove
@ -175,28 +165,14 @@ to list only packages with the specified
By default only packages fully installed will be listed if By default only packages fully installed will be listed if
.Em state .Em state
has not been specified. Accepted states are: has not been specified. Accepted states are:
.Em config-files , .Em half-removed ,
.Em half-unpacked , .Em half-unpacked ,
.Em unpacked , .Em installed
and and
.Em installed . .Em unpacked .
.It Sy list-manual .It Sy list-manual
Lists packages that were installed manually by the user, i.e not as dependencies Lists packages that were installed manually by the user, i.e not as dependencies
of any other package. 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 .It Sy reconfigure Ar pkgname | Ar all
Reconfigure an unpacked package. Packages in this state are not fully installed, Reconfigure an unpacked package. Packages in this state are not fully installed,
because they were not configured for whatever reason. The configure stage will 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) .It Sy remove Ar pkgname(s)
Removes the installed package Removes the installed package
.Em pkgname(s) . .Em pkgname(s) .
Its files will be removed and its state will be changed to Files not matching the original SHA256 hash will be preserved. If
.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
.Ql -f .Ql -f
option is used, package files will be option is used, package files will be
.Em removed even if its SHA256 hash don't match . .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 A package can be in a different state while it is being
.Em installed , .Em installed ,
.Em removed , .Em removed ,
.Em unpacked , .Em unpacked
.Em configured
or or
.Em purged . .Em configured .
The following states are available: The following states are available:
.Bl -tag -width ident .Bl -tag -width ident
.It Sy installed .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 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 installed because it was not yet configured. Please note that some packages will
do not work if they are only unpacked. do not work if they are only unpacked.
.It Sy config-files .It Sy half-remove
The package has been removed but configuration files and its metadata directory The package removal did not finish for unknown reasons (power outage, process killed, etc).
are still available (and it is still registered in the package database). The
You can purge safely packages that are in this state, modified configuration .Em purge
files will be preserved. 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 .Sh FILES
.Bl -tag -width /var/db/xbps/metadata/<pkgname>/props.plist -compact .Bl -tag -width /var/db/xbps/metadata/<pkgname>/props.plist -compact
.It Pa /etc/xbps/xbps.conf .It Pa /etc/xbps/xbps.conf

View File

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

View File

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

View File

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

BIN
etc/.xbps.conf.swp Normal file

Binary file not shown.

View File

@ -2,24 +2,30 @@
# ============================ # ============================
# #
# Root directory. # Root directory.
#rootdir = / #RootDir = /
# #
# Cache directory to store downloaded binary packages. # Cache directory to store downloaded binary packages.
# If string begins with '/' it will be treated as full path, # If string begins with '/' it will be treated as full path,
# otherwise it will be treated as relative to the root-directory. # 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. # 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. # 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. # 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. # 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. # Repositories.
# #

View File

@ -56,7 +56,7 @@
*/ */
#define XBPS_PKGINDEX_VERSION "1.3" #define XBPS_PKGINDEX_VERSION "1.3"
#define XBPS_API_VERSION "20111223" #define XBPS_API_VERSION "20111224"
#define XBPS_VERSION "0.12" #define XBPS_VERSION "0.12"
/** /**
@ -159,6 +159,13 @@
*/ */
#define XBPS_FETCH_TIMEOUT 30 #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 __BEGIN_DECLS
void xbps_dbg_printf(const char *, ...); 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_DONE: a package has been removed successfully.
* XBPS_STATE_REMOVE_FILE: a package file is being removed. * XBPS_STATE_REMOVE_FILE: a package file is being removed.
* XBPS_STATE_REMOVE_OBSOLETE: an obsolete 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_REPLACE: a package is being replaced.
* XBPS_STATE_INSTALL: a package is being installed. * XBPS_STATE_INSTALL: a package is being installed.
* XBPS_STATE_INSTALL_DONE: a package has been installed successfully. * XBPS_STATE_INSTALL_DONE: a package has been installed successfully.
@ -209,7 +214,6 @@ void xbps_warn_printf(const char *, ...);
* its hash has failed. * its hash has failed.
* XBPS_STATE_REMOVE_FILE_OBSOLETE_FAIL: an obsolete package file * XBPS_STATE_REMOVE_FILE_OBSOLETE_FAIL: an obsolete package file
* removal has failed. * removal has failed.
* XBPS_STATE_PURGE_FAIL: package purge has failed.
* XBPS_STATE_CONFIGURE_FAIL: package configure has failed. * XBPS_STATE_CONFIGURE_FAIL: package configure has failed.
* XBPS_STATE_CONFIG_FILE_FAIL: package configuration file operation * XBPS_STATE_CONFIG_FILE_FAIL: package configuration file operation
* has failed. * has failed.
@ -419,12 +423,12 @@ struct xbps_handle {
*/ */
cfg_t *cfg; cfg_t *cfg;
/** /**
* @private regpkgdb_dictionary. * @private regpkgdb.
* *
* Internalized proplib dictionary with the registed package database * Internalized proplib dictionary with the registed package database
* stored in XBPS_META_PATH/XBPS_REGPKGDB. * stored in XBPS_META_PATH/XBPS_REGPKGDB.
*/ */
prop_dictionary_t regpkgdb_dictionary; prop_dictionary_t regpkgdb;
/** /**
* @private * @private
* *
@ -498,13 +502,20 @@ struct xbps_handle {
*/ */
const char *conffile; const char *conffile;
/** /**
* @private fetch_timeout * @var fetch_timeout
* *
* Unsigned integer to specify libfetch's timeout limit. * Unsigned integer to specify libfetch's timeout limit.
* If not set, it defaults to 30 (in seconds). This is set internally * If not set, it defaults to 30 (in seconds). This is set internally
* by the API from a setting in configuration file. * by the API from a setting in configuration file.
*/ */
uint16_t fetch_timeout; 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 * @var flags
* *
@ -554,8 +565,8 @@ struct xbps_handle {
* - Set default cache connections for libfetch. * - Set default cache connections for libfetch.
* - Parse configuration file. * - Parse configuration file.
* *
* @param[in] xhp Pointer to an xbps_handle structure, as returned by * @param[in] xhp The xbps_handle structure previously allocated
* \a xbps_handle_alloc(). * by \a xbps_handle_alloc().
* @note It's assumed that \a xhp is a valid pointer. * @note It's assumed that \a xhp is a valid pointer.
* *
* @return 0 on success, an errno value otherwise. * @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 *), int (*fn)(prop_object_t, void *, bool *),
void *arg); 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 * Finds the proplib's dictionary associated with a package, by looking
* it via its name in a proplib dictionary. * 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 */ /** @addtogroup pkg_register */
/*@{*/ /*@{*/
@ -1220,7 +1233,6 @@ int xbps_transaction_update_packages(void);
* be added into the transaction dictionary. * be added into the transaction dictionary.
* *
* @param[in] pkgname Package name to be removed. * @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 * @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. * 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. * process.
*/ */
int xbps_transaction_remove_pkg(const char *pkgname, int xbps_transaction_remove_pkg(const char *pkgname,
bool purge,
bool recursive); bool recursive);
/** /**
* Finds all package orphans currently installed and adds them into * Finds all package orphans currently installed and adds them into
* the transaction dictionary. * 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 * @return 0 on succcess, ENOENT if no package orphans were found, ENXIO
* or EINVAL if a problem ocurred in the process. * 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. * 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_BROKEN</b>: not yet used.
* *
* <b>XBPS_PKG_STATE_CONFIG_FILES</b>: Package has been removed but not * <b>XBPS_PKG_STATE_HALF_REMOVED</b>: Package has been removed but not
* yet purged. * 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 * <b>XBPS_PKG_STATE_NOT_INSTALLED</b>: Package going to be installed in
* a transaction dictionary but that has not been yet unpacked. * 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_UNPACKED = 1,
XBPS_PKG_STATE_INSTALLED, XBPS_PKG_STATE_INSTALLED,
XBPS_PKG_STATE_BROKEN, XBPS_PKG_STATE_BROKEN,
XBPS_PKG_STATE_CONFIG_FILES, XBPS_PKG_STATE_HALF_REMOVED,
XBPS_PKG_STATE_NOT_INSTALLED, XBPS_PKG_STATE_NOT_INSTALLED,
XBPS_PKG_STATE_HALF_UNPACKED XBPS_PKG_STATE_HALF_UNPACKED
} pkg_state_t; } pkg_state_t;

View File

@ -128,7 +128,7 @@ int HIDDEN xbps_repository_find_pkg_deps(prop_dictionary_t,
* @private * @private
* From lib/package_requiredby.c * 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 *); 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_configure.o package_config_files.o package_orphans.o
OBJS += package_remove.o package_remove_obsoletes.o package_state.o OBJS += package_remove.o package_remove_obsoletes.o package_state.o
OBJS += package_unpack.o package_requiredby.o package_register.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 += transaction_dictionary.o transaction_sortdeps.o transaction_ops.o
OBJS += download.o initend.o OBJS += download.o initend.o
OBJS += plist.o plist_archive_entry.o plist_find.o plist_match.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("rootdir"), __UNCONST("/"), CFGF_NONE),
CFG_STR(__UNCONST("cachedir"), CFG_STR(__UNCONST("cachedir"),
__UNCONST(XBPS_CACHE_PATH), CFGF_NONE), __UNCONST(XBPS_CACHE_PATH), CFGF_NONE),
CFG_INT(__UNCONST("fetch-cache-connections"), CFG_INT(__UNCONST("FetchCacheConnections"),
XBPS_FETCH_CACHECONN, CFGF_NONE), XBPS_FETCH_CACHECONN, CFGF_NONE),
CFG_INT(__UNCONST("fetch-cache-connections-per-host"), CFG_INT(__UNCONST("FetchCacheConnectionsPerHost"),
XBPS_FETCH_CACHECONN_HOST, CFGF_NONE), XBPS_FETCH_CACHECONN_HOST, CFGF_NONE),
CFG_INT(__UNCONST("fetch-timeout-connection"), CFG_INT(__UNCONST("FetchTimeoutConnection"),
XBPS_FETCH_TIMEOUT, CFGF_NONE), XBPS_FETCH_TIMEOUT, CFGF_NONE),
CFG_INT(__UNCONST("TransactionFrequencyFlush"),
XBPS_TRANS_FLUSH, CFGF_NONE),
CFG_BOOL(__UNCONST("syslog"), true, CFGF_NONE), CFG_BOOL(__UNCONST("syslog"), true, CFGF_NONE),
CFG_STR_LIST(__UNCONST("repositories"), NULL, CFGF_MULTI), CFG_STR_LIST(__UNCONST("repositories"), NULL, CFGF_MULTI),
CFG_SEC(__UNCONST("virtual-package"), CFG_SEC(__UNCONST("virtual-package"),
@ -161,22 +163,27 @@ xbps_init(struct xbps_handle *xh)
if (xhp->cfg == NULL) { if (xhp->cfg == NULL) {
xhp->syslog_enabled = true; xhp->syslog_enabled = true;
xhp->fetch_timeout = XBPS_FETCH_TIMEOUT; xhp->fetch_timeout = XBPS_FETCH_TIMEOUT;
xhp->transaction_frequency_flush = XBPS_TRANS_FLUSH;
cc = XBPS_FETCH_CACHECONN; cc = XBPS_FETCH_CACHECONN;
cch = XBPS_FETCH_CACHECONN_HOST; cch = XBPS_FETCH_CACHECONN_HOST;
} else { } else {
xhp->syslog_enabled = cfg_getbool(xhp->cfg, "syslog"); xhp->syslog_enabled = cfg_getbool(xhp->cfg, "syslog");
xhp->fetch_timeout = cfg_getint(xhp->cfg, "fetch-timeout-connection"); xhp->fetch_timeout = cfg_getint(xhp->cfg, "FetchTimeoutConnection");
cc = cfg_getint(xhp->cfg, "fetch-cache-connections"); cc = cfg_getint(xhp->cfg, "FetchCacheConnections");
cch = cfg_getint(xhp->cfg, "fetch-cache-connections-per-host"); cch = cfg_getint(xhp->cfg, "FetchCacheConnectionsPerHost");
xhp->transaction_frequency_flush =
cfg_getint(xhp->cfg, "TransactionFrequencyFlush");
} }
xbps_fetch_set_cache_connection(cc, cch); xbps_fetch_set_cache_connection(cc, cch);
xbps_dbg_printf("rootdir=%s\n", xhp->rootdir); xbps_dbg_printf("Rootdir=%s\n", xhp->rootdir);
xbps_dbg_printf("cachedir=%s\n", xhp->cachedir); xbps_dbg_printf("Cachedir=%s\n", xhp->cachedir);
xbps_dbg_printf("fetch-timeout=%u\n", xhp->fetch_timeout); xbps_dbg_printf("FetchTimeout=%u\n", xhp->fetch_timeout);
xbps_dbg_printf("fetch-cacheconn=%u\n", cc); xbps_dbg_printf("FetchCacheconn=%u\n", cc);
xbps_dbg_printf("fetch-cacheconn-host=%u\n", cch); xbps_dbg_printf("FetchCacheconnHost=%u\n", cch);
xbps_dbg_printf("syslog=%u\n", xhp->syslog_enabled); xbps_dbg_printf("Syslog=%u\n", xhp->syslog_enabled);
xbps_dbg_printf("TransactionFrequencyFlush=%u\n",
xhp->transaction_frequency_flush);
return 0; return 0;
} }

View File

@ -86,8 +86,7 @@ xbps_configure_pkg(const char *pkgname,
rv = xbps_pkg_state_installed(pkgname, &state); rv = xbps_pkg_state_installed(pkgname, &state);
if (rv == ENOENT) { if (rv == ENOENT) {
/* /*
* package not installed or has been removed * package not installed or has been removed.
* (must be purged) so ignore it.
*/ */
return 0; return 0;
} else if (rv != 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) if ((rv = xbps_pkg_state_dictionary(obj, &state)) != 0)
return rv; 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; return 0;
reqby = prop_dictionary_get(obj, "requiredby"); 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) xbps_register_pkg(prop_dictionary_t pkgrd)
{ {
struct xbps_handle *xhp; struct xbps_handle *xhp;
prop_dictionary_t dict, pkgd; prop_dictionary_t pkgd;
prop_array_t array, provides = NULL, reqby; prop_array_t provides, reqby, array;
const char *pkgname, *version, *desc, *pkgver; const char *pkgname, *version, *desc, *pkgver;
char *plist;
int rv = 0; int rv = 0;
bool autoinst = false; bool autoinst = false;
assert(prop_object_type(pkgrd) == PROP_TYPE_DICTIONARY); assert(prop_object_type(pkgrd) == PROP_TYPE_DICTIONARY);
xhp = xbps_handle_get(); 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, "pkgname", &pkgname);
prop_dictionary_get_cstring_nocopy(pkgrd, "version", &version); prop_dictionary_get_cstring_nocopy(pkgrd, "version", &version);
@ -72,80 +67,72 @@ xbps_register_pkg(prop_dictionary_t pkgrd)
assert(version != NULL); assert(version != NULL);
assert(desc != NULL); assert(desc != NULL);
assert(pkgver != NULL); assert(pkgver != NULL);
assert(xhp->regpkgdb != NULL);
if ((dict = prop_dictionary_internalize_from_zfile(plist)) != NULL) { pkgd = xbps_regpkgdb_get_pkgd(pkgname, false);
pkgd = xbps_find_pkg_in_dict_by_name(dict, if (pkgd == NULL) {
"packages", pkgname); rv = ENOENT;
if (pkgd == NULL) { goto out;
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;
} }
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: out:
if (rv != 0) { if (rv != 0) {
xbps_set_cb_state(XBPS_STATE_REGISTER_FAIL, xbps_set_cb_state(XBPS_STATE_REGISTER_FAIL,
@ -153,8 +140,6 @@ out:
"%s: failed to register package: %s", "%s: failed to register package: %s",
pkgver, strerror(rv)); pkgver, strerror(rv));
} }
prop_object_release(dict);
free(plist);
return rv; return rv;
} }
@ -163,31 +148,24 @@ int
xbps_unregister_pkg(const char *pkgname, const char *version) xbps_unregister_pkg(const char *pkgname, const char *version)
{ {
struct xbps_handle *xhp; struct xbps_handle *xhp;
char *plist; int rv;
int rv = 0;
assert(pkgname != NULL); 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); xbps_set_cb_state(XBPS_STATE_UNREGISTER, 0, pkgname, version, NULL);
xhp = xbps_handle_get(); if (!xbps_remove_pkg_from_dict_by_name(xhp->regpkgdb,
plist = xbps_xasprintf("%s/%s/%s", xhp->rootdir, "packages", pkgname)) {
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) {
xbps_set_cb_state(XBPS_STATE_UNREGISTER_FAIL, xbps_set_cb_state(XBPS_STATE_UNREGISTER_FAIL,
rv, pkgname, version, errno, pkgname, version,
"%s: failed to unregister package: %s", "%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: * files. Package removal steps:
* -# Its <b>pre-remove</b> target specified in the REMOVE script * -# Its <b>pre-remove</b> target specified in the REMOVE script
* will be executed. * will be executed.
* -# Its files, dirs and links will be removed. Modified files (not * -# Its links, files, conf_files and dirs will be removed.
* matching its sha256 hash) are preserved, unless * Modified files (not matchings its sha256 hash) are preserved, unless
* XBPS_FLAG_FORCE_REMOVE_FILES flag is set via xbps_init::flags member. * XBPS_FLAG_FORCE_REMOVE_FILES flag is set via xbps_init::flags member.
* -# Its <b>post-remove</b> target specified in the REMOVE script * -# Its <b>post-remove</b> target specified in the REMOVE script
* will be executed. * will be executed.
* -# Its requiredby objects will be removed from the installed packages * -# Its requiredby objects will be removed from the installed packages
* database. * 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 * @note
* -# If a package is going to be updated, only steps <b>1</b> and <b>4</b> * -# 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 * 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. * 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 int
xbps_remove_pkg_files(prop_dictionary_t dict, xbps_remove_pkg_files(prop_dictionary_t dict,
const char *key, const char *key,
@ -87,9 +143,8 @@ xbps_remove_pkg_files(prop_dictionary_t dict,
xhp = xbps_handle_get(); xhp = xbps_handle_get();
array = prop_dictionary_get(dict, key); array = prop_dictionary_get(dict, key);
if (array == NULL) if ((prop_object_type(array) != PROP_TYPE_ARRAY) ||
return EINVAL; prop_array_count(array) == 0)
else if (prop_array_count(array) == 0)
return 0; return 0;
iter = xbps_array_iter_from_dict(dict, key); iter = xbps_array_iter_from_dict(dict, key);
@ -174,6 +229,7 @@ xbps_remove_pkg_files(prop_dictionary_t dict,
errno, pkgname, version, errno, pkgname, version,
"%s: failed to remove %s `%s': %s", pkgver, "%s: failed to remove %s `%s': %s", pkgver,
curobj, file, strerror(errno)); curobj, file, strerror(errno));
errno = 0;
} else { } else {
/* success */ /* success */
xbps_set_cb_state(XBPS_STATE_REMOVE_FILE, xbps_set_cb_state(XBPS_STATE_REMOVE_FILE,
@ -193,47 +249,47 @@ int
xbps_remove_pkg(const char *pkgname, const char *version, bool update) xbps_remove_pkg(const char *pkgname, const char *version, bool update)
{ {
struct xbps_handle *xhp; struct xbps_handle *xhp;
prop_dictionary_t dict; prop_dictionary_t pkgd = NULL;
char *buf, *pkgver; char *buf = NULL, *pkgver = NULL;
int rv = 0; int rv = 0;
bool rmfile_exists = false; bool rmfile_exists = false;
pkg_state_t state = 0;
assert(pkgname != NULL); assert(pkgname != NULL);
assert(version != NULL); assert(version != NULL);
xhp = xbps_handle_get(); 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", buf = xbps_xasprintf("%s/metadata/%s/REMOVE",
XBPS_META_PATH, pkgname); XBPS_META_PATH, pkgname);
if (buf == NULL) { if (buf == NULL) {
rv = ENOMEM; rv = ENOMEM;
free(pkgver); goto out;
return rv;
} }
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) { if (chdir(xhp->rootdir) == -1) {
rv = errno; rv = errno;
xbps_set_cb_state(XBPS_STATE_REMOVE_FAIL, xbps_set_cb_state(XBPS_STATE_REMOVE_FAIL,
rv, pkgname, version, rv, pkgname, version,
"%s: [remove] failed to chdir to rootdir `%s': %s", "%s: [remove] failed to chdir to rootdir `%s': %s",
pkgver, xhp->rootdir, strerror(rv)); pkgver, xhp->rootdir, strerror(rv));
free(buf); goto out;
free(pkgver);
return rv;
} }
/* If package was "half-removed", remove it fully. */
if (state == XBPS_PKG_STATE_HALF_REMOVED)
goto purge;
/* /*
* Run the pre remove action. * 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 " "%s: [remove] REMOVE script failed to "
"execute pre ACTION: %s", "execute pre ACTION: %s",
pkgver, strerror(errno)); pkgver, strerror(errno));
free(pkgver); rv = errno;
free(buf); goto out;
return errno;
} }
} else { } else {
if (errno != ENOENT) { if (errno != ENOENT) {
free(pkgver); rv = errno;
free(buf); goto out;
return errno;
} }
} }
/* /*
* If updating a package, we just need to execute the current * If updating a package, we just need to execute the current
* pre-remove action target, unregister its requiredby entries and * 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); return xbps_requiredby_pkg_remove(pkgname);
} }
/* pkgd = xbps_dictionary_from_metadata_plist(pkgname, XBPS_PKGFILES);
* Remove links, files and dirs. if (pkgd == NULL) {
*/ rv = errno;
dict = xbps_dictionary_from_metadata_plist(pkgname, XBPS_PKGFILES); goto out;
if (dict == NULL) {
free(pkgver);
free(buf);
return errno;
} }
/* Remove links */ /* Remove links */
if ((rv = xbps_remove_pkg_files(dict, "links", pkgver)) != 0) { if ((rv = xbps_remove_pkg_files(pkgd, "links", pkgver)) != 0)
prop_object_release(dict); goto out;
free(buf);
free(pkgver);
return rv;
}
/* Remove regular files */ /* Remove regular files */
if ((rv = xbps_remove_pkg_files(dict, "files", pkgver)) != 0) { if ((rv = xbps_remove_pkg_files(pkgd, "files", pkgver)) != 0)
prop_object_release(dict); goto out;
free(buf);
free(pkgver); /* Remove configuration files */
return rv; if ((rv = xbps_remove_pkg_files(pkgd, "conf_files", pkgver)) != 0)
} goto out;
/* Remove dirs */ /* Remove dirs */
if ((rv = xbps_remove_pkg_files(dict, "dirs", pkgver)) != 0) { if ((rv = xbps_remove_pkg_files(pkgd, "dirs", pkgver)) != 0)
prop_object_release(dict); goto out;
free(buf);
free(pkgver);
return rv;
}
prop_object_release(dict);
/* /*
* Execute the post REMOVE action if file exists and we aren't * 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, errno, pkgname, version,
"%s: [remove] REMOVE script failed to execute " "%s: [remove] REMOVE script failed to execute "
"post ACTION: %s", pkgver, strerror(errno)); "post ACTION: %s", pkgver, strerror(errno));
free(buf); rv = errno;
free(pkgver); goto out;
return errno;
} }
free(buf);
/* /*
* Update the requiredby array of all required dependencies. * 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, rv, pkgname, version,
"%s: [remove] failed to remove requiredby entries: %s", "%s: [remove] failed to remove requiredby entries: %s",
pkgver, strerror(rv)); pkgver, strerror(rv));
free(pkgver); goto out;
return rv;
} }
/* /*
* Set package state to "config-files". * Set package state to "half-removed".
*/ */
rv = xbps_set_pkg_state_installed(pkgname, version, pkgver, rv = xbps_set_pkg_state_installed(pkgname, version, pkgver,
XBPS_PKG_STATE_CONFIG_FILES); XBPS_PKG_STATE_HALF_REMOVED);
if (rv != 0) { if (rv != 0) {
xbps_set_cb_state(XBPS_STATE_REMOVE_FAIL, xbps_set_cb_state(XBPS_STATE_REMOVE_FAIL,
rv, pkgname, version, 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)); pkgver, strerror(rv));
} else { goto out;
xbps_set_cb_state(XBPS_STATE_REMOVE_DONE,
0, pkgname, version, NULL);
} }
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; 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) if (reqby == NULL || prop_array_count(reqby) == 0)
return 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)) if (!xbps_remove_pkgname_from_array(reqby, pkgname))
return EINVAL; return EINVAL;
}
return 0; return 0;
} }
@ -101,46 +102,12 @@ remove_pkg_from_reqby(prop_object_t obj, void *arg, bool *loop_done)
int HIDDEN int HIDDEN
xbps_requiredby_pkg_remove(const char *pkgname) xbps_requiredby_pkg_remove(const char *pkgname)
{ {
struct xbps_handle *xhp;
prop_dictionary_t dict;
char *plist;
int rv = 0;
assert(pkgname != NULL); assert(pkgname != NULL);
return xbps_regpkgdb_foreach_pkg_cb(remove_pkg_from_reqby, __UNCONST(pkgname));
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;
} }
int HIDDEN 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_array_t pkg_rdeps;
prop_object_t obj, pkgd_regpkgdb; 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; const char *pkgver, *str;
int rv = 0; int rv = 0;
assert(prop_object_type(pkgs_array) == PROP_TYPE_ARRAY);
assert(prop_object_type(pkgd) == PROP_TYPE_DICTIONARY); assert(prop_object_type(pkgd) == PROP_TYPE_DICTIONARY);
prop_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver); 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; rv = EINVAL;
break; break;
} }
pkgd_regpkgdb = pkgd_regpkgdb = xbps_find_virtualpkg_in_dict_by_pattern(
xbps_find_virtualpkg_in_array_by_pattern(pkgs_array, str); xhp->regpkgdb, "packages", str);
if (pkgd_regpkgdb == NULL) if (pkgd_regpkgdb == NULL)
return EINVAL; return EINVAL;

View File

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

View File

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

View File

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

View File

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

View File

@ -56,45 +56,94 @@
* dictionary. * dictionary.
*/ */
static bool regpkgdb_initialized;
int HIDDEN int HIDDEN
xbps_regpkgdb_dictionary_init(struct xbps_handle *xhp) xbps_regpkgdb_dictionary_init(struct xbps_handle *xhp)
{ {
char *plist; int rv;
if (regpkgdb_initialized) assert(xhp != NULL);
if (xhp->regpkgdb != NULL)
return 0; 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, plist = xbps_xasprintf("%s/%s/%s", xhp->rootdir,
XBPS_META_PATH, XBPS_REGPKGDB); XBPS_META_PATH, XBPS_REGPKGDB);
if (plist == NULL) if (plist == NULL)
return ENOMEM; return ENOMEM;
xhp->regpkgdb_dictionary = if (xhp->regpkgdb != NULL && flush) {
prop_dictionary_internalize_from_zfile(plist); metadir = xbps_xasprintf("%s/%s", xhp->rootdir,
if (xhp->regpkgdb_dictionary == NULL) { XBPS_META_PATH);
free(plist); if (metadir == NULL) {
if (errno != ENOENT) free(plist);
xbps_dbg_printf("[regpkgdb] cannot internalize " return ENOMEM;
"regpkgdb dictionary: %s\n", strerror(errno)); }
return errno; /* 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); /* update copy in memory */
regpkgdb_initialized = true; xhp->regpkgdb = prop_dictionary_internalize_from_zfile(plist);
xbps_dbg_printf("[regpkgdb] initialized ok.\n"); if (xhp->regpkgdb == NULL)
rv = errno;
return 0; free(plist);
return rv;
} }
void HIDDEN void HIDDEN
xbps_regpkgdb_dictionary_release(struct xbps_handle *xhp) xbps_regpkgdb_dictionary_release(struct xbps_handle *xhp)
{ {
if (!regpkgdb_initialized) assert(xhp != NULL);
if (xhp->regpkgdb == NULL)
return; return;
prop_object_release(xhp->regpkgdb_dictionary); prop_object_release(xhp->regpkgdb);
regpkgdb_initialized = false; xhp->regpkgdb = NULL;
xbps_dbg_printf("[regpkgdb] released ok.\n"); xbps_dbg_printf("[regpkgdb] released ok.\n");
} }
@ -103,36 +152,19 @@ foreach_pkg_cb(int (*fn)(prop_object_t, void *, bool *),
void *arg, void *arg,
bool reverse) bool reverse)
{ {
prop_array_t array;
prop_object_t obj;
struct xbps_handle *xhp = xbps_handle_get(); struct xbps_handle *xhp = xbps_handle_get();
size_t i, cnt;
int rv; int rv;
bool done = false;
/* initialize regpkgdb */ /* initialize regpkgdb */
if ((rv = xbps_regpkgdb_dictionary_init(xhp)) != 0) if ((rv = xbps_regpkgdb_dictionary_init(xhp)) != 0)
return rv; 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) { if (reverse) {
while (cnt--) { rv = xbps_callback_array_iter_reverse_in_dict(
obj = prop_array_get(array, cnt); xhp->regpkgdb, "packages", fn, arg);
rv = (*fn)(obj, arg, &done);
if (rv != 0 || done)
break;
}
} else { } else {
for (i = 0; i < cnt; i++) { rv = xbps_callback_array_iter_in_dict(
obj = prop_array_get(array, i); xhp->regpkgdb, "packages", fn, arg);
rv = (*fn)(obj, arg, &done);
if (rv != 0 || done)
break;
}
} }
return rv; 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); 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; struct xbps_handle *xhp;
prop_object_t obj; prop_object_t obj;
prop_object_iterator_t iter; prop_object_iterator_t iter;
size_t i;
const char *pkgname, *version, *pkgver, *tract; const char *pkgname, *version, *pkgver, *tract;
int rv = 0; int rv = 0;
bool update, install, purge; bool update, install;
assert(prop_object_type(transd) == PROP_TYPE_DICTIONARY); assert(prop_object_type(transd) == PROP_TYPE_DICTIONARY);
update = install = purge = false; update = install = false;
xhp = xbps_handle_get(); xhp = xbps_handle_get();
iter = xbps_array_iter_from_dict(transd, "packages"); iter = xbps_array_iter_from_dict(transd, "packages");
if (iter == NULL) 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); xbps_set_cb_state(XBPS_STATE_TRANS_RUN, 0, NULL, NULL, NULL);
i = 0;
while ((obj = prop_object_iterator_next(iter)) != NULL) { 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; update = false;
prop_dictionary_get_cstring_nocopy(obj, "transaction", &tract); prop_dictionary_get_cstring_nocopy(obj, "transaction", &tract);
prop_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname); 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); prop_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver);
if (strcmp(tract, "remove") == 0) { 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", prop_dictionary_get_bool(obj, "remove-and-update",
&update); &update);
prop_dictionary_get_bool(obj, "remove-and-purge",
&purge);
rv = xbps_remove_pkg(pkgname, version, update); rv = xbps_remove_pkg(pkgname, version, update);
if (rv != 0) if (rv != 0)
goto out; goto out;
if (update || !purge)
continue;
if ((rv = xbps_purge_pkg(pkgname, false)) != 0)
goto out;
} else if (strcmp(tract, "configure") == 0) { } else if (strcmp(tract, "configure") == 0) {
/* /*
* Reconfigure pending package. * Reconfigure pending package.
@ -269,6 +272,10 @@ xbps_transaction_commit(prop_dictionary_t transd)
} }
prop_object_iterator_reset(iter); 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 there are no packages to install or update we are done */
if (!update && !install) if (!update && !install)
goto out; 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); xbps_set_cb_state(XBPS_STATE_TRANS_CONFIGURE, 0, NULL, NULL, NULL);
i = 0;
while ((obj = prop_object_iterator_next(iter)) != NULL) { 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); prop_dictionary_get_cstring_nocopy(obj, "transaction", &tract);
if ((strcmp(tract, "remove") == 0) || if ((strcmp(tract, "remove") == 0) ||
(strcmp(tract, "configure") == 0)) (strcmp(tract, "configure") == 0))
continue; continue;
prop_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname); prop_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname);
prop_dictionary_get_cstring_nocopy(obj, "version", &version); prop_dictionary_get_cstring_nocopy(obj, "version", &version);
update = false; 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: out:
prop_object_iterator_release(iter); prop_object_iterator_release(iter);

View File

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

View File

@ -227,7 +227,7 @@ xbps_transaction_install_pkg(const char *pkgpattern)
} }
int 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_dictionary_t transd, pkgd;
prop_array_t mdeps, orphans, orphans_pkg, unsorted, reqby; 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); assert(pkgname != NULL);
pkgd = xbps_find_pkg_dict_installed(pkgname, false); if ((pkgd = xbps_regpkgdb_get_pkgd(pkgname, false)) == NULL) {
if (prop_object_type(pkgd) != PROP_TYPE_DICTIONARY) {
/* pkg not installed */ /* pkg not installed */
rv = ENOENT; return ENOENT;
goto out;
} }
/* /*
* Prepare transaction dictionary and missing deps array. * Prepare transaction dictionary and missing deps array.
@ -267,6 +265,7 @@ xbps_transaction_remove_pkg(const char *pkgname, bool purge, bool recursive)
rv = ENOMEM; rv = ENOMEM;
goto out; goto out;
} }
prop_array_set_cstring_nocopy(orphans_pkg, 0, pkgname); prop_array_set_cstring_nocopy(orphans_pkg, 0, pkgname);
orphans = xbps_find_pkg_orphans(orphans_pkg); orphans = xbps_find_pkg_orphans(orphans_pkg);
prop_object_release(orphans_pkg); prop_object_release(orphans_pkg);
@ -274,13 +273,12 @@ xbps_transaction_remove_pkg(const char *pkgname, bool purge, bool recursive)
rv = EINVAL; rv = EINVAL;
goto out; goto out;
} }
count = prop_array_count(orphans); count = prop_array_count(orphans);
while (count--) { while (count--) {
obj = prop_array_get(orphans, count); obj = prop_array_get(orphans, count);
prop_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver); prop_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver);
prop_dictionary_set_cstring_nocopy(obj, "transaction", "remove"); prop_dictionary_set_cstring_nocopy(obj, "transaction", "remove");
if (purge)
prop_dictionary_set_bool(obj, "remove-and-purge", true);
prop_array_add(unsorted, obj); prop_array_add(unsorted, obj);
xbps_dbg_printf("%s: added into transaction (remove).\n", pkgver); 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_get_cstring_nocopy(pkgd, "pkgver", &pkgver);
prop_dictionary_set_cstring_nocopy(pkgd, "transaction", "remove"); prop_dictionary_set_cstring_nocopy(pkgd, "transaction", "remove");
if (purge)
prop_dictionary_set_bool(pkgd, "remove-and-purge", true);
prop_array_add(unsorted, pkgd); prop_array_add(unsorted, pkgd);
xbps_dbg_printf("%s: added into transaction (remove).\n", pkgver); xbps_dbg_printf("%s: added into transaction (remove).\n", pkgver);
reqby = prop_dictionary_get(pkgd, "requiredby"); reqby = prop_dictionary_get(pkgd, "requiredby");
@ -303,15 +299,15 @@ rmpkg:
if ((prop_object_type(reqby) == PROP_TYPE_ARRAY) && if ((prop_object_type(reqby) == PROP_TYPE_ARRAY) &&
(prop_array_count(reqby) > 0)) (prop_array_count(reqby) > 0))
rv = EEXIST; rv = EEXIST;
out: out:
if (prop_object_type(pkgd) == PROP_TYPE_DICTIONARY) prop_object_release(pkgd);
prop_object_release(pkgd);
return rv; return rv;
} }
int int
xbps_transaction_autoremove_pkgs(bool purge) xbps_transaction_autoremove_pkgs(void)
{ {
prop_dictionary_t transd; prop_dictionary_t transd;
prop_array_t orphans, mdeps, unsorted; 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_get_cstring_nocopy(obj, "pkgver", &pkgver);
prop_dictionary_set_cstring_nocopy(obj, prop_dictionary_set_cstring_nocopy(obj,
"transaction", "remove"); "transaction", "remove");
if (purge)
prop_dictionary_set_bool(obj, "remove-and-purge", true);
prop_array_add(unsorted, obj); prop_array_add(unsorted, obj);
xbps_dbg_printf("%s: added into transaction (remove).\n", xbps_dbg_printf("%s: added into transaction (remove).\n",
pkgver); 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 * If new package is providing a virtual package to the
* package that we want to replace we should respect * package that we want to replace we should respect
* its requiredby and automatic-install objects, so copy * its requiredby and automatic-install objects, so copy
* them to the pkg's dictionary in transaction. Also * them to the pkg's dictionary in transaction.
* make sure that replaced package is also purged.
*/ */
if (xbps_match_virtual_pkg_in_dict(pkg_repod, if (xbps_match_virtual_pkg_in_dict(pkg_repod,
pattern, true) || pattern, true) ||
@ -135,8 +134,6 @@ xbps_transaction_package_replace(prop_dictionary_t transd)
} }
prop_dictionary_set_bool(pkg_repod, prop_dictionary_set_bool(pkg_repod,
"automatic-install", instd_auto); "automatic-install", instd_auto);
prop_dictionary_set_bool(instd,
"remove-and-purge", true);
} }
/* /*
* Add package dictionary into the transaction and mark * Add package dictionary into the transaction and mark