Mega-commit with improvements and changes done in the past days.

- Introduce package states: unpacked, broken, installed, etc.
  Not yet finished, only unpacked and installed are used for now.

- Move package metadata files in binary packages directly to
  the top directory, this speeds up some ops and makes easier to
  continue working in future changes.

- xbps-bin: -C flag to check the hash of package files has been
  superseded by the 'check' target, which verifies the integrity
  of an installed package.

- Use the 'essential' object when upgrading packages, overwritting
  current files. This is needed for critical packages like sh, libc
  and others.

- Miscellaneous tweaks and improvements thorough the code.

--HG--
extra : convert_revision : 2073fcc123efc24b3e9327b5e22aa91752f20df6
This commit is contained in:
Juan RP 2009-08-08 22:29:48 +02:00
parent 75cac4a637
commit 17404bdb42
24 changed files with 1216 additions and 529 deletions

View file

@ -1,5 +1,5 @@
BIN = xbps-bin BIN = xbps-bin
OBJS = install.o main.o remove.o ../xbps-repo/util.o OBJS = check.o install.o main.o remove.o ../xbps-repo/util.o
TOPDIR = ../.. TOPDIR = ../..
include $(TOPDIR)/prog.mk include $(TOPDIR)/prog.mk

289
bin/xbps-bin/check.c Normal file
View file

@ -0,0 +1,289 @@
/*-
* Copyright (c) 2009 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 <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <limits.h>
#include <libgen.h>
#include <unistd.h>
#include <xbps_api.h>
#include "defs.h"
/*
* Checks package integrity of an installed package. This
* consists in four tasks:
*
* o Check for metadata files (files.plist and props.plist),
* we only check if the file exists and its dictionary can
* be externalized and is not empty.
* o Check for missing installed files.
* o Check the hash for all installed files, except
* configuration files (which is expected if they are modified).
* o Check for missing run time dependencies.
*
* If any of these checks fail, the package will change its
* state to 'broken'.
*/
int
xbps_check_pkg_integrity(const char *pkgname)
{
prop_dictionary_t pkgd, propsd, filesd;
prop_array_t array;
prop_object_t obj;
prop_object_iterator_t iter;
const char *rootdir, *file, *sha256, *reqpkg;
char *path;
int rv = 0;
bool files_broken = false, broken = false;
assert(pkgname != NULL);
rootdir = xbps_get_rootdir();
pkgd = xbps_find_pkg_installed_from_plist(pkgname);
if (pkgd == NULL) {
printf("Package %s is not installed.\n", pkgname);
return 0;
}
/*
* Check for props.plist metadata file.
*/
path = xbps_xasprintf("%s/%s/metadata/%s/%s", rootdir,
XBPS_META_PATH, pkgname, XBPS_PKGPROPS);
if (path == NULL) {
rv = errno;
goto out;
}
propsd = prop_dictionary_internalize_from_file(path);
free(path);
if (propsd == NULL) {
printf("%s: unexistent %s metadata file.\n", pkgname,
XBPS_PKGPROPS);
rv = errno;
broken = true;
goto out;
} else if (prop_object_type(propsd) != PROP_TYPE_DICTIONARY) {
printf("%s: invalid %s metadata file.\n", pkgname,
XBPS_PKGPROPS);
rv = EINVAL;
broken = true;
goto out1;
} else if (prop_dictionary_count(propsd) == 0) {
printf("%s: incomplete %s metadata file.\n", pkgname,
XBPS_PKGPROPS);
rv = EINVAL;
broken = true;
goto out1;
}
/*
* Check for files.plist metadata file.
*/
path = xbps_xasprintf("%s/%s/metadata/%s/%s", rootdir,
XBPS_META_PATH, pkgname, XBPS_PKGFILES);
if (path == NULL) {
rv = errno;
goto out1;
}
filesd = prop_dictionary_internalize_from_file(path);
free(path);
if (filesd == NULL) {
printf("%s: unexistent %s metadata file.\n", pkgname,
XBPS_PKGPROPS);
rv = ENOENT;
broken = true;
goto out1;
} else if (prop_object_type(filesd) != PROP_TYPE_DICTIONARY) {
printf("%s: invalid %s metadata file.\n", pkgname,
XBPS_PKGFILES);
rv = EINVAL;
broken = true;
goto out2;
} else if (prop_dictionary_count(filesd) == 0) {
printf("%s: incomplete %s metadata file.\n", pkgname,
XBPS_PKGFILES);
rv = EINVAL;
broken = true;
goto out2;
} else if (((array = prop_dictionary_get(filesd, "files")) == NULL) ||
((array = prop_dictionary_get(filesd, "links")) == NULL) ||
((array = prop_dictionary_get(filesd, "dirs")) == NULL)) {
printf("%s: incomplete %s metadata file.\n", pkgname,
XBPS_PKGFILES);
rv = EINVAL;
broken = true;
goto out2;
}
printf("%s: metadata check PASSED.\n", pkgname);
/*
* Check for missing files and its hash.
*/
array = prop_dictionary_get(filesd, "files");
if ((prop_object_type(array) == PROP_TYPE_ARRAY) &&
prop_array_count(array) > 0) {
iter = xbps_get_array_iter_from_dict(filesd, "files");
if (iter == NULL) {
rv = ENOMEM;
goto out2;
}
while ((obj = prop_object_iterator_next(iter))) {
prop_dictionary_get_cstring_nocopy(obj, "file", &file);
path = xbps_xasprintf("%s/%s", rootdir, file);
if (path == NULL) {
prop_object_iterator_release(iter);
rv = errno;
goto out2;
}
prop_dictionary_get_cstring_nocopy(obj,
"sha256", &sha256);
rv = xbps_check_file_hash(path, sha256);
switch (rv) {
case 0:
break;
case ENOENT:
printf("%s: unexistent file %s.\n",
pkgname, file);
files_broken = true;
broken = true;
break;
case ERANGE:
printf("%s: hash mismatch for %s.\n",
pkgname, file);
files_broken = true;
broken = true;
break;
default:
printf("%s: unexpected error for %s (%s)\n",
pkgname, file, strerror(rv));
break;
}
free(path);
}
prop_object_iterator_release(iter);
if (files_broken)
printf("%s: files check FAILED.\n", pkgname);
else
printf("%s: files check PASSED.\n", pkgname);
}
/*
* Check for missing configuration files.
*/
array = prop_dictionary_get(filesd, "conf_files");
if (array && prop_object_type(array) == PROP_TYPE_ARRAY &&
prop_array_count(array) > 0) {
iter = xbps_get_array_iter_from_dict(filesd, "conf_files");
if (iter == NULL) {
rv = ENOMEM;
goto out2;
}
while ((obj = prop_object_iterator_next(iter))) {
prop_dictionary_get_cstring_nocopy(obj, "file", &file);
path = xbps_xasprintf("%s/%s", rootdir, file);
if (path == NULL) {
prop_object_iterator_release(iter);
rv = ENOMEM;
goto out2;
}
if ((rv = access(path, R_OK)) == -1) {
if (errno == ENOENT) {
printf("%s: unexistent file %s\n",
pkgname, file);
broken = true;
} else
printf("%s: unexpected error for "
"%s (%s)\n", pkgname, file,
strerror(errno));
}
free(path);
}
prop_object_iterator_release(iter);
if (rv == 0)
printf("%s: configuration files check PASSED.\n",
pkgname);
else
printf("%s: configuration files check FAILED.\n",
pkgname);
}
/*
* Check for missing run time dependencies.
*/
if (xbps_pkg_has_rundeps(propsd)) {
iter = xbps_get_array_iter_from_dict(propsd, "run_depends");
if (iter == NULL) {
rv = ENOMEM;
goto out2;
}
while ((obj = prop_object_iterator_next(iter))) {
reqpkg = prop_string_cstring_nocopy(obj);
if (xbps_check_is_installed_pkg(reqpkg) < 0) {
rv = ENOENT;
printf("%s: dependency not satisfied: %s\n",
pkgname, reqpkg);
broken = true;
}
}
prop_object_iterator_release(iter);
if (rv == ENOENT)
printf("%s: run-time dependency check FAILED.\n",
pkgname);
else
printf("%s: run-time dependency check PASSED.\n",
pkgname);
}
out2:
prop_object_release(filesd);
out1:
prop_object_release(propsd);
out:
prop_object_release(pkgd);
if (broken) {
rv = xbps_set_pkg_state_installed(pkgname,
XBPS_PKG_STATE_BROKEN);
if (rv == 0)
printf("%s: changed package state to broken.\n",
pkgname);
else
printf("%s: can't change package state (%s).\n",
pkgname, strerror(rv));
}
xbps_release_regpkgdb_dict();
return rv;
}

View file

@ -28,7 +28,8 @@
void xbps_install_pkg(const char *, bool, bool); void xbps_install_pkg(const char *, bool, bool);
void xbps_autoremove_pkgs(void); void xbps_autoremove_pkgs(void);
void xbps_remove_pkg(const char *, bool); void xbps_remove_installed_pkg(const char *, bool);
void xbps_autoupdate_pkgs(bool); void xbps_autoupdate_pkgs(bool);
int xbps_check_pkg_integrity(const char *);
#endif /* !_XBPS_BIN_DEFS_H_ */ #endif /* !_XBPS_BIN_DEFS_H_ */

View file

@ -27,6 +27,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <err.h>
#include <errno.h> #include <errno.h>
#include <limits.h> #include <limits.h>
#include <prop/proplib.h> #include <prop/proplib.h>
@ -34,8 +35,25 @@
#include <xbps_api.h> #include <xbps_api.h>
#include "defs.h" #include "defs.h"
enum {
TRANS_ONE,
TRANS_ALL
};
struct transaction {
prop_dictionary_t dict;
prop_object_iterator_t iter;
const char *originpkgname;
const char *curpkgname;
int type;
bool force;
bool update;
};
static void show_missing_deps(prop_dictionary_t, const char *); static void show_missing_deps(prop_dictionary_t, const char *);
static int show_missing_dep_cb(prop_object_t, void *, bool *); static int show_missing_dep_cb(prop_object_t, void *, bool *);
static int exec_transaction(struct transaction *);
static void cleanup(int);
static void static void
show_missing_deps(prop_dictionary_t d, const char *pkgname) show_missing_deps(prop_dictionary_t d, const char *pkgname)
@ -65,36 +83,44 @@ show_missing_dep_cb(prop_object_t obj, void *arg, bool *loop_done)
return EINVAL; return EINVAL;
} }
static void static int
check_pkg_hashes(prop_dictionary_t props, prop_object_iterator_t iter) check_pkg_hashes(prop_object_iterator_t iter)
{ {
prop_object_t obj; prop_object_t obj;
const char *repoloc, *filename; const char *pkgname, *repoloc, *filename;
int rv = 0; int rv = 0;
pkg_state_t state = 0;
printf("Checking binary package file(s) integrity...\n"); printf("Checking binary package file(s) integrity...\n");
while ((obj = prop_object_iterator_next(iter)) != NULL) { while ((obj = prop_object_iterator_next(iter)) != NULL) {
prop_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname);
state = 0;
if (xbps_get_pkg_state_dictionary(obj, &state) != 0)
return EINVAL;
if (state == XBPS_PKG_STATE_UNPACKED)
continue;
prop_dictionary_get_cstring_nocopy(obj, "repository", &repoloc); prop_dictionary_get_cstring_nocopy(obj, "repository", &repoloc);
prop_dictionary_get_cstring_nocopy(obj, "filename", &filename); prop_dictionary_get_cstring_nocopy(obj, "filename", &filename);
rv = xbps_check_pkg_file_hash(obj, repoloc); rv = xbps_check_pkg_file_hash(obj, repoloc);
if (rv != 0 && rv != ERANGE) { if (rv != 0 && rv != ERANGE) {
printf("error: checking hash for %s (%s)\n", printf("Unexpected error while checking hash for "
filename, strerror(rv)); "%s (%s)\n", filename, strerror(rv));
prop_object_release(props); return -1;
exit(EXIT_FAILURE);
} else if (rv != 0 && rv == ERANGE) { } else if (rv != 0 && rv == ERANGE) {
printf("Hash doesn't match for %s!\n", filename); printf("Hash mismatch for %s, exiting.\n",
prop_object_release(props); filename);
exit(EXIT_FAILURE); return -1;
} }
} }
prop_object_iterator_reset(iter); prop_object_iterator_reset(iter);
printf("\n");
return 0;
} }
static void static int
show_transaction_sizes(prop_dictionary_t props, prop_object_iterator_t iter, show_transaction_sizes(prop_object_iterator_t iter, const char *descr)
const char *descr)
{ {
prop_object_t obj; prop_object_t obj;
uint64_t tsize = 0, dlsize = 0, instsize = 0; uint64_t tsize = 0, dlsize = 0, instsize = 0;
@ -145,301 +171,344 @@ show_transaction_sizes(prop_dictionary_t props, prop_object_iterator_t iter,
*/ */
if (xbps_humanize_number(size, 5, (int64_t)dlsize, if (xbps_humanize_number(size, 5, (int64_t)dlsize,
"", HN_AUTOSCALE, HN_NOSPACE) == -1) { "", HN_AUTOSCALE, HN_NOSPACE) == -1) {
printf("error: humanize_number %s\n", strerror(errno)); printf("error: humanize_number returns %s\n",
prop_object_release(props); strerror(errno));
exit(EXIT_FAILURE); return -1;
} }
printf("Total download size: %s\n", size); printf("Total download size: %s\n", size);
if (xbps_humanize_number(size, 5, (int64_t)instsize, if (xbps_humanize_number(size, 5, (int64_t)instsize,
"", HN_AUTOSCALE, HN_NOSPACE) == -1) { "", HN_AUTOSCALE, HN_NOSPACE) == -1) {
printf("error: humanize_number2 %s\n", strerror(errno)); printf("error: humanize_number2 returns %s\n",
prop_object_release(props); strerror(errno));
exit(EXIT_FAILURE); return -1;
} }
printf("Total installed size: %s\n\n", size); printf("Total installed size: %s\n\n", size);
return 0;
} }
void void
xbps_install_pkg(const char *pkg, bool force, bool update) xbps_install_pkg(const char *pkg, bool force, bool update)
{ {
prop_dictionary_t props, instpkg; struct transaction *trans;
prop_dictionary_t pkgd;
prop_array_t array; prop_array_t array;
prop_object_t obj;
prop_object_iterator_t iter;
const char *instver, *origin, *pkgname, *version;
int rv = 0; int rv = 0;
bool pkg_is_dep = false, doup = false;
/* /*
* Find and sort all required package dictionaries. * Find all required pkgs and sort the package transaction.
*/ */
printf("Finding/sorting required binary packages...\n"); pkgd = xbps_find_pkg_installed_from_plist(pkg);
if (update) {
if (pkgd) {
if ((rv = xbps_find_new_pkg(pkg, pkgd)) == 0) {
printf("Package '%s' is up to date.\n", pkg);
prop_object_release(pkgd);
cleanup(rv);
}
prop_object_release(pkgd);
} else {
printf("Package '%s' not installed.\n", pkg);
cleanup(rv);
}
} else {
if (pkgd) {
printf("Package '%s' is already installed.\n", pkg);
prop_object_release(pkgd);
cleanup(rv);
}
rv = xbps_prepare_pkg(pkg); rv = xbps_prepare_pkg(pkg);
if (rv != 0 && rv == EAGAIN) { if (rv != 0 && rv == EAGAIN) {
printf("Unable to locate %s in repository pool.\n", pkg); printf("unable to locate %s in repository pool.", pkg);
exit(EXIT_FAILURE); cleanup(rv);
} else if (rv != 0 && rv != ENOENT) { } else if (rv != 0 && rv != ENOENT) {
printf("Unexpected error: %s\n", strerror(rv)); printf("unexpected error: %s", strerror(rv));
exit(EXIT_FAILURE); cleanup(rv);
}
} }
props = xbps_get_pkg_props(); trans = calloc(1, sizeof(struct transaction));
if (props == NULL) { if (trans == NULL)
goto out;
trans->dict = xbps_get_pkg_props();
if (trans->dict == NULL) {
printf("error: unexistent props dictionary!\n"); printf("error: unexistent props dictionary!\n");
exit(EXIT_FAILURE); goto out1;
} }
/* /*
* Bail out if there are unresolved deps. * Bail out if there are unresolved deps.
*/ */
array = prop_dictionary_get(props, "missing_deps"); array = prop_dictionary_get(trans->dict, "missing_deps");
if (prop_array_count(array) > 0) { if (prop_array_count(array) > 0) {
show_missing_deps(props, pkg); show_missing_deps(trans->dict, pkg);
goto out; goto out2;
} }
prop_dictionary_get_cstring_nocopy(props, "origin", &origin); prop_dictionary_get_cstring_nocopy(trans->dict,
"origin", &trans->originpkgname);
array = prop_dictionary_get(props, "packages"); /*
if (array == NULL || prop_array_count(array) == 0) { * It's time to run the transaction!
printf("error: empty packages array!\n"); */
goto out; trans->iter = xbps_get_array_iter_from_dict(trans->dict, "packages");
if (trans->iter == NULL) {
printf("error: allocating array mem! (%s)",
strerror(errno));
goto out2;
} }
iter = prop_array_iterator(array);
if (iter == NULL) { trans->force = force;
printf("error: allocating array mem! (%s)\n", strerror(errno)); trans->update = update;
goto out; trans->type = TRANS_ONE;
rv = exec_transaction(trans);
prop_object_iterator_release(trans->iter);
out2:
prop_object_release(trans->dict);
out1:
free(trans);
out:
cleanup(rv);
} }
static int
exec_transaction(struct transaction *trans)
{
prop_dictionary_t instpkgd;
prop_object_t obj;
const char *pkgname, *version, *instver, *filename;
int rv = 0;
bool essential, isdep;
pkg_state_t state = 0;
assert(trans != NULL);
assert(trans->dict != NULL);
assert(trans->iter != NULL);
essential = isdep = false;
/* /*
* Show download/installed size for the transaction. * Show download/installed size for the transaction.
*/ */
show_transaction_sizes(props, iter, "installed"); rv = show_transaction_sizes(trans->iter,
trans->type == TRANS_ALL ? "updated" : "installed");
if (rv != 0)
return rv;
/* /*
* Ask interactively (if -f not set). * Ask interactively (if -f not set).
*/ */
if (force == false) { if (trans->force == false) {
if (xbps_noyes("Do you want to continue?") == false) { if (xbps_noyes("Do you want to continue?") == false) {
printf("Aborting!\n"); printf("Aborting!\n");
goto out2; return 0;
} }
} }
/* /*
* Check the SHA256 hash for all required packages. * Check the SHA256 hash for all required packages.
*/ */
check_pkg_hashes(props, iter); if ((rv = check_pkg_hashes(trans->iter)) != 0)
return rv;
/* /*
* Install all packages, the list is already sorted. * Iterate over the transaction dictionary.
*/ */
while ((obj = prop_object_iterator_next(iter)) != NULL) { while ((obj = prop_object_iterator_next(trans->iter)) != NULL) {
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);
if (strcmp(origin, pkgname)) prop_dictionary_get_bool(obj, "essential", &essential);
pkg_is_dep = true; prop_dictionary_get_cstring_nocopy(obj, "filename", &filename);
if ((trans->type == TRANS_ONE) &&
strcmp(trans->originpkgname, pkgname))
isdep = true;
if (update && strcmp(pkg, pkgname) == 0) {
/* /*
* Update a package, firstly removing current package. * If dependency is already unpacked skip this phase.
*/ */
instpkg = xbps_find_pkg_installed_from_plist(pkgname); state = 0;
if (instpkg == NULL) { if (xbps_get_pkg_state_dictionary(obj, &state) != 0)
return EINVAL;
if (state == XBPS_PKG_STATE_UNPACKED)
continue;
if ((trans->type == TRANS_ALL) ||
(trans->update &&
strcmp(trans->curpkgname, pkgname) == 0)) {
instpkgd = xbps_find_pkg_installed_from_plist(pkgname);
if (instpkgd == NULL) {
printf("error: unable to find %s installed " printf("error: unable to find %s installed "
"dict!\n", pkgname); "dict!\n", pkgname);
goto out2; return EINVAL;
} }
prop_dictionary_get_cstring_nocopy(instpkg, prop_dictionary_get_cstring_nocopy(instpkgd,
"version", &instver); "version", &instver);
printf("Updating package %s-%s to %s...\n", pkgname, prop_object_release(instpkgd);
instver, version);
prop_object_release(instpkg); /*
rv = xbps_remove_binary_pkg(pkgname, update); * If this package is not 'essential', just remove
* the old package and install the new one. Otherwise
* we just overwrite the files.
*/
if (essential == false) {
rv = xbps_remove_pkg(pkgname, version, true);
if (rv != 0) { if (rv != 0) {
printf("error: removing %s-%s (%s)\n", printf("error: removing %s-%s (%s)\n",
pkgname, instver, strerror(rv)); pkgname, instver, strerror(rv));
goto out2; return rv;
}
} }
} else {
printf("Installing %s%s-%s ...\n",
pkg_is_dep ? "dependency " : "", pkgname, version);
} }
/* /*
* Unpack binary package. * Unpack binary package.
*/ */
if ((rv = xbps_unpack_binary_pkg(obj)) != 0) { printf("Unpacking %s-%s (from .../%s) ...\n", pkgname, version,
filename);
if ((rv = xbps_unpack_binary_pkg(obj, essential)) != 0) {
printf("error: unpacking %s-%s (%s)\n", pkgname, printf("error: unpacking %s-%s (%s)\n", pkgname,
version, strerror(rv)); version, strerror(rv));
goto out2; return rv;
} }
/* /*
* Register binary package. * Register binary package.
*/ */
if (update && !pkg_is_dep) if ((rv = xbps_register_pkg(obj, isdep)) != 0) {
doup = true;
if ((rv = xbps_register_pkg(obj, doup, pkg_is_dep)) != 0) {
printf("error: registering %s-%s! (%s)\n", printf("error: registering %s-%s! (%s)\n",
pkgname, version, strerror(rv)); pkgname, version, strerror(rv));
goto out2; return rv;
} }
pkg_is_dep = false; isdep = false;
/*
* Set package state to unpacked in the transaction
* dictionary.
*/
if ((rv = xbps_set_pkg_state_dictionary(obj,
XBPS_PKG_STATE_UNPACKED)) != 0)
return rv;
} }
out2: prop_object_iterator_reset(trans->iter);
prop_object_iterator_release(iter); /*
out: * Configure all unpacked packages.
prop_object_release(props); */
xbps_release_repolist_data(); while ((obj = prop_object_iterator_next(trans->iter)) != NULL) {
xbps_release_regpkgdb_dict(); prop_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname);
if (rv != 0) prop_dictionary_get_cstring_nocopy(obj, "version", &version);
exit(EXIT_FAILURE); printf("Configuring package %s-%s ...\n", pkgname, version);
exit(EXIT_SUCCESS); if ((rv = xbps_configure_pkg(pkgname, version)) != 0) {
printf("Error configuring package %s-%s\n",
pkgname, version);
return rv;
}
}
return 0;
} }
void void
xbps_autoupdate_pkgs(bool force) xbps_autoupdate_pkgs(bool force)
{ {
prop_dictionary_t dict, props, instpkg; struct transaction *trans;
prop_array_t array; prop_dictionary_t dict;
prop_object_t obj; prop_object_t obj;
prop_object_iterator_t iter; const char *pkgname;
const char *pkgname, *version, *instver;
int rv = 0; int rv = 0;
/*
* Prepare dictionary with all registered packages.
*/
dict = xbps_prepare_regpkgdb_dict(); dict = xbps_prepare_regpkgdb_dict();
if (dict == NULL) { if (dict == NULL) {
printf("No packages currently installed (%s).\n", printf("No packages currently installed (%s).\n",
strerror(errno)); strerror(errno));
exit(EXIT_SUCCESS); cleanup(rv);
} }
/*
iter = xbps_get_array_iter_from_dict(dict, "packages"); * Prepare dictionary with all registered repositories.
if (iter == NULL) { */
rv = EINVAL;
goto out;
}
if ((rv = xbps_prepare_repolist_data()) != 0) if ((rv = xbps_prepare_repolist_data()) != 0)
goto out; goto out;
while ((obj = prop_object_iterator_next(iter)) != NULL) { /*
* Prepare transaction data.
*/
trans = calloc(1, sizeof(struct transaction));
if (trans == NULL)
goto out;
trans->iter = xbps_get_array_iter_from_dict(dict, "packages");
if (trans->iter == NULL) {
rv = EINVAL;
goto out1;
}
/*
* Find out if there is a newer version for all currently
* installed packages.
*/
while ((obj = prop_object_iterator_next(trans->iter)) != NULL) {
prop_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname); prop_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname);
rv = xbps_find_new_pkg(pkgname, obj); rv = xbps_find_new_pkg(pkgname, obj);
if (rv != 0) if (rv != 0) {
break; prop_object_iterator_release(trans->iter);
goto out1;
} }
prop_object_iterator_release(iter); }
prop_object_iterator_release(trans->iter);
/* Sort the list of packages */ /*
props = xbps_get_pkg_props(); * Get package transaction dictionary.
if (props == NULL) { */
trans->dict = xbps_get_pkg_props();
if (trans->dict == NULL) {
if (errno == 0) { if (errno == 0) {
printf("All packages are up-to-date.\n"); printf("All packages are up-to-date.\n");
exit(EXIT_SUCCESS); goto out;
} }
printf("Error while checking for new pkgs: %s\n", printf("Error while checking for new pkgs: %s\n",
strerror(errno)); strerror(errno));
goto out; goto out1;
} }
if ((rv = xbps_sort_pkg_deps(props)) != 0) { /*
* Sort the package transaction dictionary.
*/
if ((rv = xbps_sort_pkg_deps(trans->dict)) != 0) {
printf("Error while sorting packages: %s\n", printf("Error while sorting packages: %s\n",
strerror(rv)); strerror(rv));
goto out; goto out2;
} }
/* Update all packages now */
array = prop_dictionary_get(props, "packages"); /*
if (array == NULL || prop_array_count(array) == 0) { * It's time to run the transaction!
printf("error: empty packages array!\n"); */
prop_object_release(props); trans->iter = xbps_get_array_iter_from_dict(trans->dict, "packages");
goto out; if (trans->iter == NULL) {
}
iter = prop_array_iterator(array);
if (iter == NULL) {
printf("error: allocating array mem! (%s)\n", strerror(errno)); printf("error: allocating array mem! (%s)\n", strerror(errno));
prop_object_release(props);
goto out;
}
/*
* Show download/installed size for the transaction.
*/
show_transaction_sizes(props, iter, "upgraded");
/*
* Ask interactively (if -f not set).
*/
if (force == false) {
if (xbps_noyes("Do you want to continue?") == false) {
printf("Aborting!\n");
prop_object_release(props);
goto out2;
}
}
/*
* Check the SHA256 hash for all required packages.
*/
check_pkg_hashes(props, iter);
while ((obj = prop_object_iterator_next(iter)) != NULL) {
prop_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname);
prop_dictionary_get_cstring_nocopy(obj, "version", &version);
/*
* Update a package, firstly removing current package.
*/
instpkg = xbps_find_pkg_installed_from_plist(pkgname);
if (instpkg == NULL) {
printf("error: unable to find %s installed "
"dict!\n", pkgname);
prop_object_release(props);
goto out2; goto out2;
} }
prop_dictionary_get_cstring_nocopy(instpkg, trans->force = force;
"version", &instver); trans->update = true;
printf("Updating package %s-%s to %s...\n", pkgname, trans->type = TRANS_ALL;
instver, version); rv = exec_transaction(trans);
prop_object_release(instpkg);
rv = xbps_remove_binary_pkg(pkgname, true);
if (rv != 0) {
printf("error: removing %s-%s (%s)\n",
pkgname, instver, strerror(rv));
prop_object_release(props);
goto out2;
}
/*
* Unpack binary package.
*/
if ((rv = xbps_unpack_binary_pkg(obj)) != 0) {
printf("error: unpacking %s-%s (%s)\n", pkgname,
version, strerror(rv));
prop_object_release(props);
goto out2;
}
/*
* Register binary package.
*/
if ((rv = xbps_register_pkg(obj, true, false)) != 0) {
printf("error: registering %s-%s! (%s)\n",
pkgname, version, strerror(rv));
prop_object_release(props);
goto out2;
}
}
prop_object_iterator_release(trans->iter);
out2: out2:
prop_object_iterator_release(iter); prop_object_release(trans->dict);
out1:
free(trans);
out: out:
cleanup(rv);
}
static void
cleanup(int rv)
{
xbps_release_repolist_data(); xbps_release_repolist_data();
xbps_release_regpkgdb_dict(); xbps_release_regpkgdb_dict();
if (rv != 0) exit(rv == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
exit(EXIT_FAILURE);
exit(EXIT_SUCCESS);
} }

View file

@ -45,9 +45,10 @@ usage(void)
{ {
printf("Usage: xbps-bin [options] [target] [arguments]\n\n" printf("Usage: xbps-bin [options] [target] [arguments]\n\n"
" Available targets:\n" " Available targets:\n"
" autoremove, autoupdate, files, install, list, remove\n" " autoremove, autoupdate, check, files, install, list\n"
" show, update\n" " remove, show, update\n"
" Targets with arguments:\n" " Targets with arguments:\n"
" check\t<pkgname>\n"
" files\t<pkgname>\n" " files\t<pkgname>\n"
" install\t<pkgname>\n" " install\t<pkgname>\n"
" remove\t<pkgname>\n" " remove\t<pkgname>\n"
@ -56,8 +57,6 @@ usage(void)
" Options shared by all targets:\n" " Options shared by all targets:\n"
" -r\t\t<rootdir>\n" " -r\t\t<rootdir>\n"
" -v\t\t<verbose>\n" " -v\t\t<verbose>\n"
" Options used by the files target:\n"
" -C\t\tTo check the SHA256 hash for any listed file.\n"
" Options used by the (auto)remove target:\n" " Options used by the (auto)remove target:\n"
" -f\t\tForce installation or removal of packages.\n" " -f\t\tForce installation or removal of packages.\n"
" \t\tBeware with this option if you use autoremove!\n" " \t\tBeware with this option if you use autoremove!\n"
@ -65,7 +64,7 @@ usage(void)
" Examples:\n" " Examples:\n"
" $ xbps-bin autoremove\n" " $ xbps-bin autoremove\n"
" $ xbps-bin autoupdate\n" " $ xbps-bin autoupdate\n"
" $ xbps-bin -C files klibc\n" " $ xbps-bin files klibc\n"
" $ xbps-bin install klibc\n" " $ xbps-bin install klibc\n"
" $ xbps-bin -r /path/to/root install klibc\n" " $ xbps-bin -r /path/to/root install klibc\n"
" $ xbps-bin list\n" " $ xbps-bin list\n"
@ -101,13 +100,10 @@ main(int argc, char **argv)
{ {
prop_dictionary_t dict; prop_dictionary_t dict;
int c, flags = 0, rv = 0; int c, flags = 0, rv = 0;
bool chkhash = false, force = false, verbose = false; bool force = false, verbose = false;
while ((c = getopt(argc, argv, "Cfr:v")) != -1) { while ((c = getopt(argc, argv, "Cfr:v")) != -1) {
switch (c) { switch (c) {
case 'C':
chkhash = true;
break;
case 'f': case 'f':
force = true; force = true;
break; break;
@ -178,7 +174,7 @@ main(int argc, char **argv)
if (argc != 2) if (argc != 2)
usage(); usage();
xbps_remove_pkg(argv[1], force); xbps_remove_installed_pkg(argv[1], force);
} else if (strcasecmp(argv[0], "show") == 0) { } else if (strcasecmp(argv[0], "show") == 0) {
/* Shows info about an installed binary package. */ /* Shows info about an installed binary package. */
@ -196,12 +192,19 @@ main(int argc, char **argv)
if (argc != 2) if (argc != 2)
usage(); usage();
rv = show_pkg_files_from_metadir(argv[1], chkhash); rv = show_pkg_files_from_metadir(argv[1]);
if (rv != 0) { if (rv != 0) {
printf("Package %s not installed.\n", argv[1]); printf("Package %s not installed.\n", argv[1]);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} else if (strcasecmp(argv[0], "check") == 0) {
/* Checks the integrity of an installed package. */
if (argc != 2)
usage();
rv = xbps_check_pkg_integrity(argv[1]);
} else if (strcasecmp(argv[0], "autoupdate") == 0) { } else if (strcasecmp(argv[0], "autoupdate") == 0) {
/* /*
* To update all packages currently installed. * To update all packages currently installed.

View file

@ -96,7 +96,7 @@ xbps_autoremove_pkgs(void)
prop_dictionary_get_cstring_nocopy(obj, "version", &version); prop_dictionary_get_cstring_nocopy(obj, "version", &version);
printf("Removing package %s-%s ...\n", pkgname, version); printf("Removing package %s-%s ...\n", pkgname, version);
if ((rv = xbps_remove_binary_pkg(pkgname, false)) != 0) if ((rv = xbps_remove_pkg(pkgname, version, false)) != 0)
goto out2; goto out2;
} }
out2: out2:
@ -110,7 +110,7 @@ out:
} }
void void
xbps_remove_pkg(const char *pkgname, bool force) xbps_remove_installed_pkg(const char *pkgname, bool force)
{ {
prop_array_t reqby; prop_array_t reqby;
prop_dictionary_t dict; prop_dictionary_t dict;
@ -151,7 +151,7 @@ xbps_remove_pkg(const char *pkgname, bool force)
} }
printf("Removing package %s-%s ...\n", pkgname, version); printf("Removing package %s-%s ...\n", pkgname, version);
if ((rv = xbps_remove_binary_pkg(pkgname, false)) != 0) { if ((rv = xbps_remove_pkg(pkgname, version, false)) != 0) {
printf("Unable to remove %s-%s (%s).\n", printf("Unable to remove %s-%s (%s).\n",
pkgname, version, strerror(errno)); pkgname, version, strerror(errno));
goto out; goto out;

View file

@ -139,7 +139,12 @@ main(int argc, char **argv)
prop_dictionary_set_cstring_nocopy(dict, "version", argv[2]); prop_dictionary_set_cstring_nocopy(dict, "version", argv[2]);
prop_dictionary_set_cstring_nocopy(dict, "short_desc", argv[3]); prop_dictionary_set_cstring_nocopy(dict, "short_desc", argv[3]);
rv = xbps_register_pkg(dict, false, automatic); rv = xbps_set_pkg_state_installed(argv[1],
XBPS_PKG_STATE_INSTALLED);
if (rv != 0)
exit(EXIT_FAILURE);
rv = xbps_register_pkg(dict, automatic);
if (rv == EEXIST) { if (rv == EEXIST) {
printf("%s=> %s-%s already registered.\n", printf("%s=> %s-%s already registered.\n",
in_chroot ? "[chroot] " : "", argv[1], argv[2]); in_chroot ? "[chroot] " : "", argv[1], argv[2]);

View file

@ -36,7 +36,7 @@
#include "index.h" #include "index.h"
/* Array of valid architectures */ /* Array of valid architectures */
const char *archdirs[] = { "i686", "x86_64", "noarch", NULL }; static const char *archdirs[] = { "i686", "x86_64", "noarch", NULL };
static prop_dictionary_t static prop_dictionary_t
repoidx_getdict(const char *pkgdir) repoidx_getdict(const char *pkgdir)
@ -52,16 +52,13 @@ repoidx_getdict(const char *pkgdir)
dict = prop_dictionary_internalize_from_file(plist); dict = prop_dictionary_internalize_from_file(plist);
if (dict == NULL) { if (dict == NULL) {
dict = prop_dictionary_create(); dict = prop_dictionary_create();
if (dict == NULL) { if (dict == NULL)
free(plist); goto out;
return NULL;
}
array = prop_array_create(); array = prop_array_create();
if (array == NULL) { if (array == NULL) {
free(plist);
prop_object_release(dict); prop_object_release(dict);
return NULL; goto out;
} }
prop_dictionary_set(dict, "packages", array); prop_dictionary_set(dict, "packages", array);
@ -71,6 +68,7 @@ repoidx_getdict(const char *pkgdir)
prop_dictionary_set_cstring_nocopy(dict, prop_dictionary_set_cstring_nocopy(dict,
"pkgindex-version", XBPS_PKGINDEX_VERSION); "pkgindex-version", XBPS_PKGINDEX_VERSION);
} }
out:
free(plist); free(plist);
return dict; return dict;
@ -84,38 +82,36 @@ repoidx_addpkg(const char *file, const char *filename, const char *pkgdir)
struct archive *ar; struct archive *ar;
struct archive_entry *entry; struct archive_entry *entry;
struct stat st; struct stat st;
ssize_t nbytes = -1;
const char *pkgname, *version, *regver; const char *pkgname, *version, *regver;
char *props, *sha256, *plist; char *sha256, *plist;
size_t propslen = 0;
int rv = 0; int rv = 0;
ar = archive_read_new(); ar = archive_read_new();
if (ar == NULL) if (ar == NULL) {
return errno; rv = errno;
goto out;
}
/* Enable support for tar format and all compression methods */ /* Enable support for tar format and all compression methods */
archive_read_support_compression_all(ar); archive_read_support_compression_all(ar);
archive_read_support_format_tar(ar); archive_read_support_format_tar(ar);
if ((rv = archive_read_open_filename(ar, file, if ((rv = archive_read_open_filename(ar, file,
ARCHIVE_READ_BLOCKSIZE)) == -1) { ARCHIVE_READ_BLOCKSIZE)) == -1) {
archive_read_finish(ar); rv = errno;
return errno; goto out1;
} }
/* Get existing or create repo index dictionary */ /* Get existing or create repo index dictionary */
idxdict = repoidx_getdict(pkgdir); idxdict = repoidx_getdict(pkgdir);
if (idxdict == NULL) { if (idxdict == NULL) {
archive_read_finish(ar); rv = errno;
return errno; goto out1;
} }
plist = xbps_get_pkg_index_plist(pkgdir); plist = xbps_get_pkg_index_plist(pkgdir);
if (plist == NULL) { if (plist == NULL) {
prop_dictionary_remove(idxdict, "packages"); prop_dictionary_remove(idxdict, "packages");
prop_object_release(idxdict); rv = ENOMEM;
archive_read_finish(ar); goto out2;
return ENOMEM;
} }
/* /*
@ -123,32 +119,15 @@ repoidx_addpkg(const char *file, const char *filename, const char *pkgdir)
* into a buffer. * into a buffer.
*/ */
while (archive_read_next_header(ar, &entry) == ARCHIVE_OK) { while (archive_read_next_header(ar, &entry) == ARCHIVE_OK) {
if (strstr(archive_entry_pathname(entry), "props.plist") == 0) { if (strstr(archive_entry_pathname(entry), XBPS_PKGPROPS) == 0) {
archive_read_data_skip(ar); archive_read_data_skip(ar);
continue; continue;
} }
newpkgd = xbps_read_dict_from_archive_entry(ar, entry);
propslen = (size_t)archive_entry_size(entry);
props = malloc(propslen);
if (props == NULL) {
rv = errno;
break;
}
nbytes = archive_read_data(ar, props, propslen);
if ((size_t)nbytes != propslen) {
rv = EINVAL;
break;
}
newpkgd = prop_dictionary_internalize(props);
free(props);
propslen = 0;
if (newpkgd == NULL) { if (newpkgd == NULL) {
archive_read_data_skip(ar); printf("%s: can't read %s metadata file, skipping!\n",
continue; file, XBPS_PKGPROPS);
} else if (prop_object_type(newpkgd) != PROP_TYPE_DICTIONARY) { break;
prop_object_release(newpkgd);
archive_read_data_skip(ar);
continue;
} }
prop_dictionary_get_cstring_nocopy(newpkgd, "pkgname", prop_dictionary_get_cstring_nocopy(newpkgd, "pkgname",
@ -233,10 +212,13 @@ repoidx_addpkg(const char *file, const char *filename, const char *pkgdir)
pkgname, version); pkgname, version);
break; break;
} }
archive_read_finish(ar);
free(plist);
prop_object_release(idxdict);
free(plist);
out2:
prop_object_release(idxdict);
out1:
archive_read_finish(ar);
out:
return rv; return rv;
} }
@ -253,7 +235,6 @@ xbps_repo_genindex(const char *pkgdir)
if (uname(&un) == -1) if (uname(&un) == -1)
return errno; return errno;
/* /*
* Iterate over the known architecture directories to find * Iterate over the known architecture directories to find
* binary packages. * binary packages.
@ -296,7 +277,6 @@ xbps_repo_genindex(const char *pkgdir)
free(path); free(path);
return rv; return rv;
} }
} }
(void)closedir(dirp); (void)closedir(dirp);
free(path); free(path);

View file

@ -197,14 +197,14 @@ show_pkg_info_from_metadir(const char *pkgname)
} }
int int
show_pkg_files_from_metadir(const char *pkgname, bool hash) show_pkg_files_from_metadir(const char *pkgname)
{ {
prop_dictionary_t pkgd; prop_dictionary_t pkgd;
prop_array_t array; prop_array_t array;
prop_object_iterator_t iter = NULL; prop_object_iterator_t iter = NULL;
prop_object_t obj; prop_object_t obj;
const char *destdir, *file, *sha256; const char *destdir, *file;
char *plist, *path = NULL, *array_str = "files"; char *plist, *array_str = "files";
int i, rv = 0; int i, rv = 0;
destdir = xbps_get_rootdir(); destdir = xbps_get_rootdir();
@ -233,7 +233,6 @@ show_pkg_files_from_metadir(const char *pkgname, bool hash)
printf("%s\n", file); printf("%s\n", file);
} }
prop_object_iterator_release(iter); prop_object_iterator_release(iter);
iter = NULL;
} }
/* Files and configuration files. */ /* Files and configuration files. */
@ -254,41 +253,10 @@ show_pkg_files_from_metadir(const char *pkgname, bool hash)
} }
while ((obj = prop_object_iterator_next(iter))) { while ((obj = prop_object_iterator_next(iter))) {
prop_dictionary_get_cstring_nocopy(obj, "file", &file); prop_dictionary_get_cstring_nocopy(obj, "file", &file);
if (hash == false) {
printf("%s\n", file); printf("%s\n", file);
continue;
}
printf("%s", file);
if (destdir) {
path = xbps_xasprintf("%s/%s", destdir, file);
if (path == NULL) {
rv = EINVAL;
goto out2;
}
}
prop_dictionary_get_cstring_nocopy(obj,
"sha256", &sha256);
if (destdir)
rv = xbps_check_file_hash(path, sha256);
else
rv = xbps_check_file_hash(file, sha256);
if (rv != 0 && rv != ERANGE)
printf(" (can't check: %s)", strerror(rv));
else if (rv == ERANGE)
printf(" WARNING! SHA256 HASH MISMATCH!");
printf("\n");
if (destdir)
free(path);
} }
prop_object_iterator_release(iter); prop_object_iterator_release(iter);
iter = NULL;
} }
out2:
if (iter != NULL)
prop_object_iterator_release(iter);
out: out:
prop_object_release(pkgd); prop_object_release(pkgd);

View file

@ -28,7 +28,7 @@
int search_string_in_pkgs(prop_object_t, void *, bool *); int search_string_in_pkgs(prop_object_t, void *, bool *);
int show_pkg_info_from_metadir(const char *); int show_pkg_info_from_metadir(const char *);
int show_pkg_files_from_metadir(const char *, bool); int show_pkg_files_from_metadir(const char *);
int show_pkg_info_from_repolist(prop_object_t, void *, bool *); int show_pkg_info_from_repolist(prop_object_t, void *, bool *);
int list_strings_in_array(prop_object_t, void *, bool *); int list_strings_in_array(prop_object_t, void *, bool *);
int list_strings_sep_in_array(prop_object_t, void *, bool *); int list_strings_sep_in_array(prop_object_t, void *, bool *);

View file

@ -5,22 +5,27 @@
A binary package built with xbps is a normal tar(1) archive, compressed A binary package built with xbps is a normal tar(1) archive, compressed
with bzip2 and has the following structure: with bzip2 and has the following structure:
/ Package metadata
/usr ------| -----------------
/var ------| => Package structure that will be installed. /INSTALL
/etc ------| /REMOVE
/files.plist
/props.plist
Package data
-----------------
/usr
/var
/etc
... ...
/var/db/xbps/metadata/$pkgname
/var/db/xbps/metadata/$pkgname/files.plist
/var/db/xbps/metadata/$pkgname/props.plist
/var/db/xbps/metadata/$pkgname/INSTALL
/var/db/xbps/metadata/$pkgname/REMOVE
Metadata info is stored in the "/var/db/xbps/metadata/$pkgname" Metadata info is stored in the "/var/db/xbps/metadata/$pkgname"
directory and two files will be always be present: flist and props.plist. directory and two files will be always be present: files.plist
and props.plist.
The files.plist file contains the list of files/links/dirs that package The files.plist file contains the list of files/links/dirs that package
will install, as well as SHA256 hashes for files. will install, as well as SHA256 hashes for files.
The props.plist file contains package metadata properties and has the The props.plist file contains package metadata properties and has the
following structure: following structure:

View file

@ -29,13 +29,9 @@ xbps-bin:
* Implement shell style match patterns with fnmatch(). * Implement shell style match patterns with fnmatch().
* Make -f flag to overwrite files when installing, and to ignore * Make -f flag to overwrite files when installing, and to ignore
files with wrong checksum or unexistent when removing. files with wrong checksum or unexistent when removing.
* Add a target to check pkg integrity: normal files, metadata
and its dependencies.
libxbps: libxbps:
* Fix glibc updates: removing libc is bad. * Fix glibc updates: removing libc is bad.
* Create xbps_upgrade_pkg() to replace or remove/unpack and register.
Remove duplicate code from xbps-bin/install.c. [IN PROGRESS]
* Add support to upgrade packages but overwritting current files; * Add support to upgrade packages but overwritting current files;
this will fix libc, sh and others. An "essential" boolean obj this will fix libc, sh and others. An "essential" boolean obj
seems to be a good way to find such packages, like dpkg. [IN PROGRESS] seems to be a good way to find such packages, like dpkg. [IN PROGRESS]

View file

@ -9,9 +9,10 @@ LIBXBPS = libxbps.so
LIBXBPS_STATIC = libxbps.a LIBXBPS_STATIC = libxbps.a
LIBXBPS_LDFLAGS = -larchive -lprop -shared -Wl,-soname,$(LIBXBPS).$(MAJOR) LIBXBPS_LDFLAGS = -larchive -lprop -shared -Wl,-soname,$(LIBXBPS).$(MAJOR)
OBJECTS = cmpver.o depends.o fexec.o findpkg.o humanize_number.o OBJECTS = configure.o cmpver.o depends.o fexec.o findpkg.o
OBJECTS += orphans.o plist.o register.o remove.o repository.o requiredby.o OBJECTS += humanize_number.o orphans.o plist.o register.o remove.o
OBJECTS += sha256.o sortdeps.o unpack.o util.o OBJECTS += repository.o requiredby.o sha256.o sortdeps.o state.o
OBJECTS += unpack.o util.o
all: $(LIBXBPS) $(LIBXBPS_STATIC) all: $(LIBXBPS) $(LIBXBPS_STATIC)
.PHONY: all .PHONY: all

92
lib/configure.c Normal file
View file

@ -0,0 +1,92 @@
/*-
* Copyright (c) 2009 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 <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <xbps_api.h>
/*
* Configure a package that is currently unpacked. This
* runs the post INSTALL action if required and updates the
* package state to installed.
*/
int
xbps_configure_pkg(const char *pkgname, const char *version)
{
const char *rootdir;
char *buf;
int rv = 0;
pkg_state_t state = 0;
assert(pkgname != NULL);
assert(version != NULL);
rootdir = xbps_get_rootdir();
if ((rv = xbps_get_pkg_state_installed(pkgname, &state)) != 0)
return rv;
/*
* If package is already installed do nothing, and only
* continue if it's unpacked.
*/
if (state == XBPS_PKG_STATE_INSTALLED)
return 0;
else if (state != XBPS_PKG_STATE_UNPACKED)
return EINVAL;
buf = xbps_xasprintf(".%s/metadata/%s/INSTALL",
XBPS_META_PATH, pkgname);
if (buf == NULL)
return errno;
if (access(buf, R_OK) == 0) {
if (chdir(rootdir) == -1)
return errno;
if ((rv = xbps_file_chdir_exec(rootdir, buf, "post",
pkgname, version, NULL)) != 0) {
free(buf);
printf("%s: post INSTALL action returned: %s\n",
pkgname, strerror(errno));
return rv;
}
} else {
if (errno != ENOENT) {
free(buf);
return errno;
}
}
free(buf);
return xbps_set_pkg_state_installed(pkgname, XBPS_PKG_STATE_INSTALLED);
}

View file

@ -32,29 +32,27 @@
#include <xbps_api.h> #include <xbps_api.h>
static int add_missing_reqdep(prop_dictionary_t, const char *, static int add_missing_reqdep(prop_dictionary_t, const char *, const char *);
const char *); static int find_repo_deps(prop_dictionary_t, prop_dictionary_t, prop_array_t);
static int find_repo_deps(prop_dictionary_t, prop_dictionary_t, static int find_repo_missing_deps(prop_dictionary_t, prop_dictionary_t);
prop_dictionary_t, prop_array_t);
static int find_repo_missing_deps(prop_dictionary_t, prop_dictionary_t,
prop_dictionary_t);
static int static int
store_dependency(prop_dictionary_t master, prop_dictionary_t origind, store_dependency(prop_dictionary_t master, prop_dictionary_t depd,
prop_dictionary_t depd, prop_dictionary_t repod) prop_dictionary_t repod)
{ {
prop_dictionary_t dict; prop_dictionary_t dict;
prop_array_t array; prop_array_t array;
const char *reqbyname, *repoloc; const char *repoloc, *pkgname;
int rv = 0;
pkg_state_t state = 0;
assert(origind != NULL); assert(master != NULL);
assert(depd != NULL); assert(depd != NULL);
assert(repod != NULL); assert(repod != NULL);
/* /*
* Get some info about dependencies and current repository. * Get some info about dependencies and current repository.
*/ */
prop_dictionary_get_cstring_nocopy(origind, "pkgname", &reqbyname); prop_dictionary_get_cstring_nocopy(depd, "pkgname", &pkgname);
prop_dictionary_get_cstring_nocopy(repod, "location-local", &repoloc); prop_dictionary_get_cstring_nocopy(repod, "location-local", &repoloc);
dict = prop_dictionary_copy(depd); dict = prop_dictionary_copy(depd);
@ -66,6 +64,26 @@ store_dependency(prop_dictionary_t master, prop_dictionary_t origind,
prop_object_release(dict); prop_object_release(dict);
return errno; return errno;
} }
/*
* Always set "not-installed" package state. Will be overwritten
* to its correct state later.
*/
rv = xbps_set_pkg_state_dictionary(dict, XBPS_PKG_STATE_NOT_INSTALLED);
if (rv != 0) {
prop_object_release(dict);
return rv;
}
/*
* Overwrite package state in dictionary if it was unpacked
* previously.
*/
rv = xbps_get_pkg_state_installed(pkgname, &state);
if (rv == 0) {
if ((rv = xbps_set_pkg_state_dictionary(dict, state)) != 0) {
prop_object_release(dict);
return rv;
}
}
/* /*
* Add required objects into package dep's dictionary. * Add required objects into package dep's dictionary.
*/ */
@ -132,8 +150,7 @@ xbps_find_deps_in_pkg(prop_dictionary_t master, prop_dictionary_t pkg)
assert(iter != NULL); assert(iter != NULL);
pkg_rdeps = prop_dictionary_get(pkg, "run_depends"); pkg_rdeps = prop_dictionary_get(pkg, "run_depends");
if (pkg_rdeps == NULL) assert(pkg_rdeps != NULL);
return 0;
/* /*
* Iterate over the repository pool and find out if we have * Iterate over the repository pool and find out if we have
@ -145,7 +162,7 @@ xbps_find_deps_in_pkg(prop_dictionary_t master, prop_dictionary_t pkg)
* if any of them is not there it will be added * if any of them is not there it will be added
* into the missing_deps array. * into the missing_deps array.
*/ */
rv = find_repo_deps(master, rdata->rd_repod, pkg, pkg_rdeps); rv = find_repo_deps(master, rdata->rd_repod, pkg_rdeps);
if (rv != 0) { if (rv != 0) {
if (rv == ENOENT) { if (rv == ENOENT) {
rv = 0; rv = 0;
@ -164,7 +181,7 @@ xbps_find_deps_in_pkg(prop_dictionary_t master, prop_dictionary_t pkg)
* just in case that indirect deps weren't found. * just in case that indirect deps weren't found.
*/ */
SIMPLEQ_FOREACH(rdata, &repodata_queue, chain) { SIMPLEQ_FOREACH(rdata, &repodata_queue, chain) {
rv = find_repo_missing_deps(master, rdata->rd_repod, pkg); rv = find_repo_missing_deps(master, rdata->rd_repod);
if (rv != 0 && rv != ENOENT) if (rv != 0 && rv != ENOENT)
return rv; return rv;
} }
@ -173,8 +190,7 @@ xbps_find_deps_in_pkg(prop_dictionary_t master, prop_dictionary_t pkg)
} }
static int static int
find_repo_missing_deps(prop_dictionary_t master, prop_dictionary_t repo, find_repo_missing_deps(prop_dictionary_t master, prop_dictionary_t repo)
prop_dictionary_t pkg)
{ {
prop_array_t array; prop_array_t array;
prop_dictionary_t curpkgd; prop_dictionary_t curpkgd;
@ -214,7 +230,7 @@ find_repo_missing_deps(prop_dictionary_t master, prop_dictionary_t repo,
/* /*
* Package is on repo, add it into the dictionary. * Package is on repo, add it into the dictionary.
*/ */
if ((rv = store_dependency(master, pkg, curpkgd, repo)) != 0) if ((rv = store_dependency(master, curpkgd, repo)) != 0)
break; break;
/* /*
* Remove package from missing_deps array now. * Remove package from missing_deps array now.
@ -233,9 +249,9 @@ find_repo_missing_deps(prop_dictionary_t master, prop_dictionary_t repo,
static int static int
find_repo_deps(prop_dictionary_t master, prop_dictionary_t repo, find_repo_deps(prop_dictionary_t master, prop_dictionary_t repo,
prop_dictionary_t pkg, prop_array_t pkg_rdeps) prop_array_t pkg_rdeps)
{ {
prop_dictionary_t curpkgd; prop_dictionary_t curpkgd, tmpd = NULL;
prop_array_t curpkg_rdeps; prop_array_t curpkg_rdeps;
prop_object_t obj; prop_object_t obj;
prop_object_iterator_t iter; prop_object_iterator_t iter;
@ -285,10 +301,24 @@ find_repo_deps(prop_dictionary_t master, prop_dictionary_t repo,
continue; continue;
} }
} }
/*
* If package is installed but version doesn't satisfy
* the dependency mark it as an update, otherwise as
* an install.
*/
tmpd = xbps_find_pkg_installed_from_plist(pkgname);
if (tmpd != NULL) {
prop_dictionary_set_cstring_nocopy(curpkgd,
"trans-action", "update");
prop_object_release(tmpd);
} else {
prop_dictionary_set_cstring_nocopy(curpkgd,
"trans-action", "install");
}
/* /*
* Package is on repo, add it into the dictionary. * Package is on repo, add it into the dictionary.
*/ */
if ((rv = store_dependency(master, pkg, curpkgd, repo)) != 0) { if ((rv = store_dependency(master, curpkgd, repo)) != 0) {
free(pkgname); free(pkgname);
break; break;
} }
@ -311,7 +341,7 @@ find_repo_deps(prop_dictionary_t master, prop_dictionary_t repo,
/* /*
* Iterate on required pkg to find more deps. * Iterate on required pkg to find more deps.
*/ */
if (!find_repo_deps(master, repo, curpkgd, curpkg_rdeps)) if (!find_repo_deps(master, repo, curpkg_rdeps))
continue; continue;
} }
prop_object_iterator_release(iter); prop_object_iterator_release(iter);

View file

@ -91,7 +91,7 @@ xbps_get_pkg_props(void)
if (pkg_props_initialized == false) if (pkg_props_initialized == false)
return NULL; return NULL;
return prop_dictionary_copy(pkg_props); return pkg_props;
} }
int int
@ -134,13 +134,13 @@ xbps_prepare_repolist_data(void)
array = prop_dictionary_get(dict, "repository-list"); array = prop_dictionary_get(dict, "repository-list");
if (array == NULL) { if (array == NULL) {
rv = EINVAL; rv = EINVAL;
goto out; goto out1;
} }
iter = prop_array_iterator(array); iter = prop_array_iterator(array);
if (iter == NULL) { if (iter == NULL) {
rv = ENOMEM; rv = ENOMEM;
goto out; goto out1;
} }
while ((obj = prop_object_iterator_next(iter)) != NULL) { while ((obj = prop_object_iterator_next(iter)) != NULL) {
@ -175,8 +175,9 @@ xbps_prepare_repolist_data(void)
out2: out2:
prop_object_iterator_release(iter); prop_object_iterator_release(iter);
out: out1:
prop_object_release(dict); prop_object_release(dict);
out:
if (rv != 0) if (rv != 0)
xbps_release_repolist_data(); xbps_release_repolist_data();
@ -283,6 +284,7 @@ xbps_prepare_pkg(const char *pkgname)
struct repository_data *rdata; struct repository_data *rdata;
const char *repoloc; const char *repoloc;
int rv = 0; int rv = 0;
pkg_state_t state = 0;
assert(pkgname != NULL); assert(pkgname != NULL);
@ -364,6 +366,24 @@ xbps_prepare_pkg(const char *pkgname)
goto out; goto out;
} }
/*
* Always set "not-installed" package state. Will be overwritten
* to its correct state later.
*/
rv = xbps_set_pkg_state_dictionary(pkgrd, XBPS_PKG_STATE_NOT_INSTALLED);
if (rv != 0)
goto out;
/*
* Overwrite package state in dictionary if it was unpacked
* previously.
*/
rv = xbps_get_pkg_state_installed(pkgname, &state);
if (rv == 0) {
if ((rv = xbps_set_pkg_state_dictionary(pkgrd, state)) != 0)
goto out;
}
if (!prop_array_add(pkgs_array, pkgrd)) if (!prop_array_add(pkgs_array, pkgrd))
rv = errno; rv = errno;

View file

@ -34,25 +34,10 @@
#include <xbps_api.h> #include <xbps_api.h>
static prop_dictionary_t
make_dict_from_pkg(const char *name, const char *ver, const char *desc)
{
prop_dictionary_t dict;
dict = prop_dictionary_create();
assert(dict != NULL);
prop_dictionary_set_cstring_nocopy(dict, "pkgname", name);
prop_dictionary_set_cstring_nocopy(dict, "version", ver);
prop_dictionary_set_cstring_nocopy(dict, "short_desc", desc);
return dict;
}
int int
xbps_register_pkg(prop_dictionary_t pkgrd, bool update, bool automatic) xbps_register_pkg(prop_dictionary_t pkgrd, bool automatic)
{ {
prop_dictionary_t dict, pkgd, newpkgd; prop_dictionary_t dict, pkgd;
prop_array_t array; prop_array_t array;
const char *pkgname, *version, *desc, *rootdir; const char *pkgname, *version, *desc, *rootdir;
char *plist; char *plist;
@ -69,93 +54,41 @@ xbps_register_pkg(prop_dictionary_t pkgrd, bool update, bool automatic)
prop_dictionary_get_cstring_nocopy(pkgrd, "short_desc", &desc); prop_dictionary_get_cstring_nocopy(pkgrd, "short_desc", &desc);
dict = prop_dictionary_internalize_from_file(plist); dict = prop_dictionary_internalize_from_file(plist);
if (dict == NULL) { if (dict != NULL) {
/*
* No packages registered yet. Register package into
* the dictionary.
*/
dict = prop_dictionary_create();
if (dict == NULL) {
free(plist);
return ENOMEM;
}
array = prop_array_create();
if (array == NULL) {
rv = ENOMEM;
goto out;
}
pkgd = make_dict_from_pkg(pkgname, version, desc);
if (!xbps_add_obj_to_array(array, pkgd)) {
prop_object_release(array);
rv = EINVAL;
goto out;
}
prop_dictionary_set_bool(pkgd, "automatic-install",
automatic);
if (!xbps_add_obj_to_dict(dict, array, "packages")) {
prop_object_release(array);
rv = EINVAL;
goto out;
}
} else {
/*
* Check if package is already registered and return
* an error if not updating.
*/
pkgd = xbps_find_pkg_in_dict(dict, "packages", pkgname); pkgd = xbps_find_pkg_in_dict(dict, "packages", pkgname);
if (pkgd != NULL && update == false) { if (pkgd == NULL) {
rv = EEXIST;
goto out;
}
array = prop_dictionary_get(dict, "packages");
if (array == NULL) {
rv = ENOENT; rv = ENOENT;
goto out; goto out;
} }
prop_dictionary_set_cstring_nocopy(pkgd, "version", version);
newpkgd = make_dict_from_pkg(pkgname, version, desc); prop_dictionary_set_cstring_nocopy(pkgd, "short_desc", desc);
prop_dictionary_set_bool(newpkgd, "automatic-install", prop_dictionary_set_bool(pkgd, "automatic-install", automatic);
automatic);
/* /*
* Add the requiredby objects for dependent packages. * Add the requiredby objects for dependent packages.
*/ */
if (pkgrd && xbps_pkg_has_rundeps(pkgrd)) { if (pkgrd && xbps_pkg_has_rundeps(pkgrd)) {
array = prop_dictionary_get(dict, "packages");
if (array == NULL) {
prop_object_release(pkgd);
rv = ENOENT;
goto out;
}
rv = xbps_requiredby_pkg_add(array, pkgrd); rv = xbps_requiredby_pkg_add(array, pkgrd);
if (rv != 0) { if (rv != 0) {
prop_object_release(newpkgd); prop_object_release(pkgd);
goto out; goto out;
} }
} }
if (update) {
/* /*
* If updating a package, set new version in * Write plist file to storage.
* pkg dictionary.
*/ */
prop_dictionary_set_cstring_nocopy(pkgd,
"version", version);
} else {
/*
* If installing a package, add new pkg
* dictionary into the packages array.
*/
if (!xbps_add_obj_to_array(array, newpkgd)) {
prop_object_release(newpkgd);
rv = EINVAL;
goto out;
}
}
}
if (!prop_dictionary_externalize_to_file(dict, plist)) if (!prop_dictionary_externalize_to_file(dict, plist))
rv = errno; rv = errno;
} else {
free(plist);
return ENOENT;
}
out: out:
prop_object_release(dict); prop_object_release(dict);
free(plist); free(plist);

View file

@ -60,7 +60,7 @@ xbps_unregister_pkg(const char *pkgname)
} }
static int static int
xbps_remove_binary_pkg_meta(const char *pkgname) remove_pkg_metadir(const char *pkgname)
{ {
struct dirent *dp; struct dirent *dp;
DIR *dirp; DIR *dirp;
@ -271,7 +271,7 @@ dirs:
} }
int int
xbps_remove_binary_pkg(const char *pkgname, bool update) xbps_remove_pkg(const char *pkgname, const char *version, bool update)
{ {
prop_dictionary_t dict; prop_dictionary_t dict;
const char *rootdir = xbps_get_rootdir(); const char *rootdir = xbps_get_rootdir();
@ -280,6 +280,7 @@ xbps_remove_binary_pkg(const char *pkgname, bool update)
bool prepostf = false; bool prepostf = false;
assert(pkgname != NULL); assert(pkgname != NULL);
assert(version != NULL);
/* /*
* Check if pkg is installed before anything else. * Check if pkg is installed before anything else.
@ -287,9 +288,6 @@ xbps_remove_binary_pkg(const char *pkgname, bool update)
if (xbps_check_is_installed_pkgname(pkgname) == false) if (xbps_check_is_installed_pkgname(pkgname) == false)
return ENOENT; return ENOENT;
if (strcmp(rootdir, "") == 0)
rootdir = "/";
if (chdir(rootdir) == -1) if (chdir(rootdir) == -1)
return errno; return errno;
@ -306,7 +304,8 @@ xbps_remove_binary_pkg(const char *pkgname, bool update)
* Run the pre remove action. * Run the pre remove action.
*/ */
prepostf = true; prepostf = true;
rv = xbps_file_chdir_exec(rootdir, buf, "pre", pkgname, NULL); rv = xbps_file_chdir_exec(rootdir, buf, "pre", pkgname,
version, NULL);
if (rv != 0) { if (rv != 0) {
printf("%s: prerm action target error (%s)\n", pkgname, printf("%s: prerm action target error (%s)\n", pkgname,
strerror(errno)); strerror(errno));
@ -317,10 +316,10 @@ xbps_remove_binary_pkg(const char *pkgname, bool update)
/* /*
* Iterate over the pkg file list dictionary and remove all * Iterate over the pkg file list dictionary and remove all
* files/dirs associated. * files, configuration files, links and dirs.
*/ */
path = xbps_xasprintf("%s/%s/metadata/%s/files.plist", path = xbps_xasprintf("%s/%s/metadata/%s/%s",
rootdir, XBPS_META_PATH, pkgname); rootdir, XBPS_META_PATH, pkgname, XBPS_PKGFILES);
if (path == NULL) { if (path == NULL) {
free(buf); free(buf);
return errno; return errno;
@ -343,11 +342,12 @@ xbps_remove_binary_pkg(const char *pkgname, bool update)
prop_object_release(dict); prop_object_release(dict);
/* /*
* Run the post remove action if REMOVE file is there. * Run the post remove action if REMOVE file is there
* and we aren't updating a package.
*/ */
if (prepostf) { if (update == false && prepostf) {
if ((rv = xbps_file_chdir_exec(rootdir, buf, "post", if ((rv = xbps_file_chdir_exec(rootdir, buf, "post",
pkgname, NULL)) != 0) { pkgname, version, NULL)) != 0) {
printf("%s: postrm action target error (%s)\n", printf("%s: postrm action target error (%s)\n",
pkgname, strerror(errno)); pkgname, strerror(errno));
free(buf); free(buf);
@ -365,16 +365,17 @@ xbps_remove_binary_pkg(const char *pkgname, bool update)
if (update == false) { if (update == false) {
/* /*
* Unregister pkg from database only if it's a removal * Unregister pkg from database.
* and not an update.
*/ */
rv = xbps_unregister_pkg(pkgname); rv = xbps_unregister_pkg(pkgname);
if (rv != 0) if (rv != 0)
return rv; return rv;
}
/* /*
* Remove pkg metadata directory. * Remove pkg metadata directory.
*/ */
return xbps_remove_binary_pkg_meta(pkgname); return remove_pkg_metadir(pkgname);
}
return 0;
} }

235
lib/state.c Normal file
View file

@ -0,0 +1,235 @@
/*-
* Copyright (c) 2009 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 <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
#include <unistd.h>
#include <fcntl.h>
#include <xbps_api.h>
static int
set_new_state(prop_dictionary_t dict, pkg_state_t state)
{
const char *state_str;
assert(dict != NULL);
switch (state) {
case XBPS_PKG_STATE_UNPACKED:
state_str = "unpacked";
break;
case XBPS_PKG_STATE_INSTALLED:
state_str = "installed";
break;
case XBPS_PKG_STATE_BROKEN:
state_str = "broken";
break;
case XBPS_PKG_STATE_CONFIG_FILES:
state_str = "config-files";
break;
case XBPS_PKG_STATE_NOT_INSTALLED:
state_str = "not-installed";
break;
default:
return -1;
}
if (!prop_dictionary_set_cstring_nocopy(dict, "state", state_str))
return -1;
return 0;
}
static pkg_state_t
get_state(prop_dictionary_t dict)
{
const char *state_str;
pkg_state_t state = 0;
assert(dict != NULL);
prop_dictionary_get_cstring_nocopy(dict, "state", &state_str);
if (state_str == NULL)
return 0;
if (strcmp(state_str, "unpacked") == 0)
state = XBPS_PKG_STATE_UNPACKED;
else if (strcmp(state_str, "installed") == 0)
state = XBPS_PKG_STATE_INSTALLED;
else if (strcmp(state_str, "broken") == 0)
state = XBPS_PKG_STATE_BROKEN;
else if (strcmp(state_str, "config-files") == 0)
state = XBPS_PKG_STATE_CONFIG_FILES;
else if (strcmp(state_str, "not-installed") == 0)
state = XBPS_PKG_STATE_NOT_INSTALLED;
else
return 0;
return state;
}
int
xbps_get_pkg_state_installed(const char *pkgname, pkg_state_t *state)
{
prop_dictionary_t dict, pkgd;
const char *rootdir;
char *plist;
assert(pkgname != NULL);
rootdir = xbps_get_rootdir();
plist = xbps_xasprintf("%s/%s/%s", rootdir,
XBPS_META_PATH, XBPS_REGPKGDB);
if (plist == NULL)
return errno;
dict = prop_dictionary_internalize_from_file(plist);
if (dict == NULL) {
free(plist);
return errno;
}
free(plist);
pkgd = xbps_find_pkg_in_dict(dict, "packages", pkgname);
if (pkgd == NULL) {
prop_object_release(dict);
return ENOENT;
}
*state = get_state(pkgd);
if (*state == 0) {
prop_object_release(dict);
return EINVAL;
}
prop_object_release(dict);
return 0;
}
int
xbps_get_pkg_state_dictionary(prop_dictionary_t dict, pkg_state_t *state)
{
assert(dict != NULL);
if ((*state = get_state(dict)) == 0)
return EINVAL;
return 0;
}
int
xbps_set_pkg_state_dictionary(prop_dictionary_t dict, pkg_state_t state)
{
assert(dict != NULL);
return set_new_state(dict, state);
}
int
xbps_set_pkg_state_installed(const char *pkgname, pkg_state_t state)
{
prop_dictionary_t dict, pkgd;
prop_array_t array;
const char *rootdir;
char *plist;
int rv = 0;
bool newpkg = false;
rootdir = xbps_get_rootdir();
plist = xbps_xasprintf("%s/%s/%s", rootdir,
XBPS_META_PATH, XBPS_REGPKGDB);
if (plist == NULL)
return EINVAL;
dict = prop_dictionary_internalize_from_file(plist);
if (dict == NULL) {
dict = prop_dictionary_create();
if (dict == NULL) {
free(plist);
return ENOMEM;
}
array = prop_array_create();
if (array == NULL) {
rv = ENOMEM;
goto out;
}
pkgd = prop_dictionary_create();
if (pkgd == NULL) {
prop_object_release(array);
rv = errno;
goto out;
}
prop_dictionary_set_cstring_nocopy(pkgd, "pkgname", pkgname);
if ((rv = set_new_state(pkgd, state)) != 0) {
prop_object_release(array);
goto out;
}
if (!xbps_add_obj_to_array(array, pkgd)) {
prop_object_release(array);
rv = EINVAL;
goto out;
}
if (!xbps_add_obj_to_dict(dict, array, "packages")) {
prop_object_release(array);
rv = EINVAL;
goto out;
}
} else {
pkgd = xbps_find_pkg_in_dict(dict, "packages", pkgname);
if (pkgd == NULL) {
newpkg = true;
pkgd = prop_dictionary_create();
prop_dictionary_set_cstring_nocopy(pkgd, "pkgname",
pkgname);
}
array = prop_dictionary_get(dict, "packages");
if (array == NULL) {
rv = ENOENT;
goto out;
}
if ((rv = set_new_state(pkgd, state)) != 0) {
prop_object_release(pkgd);
goto out;
}
if (newpkg && !xbps_add_obj_to_array(array, pkgd)) {
prop_object_release(pkgd);
rv = EINVAL;
goto out;
}
}
if (!prop_dictionary_externalize_to_file(dict, plist))
rv = errno;
out:
prop_object_release(dict);
free(plist);
return rv;
}

View file

@ -35,13 +35,14 @@
#include <xbps_api.h> #include <xbps_api.h>
static int unpack_archive_fini(struct archive *, prop_dictionary_t); static int unpack_archive_fini(struct archive *, prop_dictionary_t, bool);
int int
xbps_unpack_binary_pkg(prop_dictionary_t pkg) xbps_unpack_binary_pkg(prop_dictionary_t pkg, bool essential)
{ {
prop_string_t filename, repoloc, arch; prop_string_t filename, repoloc, arch;
struct archive *ar; struct archive *ar;
const char *pkgname;
char *binfile; char *binfile;
int pkg_fd, rv = 0; int pkg_fd, rv = 0;
@ -50,6 +51,7 @@ xbps_unpack_binary_pkg(prop_dictionary_t pkg)
/* /*
* Append filename to the full path for binary pkg. * Append filename to the full path for binary pkg.
*/ */
prop_dictionary_get_cstring_nocopy(pkg, "pkgname", &pkgname);
filename = prop_dictionary_get(pkg, "filename"); filename = prop_dictionary_get(pkg, "filename");
arch = prop_dictionary_get(pkg, "architecture"); arch = prop_dictionary_get(pkg, "architecture");
repoloc = prop_dictionary_get(pkg, "repository"); repoloc = prop_dictionary_get(pkg, "repository");
@ -74,7 +76,9 @@ xbps_unpack_binary_pkg(prop_dictionary_t pkg)
goto out2; goto out2;
} }
/* Enable support for tar format and all compression methods */ /*
* Enable support for tar format and all compression methods.
*/
archive_read_support_compression_all(ar); archive_read_support_compression_all(ar);
archive_read_support_format_tar(ar); archive_read_support_format_tar(ar);
@ -82,15 +86,14 @@ xbps_unpack_binary_pkg(prop_dictionary_t pkg)
ARCHIVE_READ_BLOCKSIZE)) != 0) ARCHIVE_READ_BLOCKSIZE)) != 0)
goto out3; goto out3;
rv = unpack_archive_fini(ar, pkg); rv = unpack_archive_fini(ar, pkg, essential);
/* /*
* If installation of package was successful, make sure the package * If installation of package was successful, make sure the package
* is really on storage (if possible). * is really on storage (if possible).
*/ */
if (rv == 0) if (rv == 0)
if (fsync(pkg_fd) == -1) if (fdatasync(pkg_fd) == -1)
rv = errno; rv = errno;
out3: out3:
archive_read_finish(ar); archive_read_finish(ar);
out2: out2:
@ -98,31 +101,39 @@ out2:
out: out:
free(binfile); free(binfile);
if (rv == 0) {
/*
* Set package state to unpacked.
*/
rv = xbps_set_pkg_state_installed(pkgname,
XBPS_PKG_STATE_UNPACKED);
}
return rv; return rv;
} }
/* /*
* Flags for extracting files in binary packages. * Flags for extracting files in binary packages. If a package
* is marked as "essential", its files will be overwritten and then
* the old and new dictionaries are compared to find out if there
* are some files that were in the old package that should be removed.
*/ */
#define EXTRACT_FLAGS ARCHIVE_EXTRACT_SECURE_NODOTDOT | \ #define EXTRACT_FLAGS ARCHIVE_EXTRACT_SECURE_NODOTDOT | \
ARCHIVE_EXTRACT_SECURE_SYMLINKS | \ ARCHIVE_EXTRACT_SECURE_SYMLINKS
ARCHIVE_EXTRACT_NO_OVERWRITE | \
ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER
#define FEXTRACT_FLAGS ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_PERM | \ #define FEXTRACT_FLAGS ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_PERM | \
ARCHIVE_EXTRACT_TIME | EXTRACT_FLAGS ARCHIVE_EXTRACT_TIME | EXTRACT_FLAGS
/* /*
* TODO: remove printfs and return appropiate errors to be interpreted by * TODO: remove printfs and return appropiate errors to be interpreted by
* the consumer. * the consumer.
*/ */
static int static int
unpack_archive_fini(struct archive *ar, prop_dictionary_t pkg) unpack_archive_fini(struct archive *ar, prop_dictionary_t pkg,
bool essential)
{ {
struct archive_entry *entry; struct archive_entry *entry;
const char *prepost = "./INSTALL";
const char *pkgname, *version, *rootdir; const char *pkgname, *version, *rootdir;
char *buf; char *buf, *buf2;
int rv = 0, flags = 0, lflags = 0; int rv = 0, flags, lflags;
bool actgt = false; bool actgt = false;
assert(ar != NULL); assert(ar != NULL);
@ -130,6 +141,10 @@ unpack_archive_fini(struct archive *ar, prop_dictionary_t pkg)
rootdir = xbps_get_rootdir(); rootdir = xbps_get_rootdir();
flags = xbps_get_flags(); flags = xbps_get_flags();
/*
* First we change to the destination directory or / if
* not specified.
*/
if (strcmp(rootdir, "") == 0) if (strcmp(rootdir, "") == 0)
rootdir = "/"; rootdir = "/";
@ -144,38 +159,72 @@ unpack_archive_fini(struct archive *ar, prop_dictionary_t pkg)
else else
lflags = EXTRACT_FLAGS; lflags = EXTRACT_FLAGS;
if (essential == false) {
lflags |= ARCHIVE_EXTRACT_NO_OVERWRITE;
lflags |= ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER;
}
while (archive_read_next_header(ar, &entry) == ARCHIVE_OK) {
/*
* Run the pre INSTALL action if the file is there.
*/
if (strcmp("./INSTALL", archive_entry_pathname(entry)) == 0) {
buf = xbps_xasprintf(".%s/metadata/%s/INSTALL", buf = xbps_xasprintf(".%s/metadata/%s/INSTALL",
XBPS_META_PATH, pkgname); XBPS_META_PATH, pkgname);
if (buf == NULL) if (buf == NULL)
return errno; return errno;
while (archive_read_next_header(ar, &entry) == ARCHIVE_OK) {
/*
* Run the pre installation action target if there's a script
* before writing data to disk.
*/
if (strcmp(prepost, archive_entry_pathname(entry)) == 0) {
actgt = true; actgt = true;
printf("\n");
(void)fflush(stdout);
archive_entry_set_pathname(entry, buf); archive_entry_set_pathname(entry, buf);
if (archive_read_extract(ar, entry, lflags) != 0) { if (archive_read_extract(ar, entry, lflags) != 0) {
if ((rv = archive_errno(ar)) != EEXIST) if ((rv = archive_errno(ar)) != EEXIST) {
break; free(buf);
return rv;
}
} }
if ((rv = xbps_file_chdir_exec(rootdir, buf, "pre", if ((rv = xbps_file_chdir_exec(rootdir, buf, "pre",
pkgname, version, NULL)) != 0) { pkgname, version, NULL)) != 0) {
free(buf);
printf("%s: preinst action target error %s\n", printf("%s: preinst action target error %s\n",
pkgname, strerror(errno)); pkgname, strerror(errno));
(void)fflush(stdout); return rv;
break;
} }
/* pass to the next entry if successful */ /* pass to the next entry if successful */
free(buf);
continue; continue;
/*
* Unpack metadata files (REMOVE, files.plist and props.plist)
* into the proper path.
*/
} else if (strcmp("./REMOVE",
archive_entry_pathname(entry)) == 0) {
buf2 = xbps_xasprintf(".%s/metadata/%s/REMOVE",
XBPS_META_PATH, pkgname);
if (buf2 == NULL)
return errno;
archive_entry_set_pathname(entry, buf2);
free(buf2);
buf2 = NULL;
} else if (strcmp("./files.plist",
archive_entry_pathname(entry)) == 0) {
buf2 = xbps_xasprintf(".%s/metadata/%s/files.plist",
XBPS_META_PATH, pkgname);
if (buf2 == NULL)
return errno;
archive_entry_set_pathname(entry, buf2);
free(buf2);
buf2 = NULL;
} else if (strcmp("./props.plist",
archive_entry_pathname(entry)) == 0) {
buf2 = xbps_xasprintf(".%s/metadata/%s/props.plist",
XBPS_META_PATH, pkgname);
if (buf2 == NULL)
return errno;
archive_entry_set_pathname(entry, buf2);
free(buf2);
} }
/* /*
* Extract all data from the archive now. * Extract all data from the archive now.
@ -185,14 +234,12 @@ unpack_archive_fini(struct archive *ar, prop_dictionary_t pkg)
if (rv != EEXIST) { if (rv != EEXIST) {
printf("ERROR: %s...exiting!\n", printf("ERROR: %s...exiting!\n",
archive_error_string(ar)); archive_error_string(ar));
(void)fflush(stdout); return rv;;
break;
} else if (rv == EEXIST) { } else if (rv == EEXIST) {
if (flags & XBPS_VERBOSE) { if (flags & XBPS_VERBOSE) {
printf("WARNING: ignoring existent " printf("WARNING: ignoring existent "
"path: %s\n", "path: %s\n",
archive_entry_pathname(entry)); archive_entry_pathname(entry));
(void)fflush(stdout);
} }
rv = 0; rv = 0;
continue; continue;
@ -204,20 +251,5 @@ unpack_archive_fini(struct archive *ar, prop_dictionary_t pkg)
} }
} }
if (rv == 0 && actgt) {
/*
* Run the post installaction action target, if package
* contains the script.
*/
if ((rv = xbps_file_chdir_exec(rootdir, buf, "post",
pkgname, version, NULL)) != 0) {
printf("%s: postinst action target error %s\n",
pkgname, strerror(errno));
(void)fflush(stdout);
}
}
free(buf);
return rv; return rv;
} }

View file

@ -116,6 +116,7 @@ xbps_check_is_installed_pkg(const char *pkg)
const char *reqver, *instver; const char *reqver, *instver;
char *pkgname; char *pkgname;
int rv = 0; int rv = 0;
pkg_state_t state = 0;
assert(pkg != NULL); assert(pkg != NULL);
@ -125,16 +126,28 @@ xbps_check_is_installed_pkg(const char *pkg)
dict = xbps_find_pkg_installed_from_plist(pkgname); dict = xbps_find_pkg_installed_from_plist(pkgname);
if (dict == NULL) { if (dict == NULL) {
free(pkgname); free(pkgname);
return -2; /* not installed */ return -1; /* not installed */
} }
/*
* Check that package state is fully installed, not
* unpacked or something else.
*/
if (xbps_get_pkg_state_installed(pkgname, &state) != 0) {
free(pkgname);
return -1;
}
free(pkgname);
if (state != XBPS_PKG_STATE_INSTALLED)
return -1;
/* Get version from installed package */ /* Get version from installed package */
prop_dictionary_get_cstring_nocopy(dict, "version", &instver); prop_dictionary_get_cstring_nocopy(dict, "version", &instver);
/* Compare installed and required version. */ /* Compare installed and required version. */
rv = xbps_cmpver(instver, reqver); rv = xbps_cmpver(instver, reqver);
free(pkgname);
prop_object_release(dict); prop_object_release(dict);
return rv; return rv;

View file

@ -51,6 +51,7 @@ xbps_make_binpkg()
xbps_make_binpkg_real() xbps_make_binpkg_real()
{ {
local binpkg pkgdir arch use_sudo lver local binpkg pkgdir arch use_sudo lver
local tar_flags="cfp"
if [ ! -d ${DESTDIR} ]; then if [ ! -d ${DESTDIR} ]; then
echo "$pkgname: unexistent destdir... skipping!" echo "$pkgname: unexistent destdir... skipping!"
@ -79,25 +80,39 @@ xbps_make_binpkg_real()
binpkg=$pkgname-$lver.$arch.xbps binpkg=$pkgname-$lver.$arch.xbps
pkgdir=$XBPS_PACKAGESDIR/$arch pkgdir=$XBPS_PACKAGESDIR/$arch
if [ -x ./INSTALL ]; then
# #
# Make sure that INSTALL is the first file on the archive, # Make sure that INSTALL is the first file on the archive,
# this is to ensure that it's run before any other file is # this is to ensure that it's run before any other file is
# unpacked. # unpacked.
# #
run_rootcmd $use_sudo tar cfp \ if [ -x ./INSTALL ]; then
$XBPS_BUILDDIR/$binpkg ./INSTALL && \ run_rootcmd $use_sudo tar $tar_flags \
run_rootcmd $use_sudo tar rfp $XBPS_BUILDDIR/$binpkg . \ $XBPS_BUILDDIR/$binpkg ./INSTALL
--exclude "./INSTALL" \ [ $? -ne 0 ] && msg_error "Failed to add INSTALL script."
--exclude "./var/db/xbps/metadata/*/flist" && \
bzip2 -9 $XBPS_BUILDDIR/$binpkg && \
mv $XBPS_BUILDDIR/$binpkg.bz2 $XBPS_BUILDDIR/$binpkg
else
run_rootcmd $use_sudo tar cfp $XBPS_BUILDDIR/$binpkg . \
--exclude "./var/db/xbps/metadata/*/flist" && \
bzip2 -9 $XBPS_BUILDDIR/$binpkg && \
mv $XBPS_BUILDDIR/$binpkg.bz2 $XBPS_BUILDDIR/$binpkg
fi fi
if [ -x ./REMOVE ]; then
if [ -x ./INSTALL ]; then
tar_flags="rfp"
fi
run_rootcmd $use_sudo tar $tar_flags \
$XBPS_BUILDDIR/$binpkg ./REMOVE
[ $? -ne 0 ] && msg_error "Failed to add REMOVE script."
fi
if [ -x ./INSTALL -o -x ./REMOVE ]; then
tar_flags="rfp"
elif [ ! -x ./INSTALL -o ! -x ./REMOVE ]; then
tar_flags="cfp"
fi
run_rootcmd $use_sudo tar $tar_flags $XBPS_BUILDDIR/$binpkg \
./files.plist ./props.plist
[ $? -ne 0 ] && msg_error "Failed to add metadata files."
run_rootcmd $use_sudo tar rfp $XBPS_BUILDDIR/$binpkg . \
--exclude "./INSTALL" --exclude "./REMOVE" \
--exclude "./files.plist" --exclude "./props.plist" \
--exclude "./var/db/xbps/metadata/*/flist" && \
bzip2 -9 $XBPS_BUILDDIR/$binpkg && \
mv $XBPS_BUILDDIR/$binpkg.bz2 $XBPS_BUILDDIR/$binpkg
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
[ ! -d $pkgdir ] && mkdir -p $pkgdir [ ! -d $pkgdir ] && mkdir -p $pkgdir
mv -f $XBPS_BUILDDIR/$binpkg $pkgdir mv -f $XBPS_BUILDDIR/$binpkg $pkgdir

View file

@ -346,12 +346,12 @@ _EOF
else else
rm -f $TMPFLIST rm -f $TMPFLIST
fi fi
mv -f $TMPFPLIST $metadir/files.plist mv -f $TMPFPLIST ${DESTDIR}/files.plist
mv -f $TMPFPROPS $metadir/props.plist mv -f $TMPFPROPS ${DESTDIR}/props.plist
$XBPS_REGPKGDB_CMD sanitize-plist $metadir/files.plist $XBPS_REGPKGDB_CMD sanitize-plist ${DESTDIR}/files.plist
$XBPS_REGPKGDB_CMD sanitize-plist $metadir/props.plist $XBPS_REGPKGDB_CMD sanitize-plist ${DESTDIR}/props.plist
chmod 644 $metadir/* chmod 644 ${DESTDIR}/files.plist ${DESTDIR}/props.plist
# #
# Update desktop-file-utils database if package contains # Update desktop-file-utils database if package contains

View file

@ -26,7 +26,6 @@
xbps_write_metadata_scripts_pkg() xbps_write_metadata_scripts_pkg()
{ {
local action="$1" local action="$1"
local metadir="${DESTDIR}/var/db/xbps/metadata/$pkgname"
local tmpf=$(mktemp -t xbps-install.XXXXXXXXXX) || exit 1 local tmpf=$(mktemp -t xbps-install.XXXXXXXXXX) || exit 1
local fpattern="s|${DESTDIR}||g;s|^\./$||g;/^$/d" local fpattern="s|${DESTDIR}||g;s|^\./$||g;/^$/d"
local targets found info_files local targets found info_files
@ -217,7 +216,7 @@ _EOF
rm -f $tmpf rm -f $tmpf
return 0 return 0
fi fi
mv $tmpf ${metadir}/REMOVE && chmod 755 ${metadir}/REMOVE mv $tmpf ${DESTDIR}/REMOVE && chmod 755 ${DESTDIR}/REMOVE
;; ;;
esac esac
} }