Merged `progress_callback' branch.

This commit is contained in:
Juan RP 2011-01-24 14:48:20 +01:00
commit 887c3e4974
30 changed files with 945 additions and 561 deletions

6
NEWS
View File

@ -1,5 +1,11 @@
xbps-0.8.0 (???): xbps-0.8.0 (???):
* Merged the `progress_callback' branch that makes possible to specify a
function callback to update progress while unpacking binary packages
and while fetching files. xbps-bin(8) now reports a percentage while
unpacking package files if -v not set, otherwise it will list the
current extracted file with its size in bytes.
* Improved package dependency resolution in repositories by using a new * Improved package dependency resolution in repositories by using a new
function, xbps_repository_pool_find_pkg() that returns a package dictionary function, xbps_repository_pool_find_pkg() that returns a package dictionary
found in the first repository registered in the pool. It can also be used found in the first repository registered in the pool. It can also be used

View File

@ -1,9 +1,9 @@
-include ../config.mk -include ../config.mk
SUBDIRS = xbps-uhelper SUBDIRS = xbps-bin
SUBDIRS += xbps-repo SUBDIRS += xbps-repo
SUBDIRS += xbps-bin
SUBDIRS += xbps-dgraph SUBDIRS += xbps-dgraph
SUBDIRS += xbps-uhelper
.PHONY: all .PHONY: all
all: all:

View File

@ -3,8 +3,8 @@ TOPDIR = ../..
BIN = xbps-bin BIN = xbps-bin
OBJS = check.o install.o main.o remove.o show-deps.o OBJS = check.o install.o main.o remove.o show-deps.o
OBJS += show-info-files.o ../xbps-repo/util.o find-files.o OBJS += show-info-files.o util.o find-files.o
OBJS += question.o OBJS += question.o fetch.o
MAN = $(BIN).8 MAN = $(BIN).8
include $(TOPDIR)/prog.mk include $(TOPDIR)/prog.mk

View File

@ -30,6 +30,8 @@
#define __UNCONST(a) ((void *)(unsigned long)(const void *)(a)) #define __UNCONST(a) ((void *)(unsigned long)(const void *)(a))
#endif #endif
#include <xbps_api.h>
int xbps_install_new_pkg(const char *); int xbps_install_new_pkg(const char *);
int xbps_update_pkg(const char *); int xbps_update_pkg(const char *);
int xbps_autoupdate_pkgs(bool); int xbps_autoupdate_pkgs(bool);
@ -43,7 +45,22 @@ int xbps_show_pkg_reverse_deps(const char *);
int show_pkg_info_from_metadir(const char *); int show_pkg_info_from_metadir(const char *);
int show_pkg_files_from_metadir(const char *); int show_pkg_files_from_metadir(const char *);
int find_files_in_packages(const char *); int find_files_in_packages(const char *);
/* from question.c */
bool xbps_yesno(const char *, ...); bool xbps_yesno(const char *, ...);
bool xbps_noyes(const char *, ...); bool xbps_noyes(const char *, ...);
/* from fetch.c */
void fetch_file_progress_cb(void *);
/* From util.c */
int show_pkg_files(prop_dictionary_t);
void show_pkg_info(prop_dictionary_t);
void show_pkg_info_only_repo(prop_dictionary_t);
int show_pkg_namedesc(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 *);
size_t find_longest_pkgver(prop_dictionary_t);
void print_package_line(const char *);
#endif /* !_XBPS_BIN_DEFS_H_ */ #endif /* !_XBPS_BIN_DEFS_H_ */

187
bin/xbps-bin/fetch.c Normal file
View File

@ -0,0 +1,187 @@
/*-
* Copyright (c) 2009-2011 Juan Romero Pardines
* Copyright (c) 2000-2004 Dag-Erling Coïdan Smørgrav
* 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
* in this position and unchanged.
* 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.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* 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.
*
* From FreeBSD fetch(8):
* $FreeBSD: src/usr.bin/fetch/fetch.c,v 1.84.2.1 2009/08/03 08:13:06 kensmith Exp $
*/
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <xbps_api.h>
#include "defs.h"
struct xferstat {
struct timeval start;
struct timeval last;
};
/*
* Compute and display ETA
*/
static const char *
stat_eta(struct xbps_fetch_progress_data *xfpd, struct xferstat *xsp)
{
static char str[16];
long elapsed, eta;
off_t received, expected;
elapsed = xsp->last.tv_sec - xsp->start.tv_sec;
received = xfpd->file_dloaded - xfpd->file_offset;
expected = xfpd->file_size - xfpd->file_dloaded;
eta = (long)(elapsed * expected / received);
if (eta > 3600)
snprintf(str, sizeof str, "%02ldh%02ldm",
eta / 3600, (eta % 3600) / 60);
else
snprintf(str, sizeof str, "%02ldm%02lds",
eta / 60, eta % 60);
return str;
}
/** High precision double comparison
* \param[in] a The first double to compare
* \param[in] b The second double to compare
* \return true on equal within precison, false if not equal within defined precision.
*/
static inline bool
compare_double(const double a, const double b)
{
const double precision = 0.00001;
if ((a - precision) < b && (a + precision) > b)
return true;
else
return false;
}
/*
* Compute and display transfer rate
*/
static const char *
stat_bps(struct xbps_fetch_progress_data *xfpd, struct xferstat *xsp)
{
static char str[16];
char size[8];
double delta, bps;
delta = (xsp->last.tv_sec + (xsp->last.tv_usec / 1.e6))
- (xsp->start.tv_sec + (xsp->start.tv_usec / 1.e6));
if (compare_double(delta, 0.0001)) {
snprintf(str, sizeof str, "-- stalled --");
} else {
bps =
((double)(xfpd->file_dloaded - xfpd->file_offset) / delta);
(void)xbps_humanize_number(size, (int64_t)bps);
snprintf(str, sizeof str, "%s/s", size);
}
return str;
}
/*
* Update the stats display
*/
static void
stat_display(struct xbps_fetch_progress_data *xfpd, struct xferstat *xsp)
{
struct timeval now;
char totsize[8], recvsize[8];
gettimeofday(&now, NULL);
if (now.tv_sec <= xsp->last.tv_sec)
return;
xsp->last = now;
(void)xbps_humanize_number(totsize, (int64_t)xfpd->file_size);
(void)xbps_humanize_number(recvsize, (int64_t)xfpd->file_dloaded);
fprintf(stderr,"\r%s: %s [%d%% of %s]", xfpd->file_name, recvsize,
(int)((double)(100.0 *
(double)xfpd->file_dloaded) / (double)xfpd->file_size), totsize);
fprintf(stderr," %s", stat_bps(xfpd, xsp));
if (xfpd->file_size > 0 && xfpd->file_dloaded > 0 &&
xsp->last.tv_sec >= xsp->start.tv_sec + 10)
fprintf(stderr," ETA: %s", stat_eta(xfpd, xsp));
fprintf(stderr,"\033[K");
}
/*
* Initialize the transfer statistics
*/
static void
stat_start(struct xferstat *xsp)
{
gettimeofday(&xsp->start, NULL);
xsp->last.tv_sec = xsp->last.tv_usec = 0;
}
/*
* Update the transfer statistics
*/
static void
stat_update(struct xbps_fetch_progress_data *xfpd, struct xferstat *xsp)
{
xfpd->file_dloaded += xfpd->file_offset;
stat_display(xfpd, xsp);
}
/*
* Finalize the transfer statistics
*/
static void
stat_end(struct xbps_fetch_progress_data *xfpd, struct xferstat *xsp)
{
char size[8];
(void)xbps_humanize_number(size, (int64_t)xfpd->file_size);
fprintf(stderr,"\rDownloaded %s for %s [avg rate: %s]",
size, xfpd->file_name, stat_bps(xfpd, xsp));
fprintf(stderr,"\033[K\n");
}
void
fetch_file_progress_cb(void *data)
{
struct xbps_fetch_progress_data *xfpd = data;
static struct xferstat xs;
if (xfpd->cb_start)
stat_start(&xs);
else if (xfpd->cb_update)
stat_update(xfpd, &xs);
else if (xfpd->cb_end)
stat_end(xfpd, &xs);
}

View File

@ -1,5 +1,5 @@
/*- /*-
* Copyright (c) 2009-2010 Juan Romero Pardines. * Copyright (c) 2009-2011 Juan Romero Pardines.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -31,8 +31,10 @@
#include <ctype.h> #include <ctype.h>
#include <assert.h> #include <assert.h>
#include <unistd.h> #include <unistd.h>
#include <limits.h>
#include <xbps_api.h> #include <xbps_api.h>
#include "strlcpy.h"
#include "defs.h" #include "defs.h"
#include "../xbps-repo/defs.h" #include "../xbps-repo/defs.h"
@ -98,6 +100,7 @@ static int
download_package_list(prop_object_iterator_t iter) download_package_list(prop_object_iterator_t iter)
{ {
prop_object_t obj; prop_object_t obj;
struct xbps_fetch_progress_data xfpd;
const char *pkgver, *repoloc, *filename, *cachedir, *sha256; const char *pkgver, *repoloc, *filename, *cachedir, *sha256;
char *binfile; char *binfile;
int rv = 0; int rv = 0;
@ -143,7 +146,8 @@ again:
return errno; return errno;
} }
printf("Downloading %s binary package ...\n", pkgver); printf("Downloading %s binary package ...\n", pkgver);
rv = xbps_fetch_file(binfile, cachedir, false, NULL); rv = xbps_fetch_file(binfile, cachedir, false, NULL,
fetch_file_progress_cb, &xfpd);
if (rv == -1) { if (rv == -1) {
fprintf(stderr, "xbps-bin: couldn't download `%s'\n", fprintf(stderr, "xbps-bin: couldn't download `%s'\n",
filename); filename);
@ -421,14 +425,48 @@ replace_packages(prop_dictionary_t trans_dict, prop_dictionary_t pkgd,
return 0; return 0;
} }
static void
unpack_progress_cb_verbose(void *data)
{
struct xbps_unpack_progress_data *xpd = data;
if (xpd->entry == NULL || xpd->entry_is_metadata)
return;
else if (xpd->entry_size <= 0)
return;
fprintf(stderr, "Extracted %sfile `%s' (%" PRIi64 " bytes)\n",
xpd->entry_is_conf ? "configuration " : "", xpd->entry,
xpd->entry_size);
}
static void
unpack_progress_cb_percentage(void *data)
{
struct xbps_unpack_progress_data *xpd = data;
double percent = 0;
if (xpd->entry_is_metadata)
return;
percent =
(double)((xpd->entry_extract_count * 100.0) / xpd->entry_total_count);
if (percent > 100.0 ||
xpd->entry_extract_count >= xpd->entry_total_count)
percent = 100.0;
printf("\033[s(%3.2f%%)\033[u", percent);
}
static int static int
exec_transaction(struct transaction *trans) exec_transaction(struct transaction *trans)
{ {
prop_dictionary_t instpkgd; prop_dictionary_t instpkgd;
prop_object_t obj; prop_object_t obj;
prop_object_iterator_t replaces_iter; prop_object_iterator_t replaces_iter;
const char *pkgname, *version, *pkgver, *instver, *filename, *tract; struct xbps_unpack_progress_data xpd;
int rv = 0; const char *pkgname, *version, *pkgver, *instver, *filen, *tract;
int flags = xbps_get_flags(), rv = 0;
bool update, preserve, autoinst; bool update, preserve, autoinst;
pkg_state_t state = 0; pkg_state_t state = 0;
@ -470,13 +508,13 @@ exec_transaction(struct transaction *trans)
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);
prop_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver); prop_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver);
prop_dictionary_get_cstring_nocopy(obj, "filename", &filename); prop_dictionary_get_cstring_nocopy(obj, "filename", &filen);
prop_dictionary_get_cstring_nocopy(obj, "trans-action", &tract); prop_dictionary_get_cstring_nocopy(obj, "trans-action", &tract);
assert(pkgname != NULL); assert(pkgname != NULL);
assert(version != NULL); assert(version != NULL);
assert(pkgver != NULL); assert(pkgver != NULL);
assert(filename != NULL); assert(filen != NULL);
assert(tract != NULL); assert(tract != NULL);
prop_dictionary_get_bool(obj, "automatic-install", &autoinst); prop_dictionary_get_bool(obj, "automatic-install", &autoinst);
@ -536,12 +574,24 @@ exec_transaction(struct transaction *trans)
/* /*
* Unpack binary package. * Unpack binary package.
*/ */
printf("Unpacking %s (from .../%s) ...\n", pkgver, filename); printf("Unpacking `%s' (from ../%s) ... ", pkgver, filen);
if ((rv = xbps_unpack_binary_pkg(obj)) != 0) {
if (flags & XBPS_FLAG_VERBOSE) {
rv = xbps_unpack_binary_pkg(obj,
unpack_progress_cb_verbose, &xpd);
printf("\n");
} else {
rv = xbps_unpack_binary_pkg(obj,
unpack_progress_cb_percentage, &xpd);
}
if (rv != 0) {
fprintf(stderr, "xbps-bin: error unpacking %s " fprintf(stderr, "xbps-bin: error unpacking %s "
"(%s)\n", pkgver, strerror(rv)); "(%s)\n", pkgver, strerror(rv));
return rv; return rv;
} }
if ((flags & XBPS_FLAG_VERBOSE) == 0)
printf("\n");
/* /*
* Register binary package. * Register binary package.
*/ */

View File

@ -41,7 +41,7 @@ pkg_remove_and_purge(const char *pkgname, const char *version, bool purge)
printf("Removing package %s-%s ...\n", pkgname, version); printf("Removing package %s-%s ...\n", pkgname, version);
if ((rv = xbps_remove_pkg(pkgname, version, false)) != 0) { if ((rv = xbps_remove_pkg(pkgname, version, false)) != 0) {
fprintf(stderr, "\nE: unable to remove %s-%s (%s).\n", xbps_error_printf("unable to remove %s-%s (%s).\n",
pkgname, version, strerror(errno)); pkgname, version, strerror(errno));
return rv; return rv;
} }
@ -49,7 +49,7 @@ pkg_remove_and_purge(const char *pkgname, const char *version, bool purge)
printf(" Purging ... "); printf(" Purging ... ");
(void)fflush(stdout); (void)fflush(stdout);
if ((rv = xbps_purge_pkg(pkgname, false)) != 0) { if ((rv = xbps_purge_pkg(pkgname, false)) != 0) {
fprintf(stderr, "\nE: unable to purge %s-%s " xbps_error_printf("unable to purge %s-%s "
"(%s).\n", pkgname, version, "(%s).\n", pkgname, version,
strerror(errno)); strerror(errno));
return rv; return rv;
@ -149,7 +149,7 @@ xbps_remove_installed_pkgs(int argc, char **argv, bool yes, bool purge,
found = true; found = true;
reqby = prop_dictionary_get(dict, "requiredby"); reqby = prop_dictionary_get(dict, "requiredby");
if (reqby != NULL && prop_array_count(reqby) > 0) { if (reqby != NULL && prop_array_count(reqby) > 0) {
printf("WARNING: %s IS REQUIRED BY %u PACKAGES!\n", xbps_warn_printf("%s IS REQUIRED BY %u PACKAGES!\n",
pkgver, prop_array_count(reqby)); pkgver, prop_array_count(reqby));
reqby_force = true; reqby_force = true;
} }
@ -184,7 +184,7 @@ xbps_remove_installed_pkgs(int argc, char **argv, bool yes, bool purge,
prop_object_release(sorted_pkgs); prop_object_release(sorted_pkgs);
return 0; return 0;
} else if (reqby_force && force_rm_with_deps) } else if (reqby_force && force_rm_with_deps)
printf("WARNING: Forcing removal! you've been alerted.\n"); xbps_warn_printf("Forcing removal! you've been alerted.\n");
for (x = 0; x < prop_array_count(sorted_pkgs); x++) { for (x = 0; x < prop_array_count(sorted_pkgs); x++) {
dict = prop_array_get(sorted_pkgs, x); dict = prop_array_get(sorted_pkgs, x);

View File

@ -34,6 +34,7 @@
#include <xbps_api.h> #include <xbps_api.h>
#include "strlcpy.h" #include "strlcpy.h"
#include "defs.h" #include "defs.h"
#include "../xbps-repo/defs.h"
void void
show_pkg_info_only_repo(prop_dictionary_t dict) show_pkg_info_only_repo(prop_dictionary_t dict)

View File

@ -2,7 +2,8 @@ TOPDIR = ../..
-include $(TOPDIR)/config.mk -include $(TOPDIR)/config.mk
BIN = xbps-repo BIN = xbps-repo
OBJS = main.o util.o index.o repository.o find-files.o OBJS = main.o index.o repository.o find-files.o
OBJS += ../xbps-bin/fetch.o ../xbps-bin/util.o
MAN = $(BIN).8 MAN = $(BIN).8
include $(TOPDIR)/prog.mk include $(TOPDIR)/prog.mk

View File

@ -38,15 +38,6 @@ int unregister_repository(const char *);
int show_pkg_info_from_repolist(const char *); int show_pkg_info_from_repolist(const char *);
int show_pkg_deps_from_repolist(const char *); int show_pkg_deps_from_repolist(const char *);
int repository_sync(void); int repository_sync(void);
/* From util.c */
int show_pkg_files(prop_dictionary_t);
void show_pkg_info(prop_dictionary_t);
void show_pkg_info_only_repo(prop_dictionary_t);
int show_pkg_namedesc(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 *);
size_t find_longest_pkgver(prop_dictionary_t);
void print_package_line(const char *);
/* From find-files.c */ /* From find-files.c */
int repo_find_files_in_packages(const char *); int repo_find_files_in_packages(const char *);

View File

@ -34,6 +34,7 @@
#include <xbps_api.h> #include <xbps_api.h>
#include "defs.h" #include "defs.h"
#include "../xbps-bin/defs.h"
static void __attribute__((noreturn)) static void __attribute__((noreturn))
usage(void) usage(void)

View File

@ -165,6 +165,7 @@ int
register_repository(const char *uri) register_repository(const char *uri)
{ {
struct repoinfo *rpi = NULL; struct repoinfo *rpi = NULL;
struct xbps_fetch_progress_data xfpd;
const char *idxstr = NULL; const char *idxstr = NULL;
char *metadir, *plist; char *metadir, *plist;
int rv = 0; int rv = 0;
@ -174,7 +175,8 @@ register_repository(const char *uri)
if (xbps_check_is_repo_string_remote(idxstr)) { if (xbps_check_is_repo_string_remote(idxstr)) {
printf("Fetching remote package index at %s...\n", idxstr); printf("Fetching remote package index at %s...\n", idxstr);
rv = xbps_repository_sync_pkg_index(idxstr); rv = xbps_repository_sync_pkg_index(idxstr,
fetch_file_progress_cb, &xfpd);
if (rv == -1) { if (rv == -1) {
fprintf(stderr, fprintf(stderr,
"E: could not fetch pkg index file: %s.\n", "E: could not fetch pkg index file: %s.\n",
@ -296,6 +298,7 @@ show_pkg_deps_from_repolist(const char *pkgname)
static int static int
repo_sync_pkg_index_cb(struct repository_pool_index *rpi, void *arg, bool *done) repo_sync_pkg_index_cb(struct repository_pool_index *rpi, void *arg, bool *done)
{ {
struct xbps_fetch_progress_data xfpd;
struct repoinfo *rp; struct repoinfo *rp;
char *plist; char *plist;
int rv = 0; int rv = 0;
@ -307,7 +310,8 @@ repo_sync_pkg_index_cb(struct repository_pool_index *rpi, void *arg, bool *done)
return 0; return 0;
printf("Syncing package index from: %s\n", rpi->rpi_uri); printf("Syncing package index from: %s\n", rpi->rpi_uri);
rv = xbps_repository_sync_pkg_index(rpi->rpi_uri); rv = xbps_repository_sync_pkg_index(rpi->rpi_uri,
fetch_file_progress_cb, &xfpd);
if (rv == -1) { if (rv == -1) {
fprintf(stderr, "E: returned: %s\n", xbps_fetch_error_string()); fprintf(stderr, "E: returned: %s\n", xbps_fetch_error_string());
return rv; return rv;

View File

@ -2,5 +2,6 @@ TOPDIR = ../..
-include $(TOPDIR)/config.mk -include $(TOPDIR)/config.mk
BIN = xbps-uhelper BIN = xbps-uhelper
OBJS = main.o ../xbps-bin/fetch.o
include $(TOPDIR)/prog.mk include $(TOPDIR)/prog.mk

View File

@ -33,6 +33,7 @@
#include <unistd.h> #include <unistd.h>
#include <xbps_api.h> #include <xbps_api.h>
#include "../xbps-bin/defs.h"
/* error messages in bold/red */ /* error messages in bold/red */
#define MSG_ERROR "\033[1m\033[31m" #define MSG_ERROR "\033[1m\033[31m"
@ -103,6 +104,7 @@ usage(void)
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
struct xbps_fetch_progress_data xfpd;
prop_dictionary_t dict; prop_dictionary_t dict;
const char *version; const char *version;
char *plist, *pkgname, *pkgver, *in_chroot_env, *hash; char *plist, *pkgname, *pkgver, *in_chroot_env, *hash;
@ -321,7 +323,8 @@ main(int argc, char **argv)
usage(); usage();
for (i = 1; i < argc; i++) { for (i = 1; i < argc; i++) {
rv = xbps_fetch_file(argv[i], ".", false, "v"); rv = xbps_fetch_file(argv[i], ".", false, "v",
fetch_file_progress_cb, &xfpd);
if (rv == -1) { if (rv == -1) {
printf("%s: %s\n", argv[1], printf("%s: %s\n", argv[1],
xbps_fetch_error_string()); xbps_fetch_error_string());

View File

@ -30,6 +30,8 @@
#include <stdio.h> #include <stdio.h>
#include <inttypes.h> #include <inttypes.h>
#include <archive.h>
#include <archive_entry.h>
#include <prop/proplib.h> #include <prop/proplib.h>
#ifdef __cplusplus #ifdef __cplusplus
@ -117,8 +119,11 @@
__BEGIN_DECLS __BEGIN_DECLS
void xbps_printf(const char *, ...);
void xbps_dbg_printf(const char *, ...); void xbps_dbg_printf(const char *, ...);
void xbps_dbg_printf_append(const char *, ...); void xbps_dbg_printf_append(const char *, ...);
void xbps_error_printf(const char *, ...);
void xbps_warn_printf(const char *, ...);
/** @addtogroup initend */ /** @addtogroup initend */
/*@{*/ /*@{*/
@ -191,6 +196,72 @@ int xbps_cmpver(const char *pkg1, const char *pkg2);
/** @addtogroup download */ /** @addtogroup download */
/*@{*/ /*@{*/
/**
* @struct xbps_fetch_progress_data xbps_api.h "xbps_api.h"
* @brief Structure to be passed to the fetch progress function callback.
*
* This structure is passed as argument to the fetch progress function
* callback and its members will be updated when there's any progress.
* All members marked as read-only in this struct are set internally by
* xbps_unpack_binary_pkg() and shouldn't be modified in the passed
* function callback.
*/
struct xbps_fetch_progress_data {
/**
* @var file_size
*
* Filename size for the file to be fetched (set internally,
* read only).
*/
off_t file_size;
/**
* @var file_offset
*
* Current offset for the filename being fetched (set internally,
* read only).
*/
off_t file_offset;
/**
* @var file_dloaded
*
* Bytes downloaded for the file being fetched (set internally).
*/
off_t file_dloaded;
/**
* @var file_name
*
* File name being fetched (set internally, read only).
*/
const char *file_name;
/**
* @var cb_start
*
* If true the function callback should be prepared to start
* the transfer progress (set internally, read only).
*/
bool cb_start;
/**
* var cb_update
*
* If true the function callback should be prepared to
* update the transfer progress (set internally, read only).
*/
bool cb_update;
/**
* var cb_end
*
* If true the function callback should be prepated to
* end the transfer progress (set internally, read only).
*/
bool cb_end;
/**
* @var cookie
*
* Pointer to private user data.
*/
void *cookie;
};
/** /**
* Download a file from a remote URL. * Download a file from a remote URL.
* *
@ -199,6 +270,10 @@ int xbps_cmpver(const char *pkg1, const char *pkg2);
* @param[in] refetch If true and local/remote size/mtime do not match, * @param[in] refetch If true and local/remote size/mtime do not match,
* fetch the file from scratch. * fetch the file from scratch.
* @param[in] flags Flags passed to libfetch's fetchXget(). * @param[in] flags Flags passed to libfetch's fetchXget().
* @param[in] progress_cb Pointer to a function callback to update the
* the fetch progress.
* @param[in] xfpd Pointer to a xbps_fetch_progress_data struct to be
* passed to the \a progress_cb callback as its argument.
* *
* @return -1 on error, 0 if not downloaded (because local/remote size/mtime * @return -1 on error, 0 if not downloaded (because local/remote size/mtime
* do not match) and 1 if downloaded successfully. * do not match) and 1 if downloaded successfully.
@ -206,7 +281,9 @@ int xbps_cmpver(const char *pkg1, const char *pkg2);
int xbps_fetch_file(const char *uri, int xbps_fetch_file(const char *uri,
const char *outputdir, const char *outputdir,
bool refetch, bool refetch,
const char *flags); const char *flags,
void (*progress_cb)(void *),
struct xbps_fetch_progress_data *xfpd);
/** /**
* Returns last error string reported by xbps_fetch_file(). * Returns last error string reported by xbps_fetch_file().
@ -217,19 +294,6 @@ const char *xbps_fetch_error_string(void);
/*@}*/ /*@}*/
int xbps_humanize_number(char *, int64_t);
/**
* @ingroup dircreate
*
* Creates a directory (and required components if necessary).
*
* @param[in] path Path for final directory.
* @param[in] mode Mode for final directory (0755 if not specified).
*
* @return 0 on success, -1 on error and errno set appropiately.
*/
int xbps_mkpath(char *path, mode_t mode);
/** /**
* @ingroup pkg_orphans * @ingroup pkg_orphans
@ -774,12 +838,18 @@ prop_dictionary_t
* by the \a uri argument (if necessary). * by the \a uri argument (if necessary).
* *
* @param[in] uri URI to a remote repository. * @param[in] uri URI to a remote repository.
* @param[in] progress_cb Pointer to a function callback to update the
* the fetch progress.
* @param[in] xfpd Pointer to a xbps_fetch_progress_data struct to be
* passed to the \a progress_cb callback as its argument.
* *
* @return -1 on error (errno is set appropiately), 0 if transfer was * @return -1 on error (errno is set appropiately), 0 if transfer was
* not necessary (local/remote size/mtime matched) or 1 if * not necessary (local/remote size/mtime matched) or 1 if
* downloaded successfully. * downloaded successfully.
*/ */
int xbps_repository_sync_pkg_index(const char *uri); int xbps_repository_sync_pkg_index(const char *uri,
void (*progress_cb)(void *),
struct xbps_fetch_progress_data *xfpd);
/*@}*/ /*@}*/
@ -857,21 +927,90 @@ int xbps_set_pkg_state_dictionary(prop_dictionary_t dict, pkg_state_t state);
/*@}*/ /*@}*/
/** @addtogroup unpack */
/*@{*/
/** /**
* @ingroup unpack * @struct xbps_unpack_progress_data xbps_api.h "xbps_api.h"
* @brief Structure to be passed to the unpacking progress function callback.
* *
* This structure is passed as argument to the unpack progress function
* callback and its members will be updated when there's any progress.
* All members in this struct are set internally by xbps_unpack_binary_pkg()
* and should be used in read-only mode in the function callback.
*/
struct xbps_unpack_progress_data {
/**
* @var entry
*
* Entry pathname string (set internally, read only).
*/
const char *entry;
/**
* @var entry_size
*
* Entry file size (set internally, read only).
*/
int64_t entry_size;
/**
* @var entry_extract_count
*
* Total number of extracted entries (set internally, read only).
*/
ssize_t entry_extract_count;
/**
* @var entry_total_count
*
* Total number of entries in package (set internally, read only).
*/
ssize_t entry_total_count;
/**
* @var entry_is_metadata
*
* If true "entry" is a package metadata file (set internally,
* read only).
*/
bool entry_is_metadata;
/**
* @var entry_is_conf
*
* If true "entry" is a configuration file (set internally,
* read only).
*/
bool entry_is_conf;
};
/**
* Unpacks a binary package into specified root directory. * Unpacks a binary package into specified root directory.
* *
* @param[in] trans_pkg_dict Package proplib dictionary as stored in the * @param[in] trans_pkg_dict Package proplib dictionary as stored in the
* \a packages array returned by the transaction dictionary. * \a packages array returned by the transaction dictionary.
* @param[in] progress_cb Pointer to a function callback to update progress data
* while extracting files in package (optional).
* @param[in] xupd Pointer to a struct xbps_unpack_progress_data to be passed to
* the function callback \a progress_cb.
* *
* @return 0 on success, otherwise an errno value. * @return 0 on success, otherwise an errno value.
*/ */
int xbps_unpack_binary_pkg(prop_dictionary_t trans_pkg_dict); int xbps_unpack_binary_pkg(prop_dictionary_t trans_pkg_dict,
void (*progress_cb)(void *),
struct xbps_unpack_progress_data *xupd);
/*@}*/
/** @addtogroup util */ /** @addtogroup util */
/*@{*/ /*@{*/
/**
* Creates a directory (and required components if necessary).
*
* @param[in] path Path for final directory.
* @param[in] mode Mode for final directory (0755 if not specified).
*
* @return 0 on success, -1 on error and errno set appropiately.
*/
int xbps_mkpath(char *path, mode_t mode);
/** /**
* Returns a string by concatenating its variable argument list * Returns a string by concatenating its variable argument list
* as specified by the format string \a fmt. * as specified by the format string \a fmt.
@ -1070,6 +1209,18 @@ void xbps_set_cachedir(const char *cachedir);
*/ */
const char *xbps_get_cachedir(void); const char *xbps_get_cachedir(void);
/**
* Converts the 64 bits signed number specified in \a bytes to
* a human parsable string buffer pointed to \a buf.
*
* @param[out] buf Buffer to store the resulting string. At least
* it should have space for 6 chars.
* @param[in] bytes 64 bits signed number to convert.
*
* @return A negative number is returned on error, 0 otherwise.
*/
int xbps_humanize_number(char *buf, int64_t bytes);
/** /**
* Sets the flag specified in \a flags for internal use. * Sets the flag specified in \a flags for internal use.
* *

View File

@ -47,146 +47,10 @@
/** /**
* @file lib/download.c * @file lib/download.c
* @brief Download routines * @brief Download routines
* @defgroup download Internal download functions * @defgroup download Download functions
* *
* These functions allow you to download files. * XBPS download related functions, frontend for NetBSD's libfetch.
*/ */
struct xferstat {
struct timeval start;
struct timeval last;
off_t size;
off_t offset;
off_t rcvd;
const char *name;
};
/*
* Compute and display ETA
*/
static const char *
stat_eta(struct xferstat *xsp)
{
static char str[16];
long elapsed, eta;
off_t received, expected;
elapsed = xsp->last.tv_sec - xsp->start.tv_sec;
received = xsp->rcvd - xsp->offset;
expected = xsp->size - xsp->rcvd;
eta = (long)(elapsed * expected / received);
if (eta > 3600)
snprintf(str, sizeof str, "%02ldh%02ldm",
eta / 3600, (eta % 3600) / 60);
else
snprintf(str, sizeof str, "%02ldm%02lds",
eta / 60, eta % 60);
return str;
}
/** High precision double comparison
* \param[in] a The first double to compare
* \param[in] b The second double to compare
* \return true on equal within precison, false if not equal within defined precision.
*/
static inline bool
compare_double(const double a, const double b)
{
const double precision = 0.00001;
if ((a - precision) < b && (a + precision) > b)
return true;
else
return false;
}
/*
* Compute and display transfer rate
*/
static const char *
stat_bps(struct xferstat *xsp)
{
static char str[16];
char size[8];
double delta, bps;
delta = (xsp->last.tv_sec + (xsp->last.tv_usec / 1.e6))
- (xsp->start.tv_sec + (xsp->start.tv_usec / 1.e6));
if (compare_double(delta, 0.0001)) {
snprintf(str, sizeof str, "-- stalled --");
} else {
bps = ((double)(xsp->rcvd - xsp->offset) / delta);
(void)xbps_humanize_number(size, (int64_t)bps);
snprintf(str, sizeof str, "%s/s", size);
}
return str;
}
/*
* Update the stats display
*/
static void
stat_display(struct xferstat *xsp)
{
struct timeval now;
char totsize[8], recvsize[8];
gettimeofday(&now, NULL);
if (now.tv_sec <= xsp->last.tv_sec)
return;
xsp->last = now;
(void)xbps_humanize_number(totsize, (int64_t)xsp->size);
(void)xbps_humanize_number(recvsize, (int64_t)xsp->rcvd);
fprintf(stderr, "\r%s: %s [%d%% of %s]",
xsp->name, recvsize,
(int)((double)(100.0 * (double)xsp->rcvd) / (double)xsp->size),
totsize);
fprintf(stderr, " %s", stat_bps(xsp));
if (xsp->size > 0 && xsp->rcvd > 0 &&
xsp->last.tv_sec >= xsp->start.tv_sec + 10)
fprintf(stderr, " ETA: %s", stat_eta(xsp));
fprintf(stderr, "\033[K");
}
/*
* Initialize the transfer statistics
*/
static void
stat_start(struct xferstat *xsp, const char *name, off_t *size, off_t *offset)
{
gettimeofday(&xsp->start, NULL);
xsp->last.tv_sec = xsp->last.tv_usec = 0;
xsp->name = name;
xsp->size = *size;
xsp->offset = *offset;
xsp->rcvd = *offset;
}
/*
* Update the transfer statistics
*/
static void
stat_update(struct xferstat *xsp, off_t rcvd)
{
xsp->rcvd = rcvd + xsp->offset;
stat_display(xsp);
}
/*
* Finalize the transfer statistics
*/
static void
stat_end(struct xferstat *xsp)
{
char size[8];
(void)xbps_humanize_number(size, (int64_t)xsp->size);
fprintf(stderr, "\rDownloaded %s for %s [avg rate: %s]",
size, xsp->name, stat_bps(xsp));
fprintf(stderr, "\033[K\n");
}
#ifdef DEBUG
static const char * static const char *
print_time(time_t *t) print_time(time_t *t)
{ {
@ -197,13 +61,6 @@ print_time(time_t *t)
strftime(buf, sizeof(buf), "%d %b %Y %H:%M", &tm); strftime(buf, sizeof(buf), "%d %b %Y %H:%M", &tm);
return buf; return buf;
} }
#endif
const char *
xbps_fetch_error_string(void)
{
return fetchLastErrString;
}
void HIDDEN void HIDDEN
xbps_fetch_set_cache_connection(int global, int per_host) xbps_fetch_set_cache_connection(int global, int per_host)
@ -222,18 +79,27 @@ xbps_fetch_unset_cache_connection(void)
fetchConnectionCacheClose(); fetchConnectionCacheClose();
} }
const char *
xbps_fetch_error_string(void)
{
return fetchLastErrString;
}
int int
xbps_fetch_file(const char *uri, const char *outputdir, bool refetch, xbps_fetch_file(const char *uri,
const char *flags) const char *outputdir,
bool refetch,
const char *flags,
void (*progress_cb)(void *),
struct xbps_fetch_progress_data *xfpd)
{ {
struct stat st; struct stat st;
struct xferstat xs;
struct url *url = NULL; struct url *url = NULL;
struct url_stat url_st; struct url_stat url_st;
struct fetchIO *fio = NULL; struct fetchIO *fio = NULL;
struct timeval tv[2]; struct timeval tv[2];
off_t bytes_dload = -1;
ssize_t bytes_read = -1, bytes_written; ssize_t bytes_read = -1, bytes_written;
off_t bytes_dld = -1;
char buf[4096], *filename, *destfile = NULL; char buf[4096], *filename, *destfile = NULL;
int fd = -1, rv = 0; int fd = -1, rv = 0;
bool restart = false; bool restart = false;
@ -244,11 +110,10 @@ xbps_fetch_file(const char *uri, const char *outputdir, bool refetch,
/* /*
* Get the filename specified in URI argument. * Get the filename specified in URI argument.
*/ */
filename = strrchr(uri, '/'); if ((filename = strrchr(uri, '/')) == NULL)
if (filename == NULL) {
errno = EINVAL;
return -1; return -1;
}
/* Skip first '/' */
filename++; filename++;
/* /*
* Compute destination file path. * Compute destination file path.
@ -261,7 +126,6 @@ xbps_fetch_file(const char *uri, const char *outputdir, bool refetch,
/* /*
* Check if we have to resume a transfer. * Check if we have to resume a transfer.
*/ */
memset(&st, 0, sizeof(st));
if (stat(destfile, &st) == 0) { if (stat(destfile, &st) == 0) {
if (st.st_size > 0) if (st.st_size > 0)
restart = true; restart = true;
@ -324,23 +188,23 @@ xbps_fetch_file(const char *uri, const char *outputdir, bool refetch,
url->offset = st.st_size; url->offset = st.st_size;
fio = fetchXGet(url, &url_st, flags); fio = fetchXGet(url, &url_st, flags);
} }
#ifdef DEBUG
printf("st.st_size: %zd\n", (ssize_t)st.st_size);
printf("st.st_atime: %s\n", print_time(&st.st_atime));
printf("st.st_mtime: %s\n", print_time(&st.st_mtime));
printf("url->scheme: %s\n", url->scheme); /* debug stuff */
printf("url->host: %s\n", url->host); xbps_dbg_printf("st.st_size: %zd\n", (ssize_t)st.st_size);
printf("url->port: %d\n", url->port); xbps_dbg_printf("st.st_atime: %s\n", print_time(&st.st_atime));
printf("url->doc: %s\n", url->doc); xbps_dbg_printf("st.st_mtime: %s\n", print_time(&st.st_mtime));
printf("url->offset: %zd\n", (ssize_t)url->offset); xbps_dbg_printf("url->scheme: %s\n", url->scheme);
printf("url->length: %zu\n", url->length); xbps_dbg_printf("url->host: %s\n", url->host);
printf("url->last_modified: %s\n", print_time(&url->last_modified)); xbps_dbg_printf("url->port: %d\n", url->port);
xbps_dbg_printf("url->doc: %s\n", url->doc);
xbps_dbg_printf("url->offset: %zd\n", (ssize_t)url->offset);
xbps_dbg_printf("url->length: %zu\n", url->length);
xbps_dbg_printf("url->last_modified: %s\n",
print_time(&url->last_modified));
xbps_dbg_printf("url_stat.size: %zd\n", (ssize_t)url_st.size);
xbps_dbg_printf("url_stat.atime: %s\n", print_time(&url_st.atime));
xbps_dbg_printf("url_stat.mtime: %s\n", print_time(&url_st.mtime));
printf("url_stat.size: %zd\n", (ssize_t)url_st.size);
printf("url_stat.atime: %s\n", print_time(&url_st.atime));
printf("url_stat.mtime: %s\n", print_time(&url_st.mtime));
#endif
if (fio == NULL && fetchLastErrCode != FETCH_OK) { if (fio == NULL && fetchLastErrCode != FETCH_OK) {
if (!refetch && restart && fetchLastErrCode == FETCH_UNAVAIL) { if (!refetch && restart && fetchLastErrCode == FETCH_UNAVAIL) {
/* /*
@ -356,13 +220,13 @@ xbps_fetch_file(const char *uri, const char *outputdir, bool refetch,
goto out; goto out;
} }
if (url_st.size == -1) { if (url_st.size == -1) {
printf("Remote file size is unknown!\n"); xbps_error_printf("Remote file size is unknown!\n");
errno = EINVAL; errno = EINVAL;
rv = -1; rv = -1;
goto out; goto out;
} else if (st.st_size > url_st.size) { } else if (st.st_size > url_st.size) {
printf("Local file %s is greater than remote file!\n", xbps_error_printf("Local file %s is greater than remote "
filename); "file!\n", filename);
errno = EFBIG; errno = EFBIG;
rv = -1; rv = -1;
goto out; goto out;
@ -371,8 +235,6 @@ xbps_fetch_file(const char *uri, const char *outputdir, bool refetch,
/* Local and remote size/mtime match, do nothing. */ /* Local and remote size/mtime match, do nothing. */
goto out; goto out;
} }
fprintf(stderr, "Connected to %s.\n", url->host);
/* /*
* If restarting, open the file for appending otherwise create it. * If restarting, open the file for appending otherwise create it.
*/ */
@ -386,32 +248,64 @@ xbps_fetch_file(const char *uri, const char *outputdir, bool refetch,
goto out; goto out;
} }
/*
* Initialize data for the fetch progress function callback
* and let the user know that the transfer is going to start
* immediately.
*/
if (progress_cb != NULL && xfpd != NULL) {
xfpd->file_name = filename;
xfpd->file_size = url_st.size;
xfpd->file_offset = url->offset;
xfpd->file_dloaded = -1;
xfpd->cb_start = true;
xfpd->cb_update = false;
xfpd->cb_end = false;
progress_cb(xfpd);
}
/* /*
* Start fetching requested file. * Start fetching requested file.
*/ */
stat_start(&xs, filename, &url_st.size, &url->offset);
while ((bytes_read = fetchIO_read(fio, buf, sizeof(buf))) > 0) { while ((bytes_read = fetchIO_read(fio, buf, sizeof(buf))) > 0) {
bytes_written = write(fd, buf, (size_t)bytes_read); bytes_written = write(fd, buf, (size_t)bytes_read);
if (bytes_written != bytes_read) { if (bytes_written != bytes_read) {
fprintf(stderr, "Couldn't write to %s!\n", destfile); xbps_error_printf("Couldn't write to %s!\n", destfile);
rv = -1; rv = -1;
goto out; goto out;
} }
bytes_dld += bytes_read; bytes_dload += bytes_read;
stat_update(&xs, bytes_dld); /*
* Let the fetch progress callback know that
* we are sucking more bytes from it.
*/
if (progress_cb != NULL && xfpd != NULL) {
xfpd->file_dloaded = bytes_dload;
xfpd->cb_start = false;
xfpd->cb_update = true;
progress_cb(xfpd);
}
}
/*
* Let the fetch progress callback know that the file
* has been fetched.
*/
if (progress_cb != NULL && xfpd != NULL) {
xfpd->cb_update = false;
xfpd->cb_end = true;
progress_cb(xfpd);
} }
if (bytes_read == -1) { if (bytes_read == -1) {
fprintf(stderr, "IO error while fetching %s: %s\n", filename, xbps_error_printf("IO error while fetching %s: %s\n", filename,
fetchLastErrString); fetchLastErrString);
errno = EIO; errno = EIO;
rv = -1; rv = -1;
goto out; goto out;
} }
stat_end(&xs); if (fd == -1) {
rv = -1;
if (fd == -1)
goto out; goto out;
}
/* /*
* Update mtime in local file to match remote file if transfer * Update mtime in local file to match remote file if transfer
* was successful. * was successful.
@ -419,12 +313,13 @@ xbps_fetch_file(const char *uri, const char *outputdir, bool refetch,
tv[0].tv_sec = url_st.atime ? url_st.atime : url_st.mtime; tv[0].tv_sec = url_st.atime ? url_st.atime : url_st.mtime;
tv[1].tv_sec = url_st.mtime; tv[1].tv_sec = url_st.mtime;
tv[0].tv_usec = tv[1].tv_usec = 0; tv[0].tv_usec = tv[1].tv_usec = 0;
if (utimes(destfile, tv) == -1) if (utimes(destfile, tv) == -1) {
rv = -1; rv = -1;
else { goto out;
}
/* File downloaded successfully */ /* File downloaded successfully */
rv = 1; rv = 1;
}
out: out:
if (fd != -1) if (fd != -1)

View File

@ -37,16 +37,6 @@
#include <xbps_api.h> #include <xbps_api.h>
#include "xbps_api_impl.h" #include "xbps_api_impl.h"
/**
* @file lib/fexec.c
* @brief Generic file execution routines
* @defgroup fexec File execution functions
*
* These functions will fork and execute a program in cwd (current working
* directory), destination directory or changing root directory to
* destination directory and passing an arbitrary number of arguments to it.
*/
static int static int
pfcexec(const char *path, const char *file, const char **argv) pfcexec(const char *path, const char *file, const char **argv)
{ {

View File

@ -1,5 +1,5 @@
/*- /*-
* Copyright (c) 2010 Juan Romero Pardines. * Copyright (c) 2011 Juan Romero Pardines.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -32,6 +32,14 @@
#include <xbps_api.h> #include <xbps_api.h>
#include "xbps_api_impl.h" #include "xbps_api_impl.h"
/**
* @file lib/initend.c
* @brief Initialization and finalization routines
* @defgroup initend Initialization and finalization functions
*
* Use these functions to initialize some parameters before starting
* using libxbps and finalize usage to release resources at the end.
*/
static bool with_debug; static bool with_debug;
void void
@ -50,18 +58,13 @@ xbps_end(void)
xbps_fetch_unset_cache_connection(); xbps_fetch_unset_cache_connection();
} }
void static void
xbps_dbg_printf(const char *fmt, ...) common_printf(FILE *f, const char *msg, const char *fmt, va_list ap)
{ {
va_list ap; if (msg != NULL)
fprintf(f, "%s", msg);
if (!with_debug) vfprintf(f, fmt, ap);
return;
va_start(ap, fmt);
fprintf(stderr, "[DEBUG] ");
vfprintf(stderr, fmt, ap);
va_end(ap);
} }
void void
@ -73,6 +76,53 @@ xbps_dbg_printf_append(const char *fmt, ...)
return; return;
va_start(ap, fmt); va_start(ap, fmt);
vfprintf(stderr, fmt, ap); common_printf(stderr, NULL, fmt, ap);
va_end(ap);
}
void
xbps_dbg_printf(const char *fmt, ...)
{
va_list ap;
if (!with_debug)
return;
va_start(ap, fmt);
common_printf(stderr, "[DEBUG] ", fmt, ap);
va_end(ap);
}
void
xbps_error_printf(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
common_printf(stderr, "ERROR: ", fmt, ap);
va_end(ap);
}
void
xbps_warn_printf(const char *fmt, ...)
{
int flags = xbps_get_flags();
va_list ap;
if ((flags & XBPS_FLAG_VERBOSE) == 0)
return;
va_start(ap, fmt);
common_printf(stderr, "WARNING: ", fmt, ap);
va_end(ap);
}
void
xbps_printf(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
common_printf(stdout, NULL, fmt, ap);
va_end(ap); va_end(ap);
} }

View File

@ -38,12 +38,6 @@
#include <xbps_api.h> #include <xbps_api.h>
/**
* @file lib/mkpath.c
* @brief Generic directory creation routines
* @defgroup dircreate Generic directory creation functions
*/
int int
xbps_mkpath(char *path, mode_t mode) xbps_mkpath(char *path, mode_t mode)
{ {

View File

@ -199,7 +199,7 @@ xbps_entry_install_conf_file(prop_dictionary_t filesd,
} else if ((strcmp(sha256_orig, sha256_cur) == 0) && } else if ((strcmp(sha256_orig, sha256_cur) == 0) &&
(strcmp(sha256_orig, sha256_new)) && (strcmp(sha256_orig, sha256_new)) &&
(strcmp(sha256_cur, sha256_new))) { (strcmp(sha256_cur, sha256_new))) {
printf("Updating configuration file `%s' " xbps_printf("Updating configuration file `%s' "
"with new version.\n", cffile); "with new version.\n", cffile);
rv = 1; rv = 1;
break; break;
@ -211,7 +211,7 @@ xbps_entry_install_conf_file(prop_dictionary_t filesd,
} else if ((strcmp(sha256_orig, sha256_new) == 0) && } else if ((strcmp(sha256_orig, sha256_new) == 0) &&
(strcmp(sha256_cur, sha256_new)) && (strcmp(sha256_cur, sha256_new)) &&
(strcmp(sha256_orig, sha256_cur))) { (strcmp(sha256_orig, sha256_cur))) {
printf("Keeping modified configuration file " xbps_printf("Keeping modified configuration file "
"`%s'.\n", cffile); "`%s'.\n", cffile);
rv = 0; rv = 0;
break; break;
@ -241,9 +241,9 @@ xbps_entry_install_conf_file(prop_dictionary_t filesd,
rv = -1; rv = -1;
break; break;
} }
printf("Keeping modified configuration file " xbps_printf("Keeping modified configuration file "
"`%s'.\n", cffile); "`%s'.\n", cffile);
printf("Installing new configuration file as " xbps_printf("Installing new configuration file as "
"`%s.new-%s'\n", cffile, version); "`%s.new-%s'\n", cffile, version);
archive_entry_set_pathname(entry, buf); archive_entry_set_pathname(entry, buf);
free(buf); free(buf);

View File

@ -1,5 +1,5 @@
/*- /*-
* Copyright (c) 2009-2010 Juan Romero Pardines. * Copyright (c) 2009-2011 Juan Romero Pardines.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -115,7 +115,7 @@ xbps_configure_pkg(const char *pkgname,
lver = version; lver = version;
} }
printf("%sonfiguring package %s-%s...\n", xbps_printf("%sonfiguring package `%s-%s' ...\n",
reconfigure ? "Rec" : "C", pkgname, lver); reconfigure ? "Rec" : "C", pkgname, lver);
buf = xbps_xasprintf(".%s/metadata/%s/INSTALL", buf = xbps_xasprintf(".%s/metadata/%s/INSTALL",
@ -134,8 +134,8 @@ xbps_configure_pkg(const char *pkgname,
if (xbps_file_exec(buf, "post", if (xbps_file_exec(buf, "post",
pkgname, lver, update ? "yes" : "no", NULL) != 0) { pkgname, lver, update ? "yes" : "no", NULL) != 0) {
free(buf); free(buf);
xbps_dbg_printf("%s: [configure] post INSTALL " xbps_error_printf("%s: post install script error: %s\n",
"action returned %s\n", pkgname, strerror(errno)); pkgname, strerror(errno));
return errno; return errno;
} }
} else { } else {

View File

@ -1,5 +1,5 @@
/*- /*-
* Copyright (c) 2009-2010 Juan Romero Pardines. * Copyright (c) 2009-2011 Juan Romero Pardines.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -31,7 +31,6 @@
#include <xbps_api.h> #include <xbps_api.h>
#include "xbps_api_impl.h" #include "xbps_api_impl.h"
#include "queue.h"
/** /**
* @file lib/package_orphans.c * @file lib/package_orphans.c
@ -61,29 +60,19 @@
* dictionary. * dictionary.
*/ */
struct orphan_pkg {
SIMPLEQ_ENTRY(orphan_pkg) chain;
prop_dictionary_t dict;
const char *pkgname;
};
static SIMPLEQ_HEAD(orphan_head, orphan_pkg) orphan_list =
SIMPLEQ_HEAD_INITIALIZER(orphan_list);
static int static int
find_orphan_pkg(prop_object_t obj, void *arg, bool *loop_done) find_orphan_pkg(prop_object_t obj, void *arg, bool *loop_done)
{ {
prop_array_t reqby; prop_array_t reqby, orphans = arg;
prop_object_t obj2; prop_object_t obj2, obj3;
prop_object_iterator_t iter; prop_object_iterator_t iter, iter2;
struct orphan_pkg *orphan; const char *orphan_pkgname;
char *pkgname; char *pkgname;
unsigned int ndep = 0, cnt = 0; unsigned int ndep = 0, cnt = 0;
bool automatic = false; bool automatic = false;
pkg_state_t state = 0; pkg_state_t state = 0;
int rv = 0; int rv = 0;
(void)arg;
(void)loop_done; (void)loop_done;
prop_dictionary_get_bool(obj, "automatic-install", &automatic); prop_dictionary_get_bool(obj, "automatic-install", &automatic);
@ -97,100 +86,79 @@ find_orphan_pkg(prop_object_t obj, void *arg, bool *loop_done)
return 0; return 0;
reqby = prop_dictionary_get(obj, "requiredby"); reqby = prop_dictionary_get(obj, "requiredby");
if (reqby == NULL) if (prop_object_type(reqby) != PROP_TYPE_ARRAY)
return 0;
else if (prop_object_type(reqby) != PROP_TYPE_ARRAY)
return EINVAL; return EINVAL;
if ((cnt = prop_array_count(reqby)) == 0) if ((cnt = prop_array_count(reqby)) == 0) {
goto add_orphan; prop_array_add(orphans, obj);
return 0;
}
iter = prop_array_iterator(reqby); iter = prop_array_iterator(reqby);
if (iter == NULL) if (iter == NULL)
return errno; return ENOMEM;
while ((obj2 = prop_object_iterator_next(iter)) != NULL) { while ((obj2 = prop_object_iterator_next(iter)) != NULL) {
pkgname = xbps_get_pkg_name(prop_string_cstring_nocopy(obj2)); pkgname = xbps_get_pkg_name(prop_string_cstring_nocopy(obj2));
if (pkgname == NULL) if (pkgname == NULL) {
prop_object_iterator_release(iter);
return EINVAL; return EINVAL;
}
SIMPLEQ_FOREACH(orphan, &orphan_list, chain) { iter2 = prop_array_iterator(orphans);
if (strcmp(orphan->pkgname, pkgname) == 0) { if (iter == NULL) {
free(pkgname);
prop_object_iterator_release(iter);
return ENOMEM;
}
while ((obj3 = prop_object_iterator_next(iter2)) != NULL) {
prop_dictionary_get_cstring_nocopy(obj3,
"pkgname", &orphan_pkgname);
if (strcmp(orphan_pkgname, pkgname) == 0) {
ndep++; ndep++;
break; break;
} }
} }
prop_object_iterator_release(iter2);
free(pkgname); free(pkgname);
} }
prop_object_iterator_release(iter); prop_object_iterator_release(iter);
if (ndep != cnt) if (ndep != cnt)
return 0; return 0;
if (!prop_array_add(orphans, obj))
add_orphan: return EINVAL;
orphan = NULL;
orphan = malloc(sizeof(struct orphan_pkg));
if (orphan == NULL)
return errno;
prop_dictionary_get_cstring_nocopy(obj, "pkgname", &orphan->pkgname);
orphan->dict = prop_dictionary_copy(obj);
SIMPLEQ_INSERT_TAIL(&orphan_list, orphan, chain);
return 0; return 0;
} }
static void
cleanup(void)
{
struct orphan_pkg *orphan;
while ((orphan = SIMPLEQ_FIRST(&orphan_list)) != NULL) {
SIMPLEQ_REMOVE(&orphan_list, orphan, orphan_pkg, chain);
prop_object_release(orphan->dict);
free(orphan);
}
xbps_regpkgdb_dictionary_release();
}
prop_array_t prop_array_t
xbps_find_orphan_packages(void) xbps_find_orphan_packages(void)
{ {
prop_array_t array; prop_array_t array;
prop_dictionary_t dict; prop_dictionary_t dict;
struct orphan_pkg *orphan;
int rv = 0; int rv = 0;
if ((dict = xbps_regpkgdb_dictionary_get()) == NULL) if ((dict = xbps_regpkgdb_dictionary_get()) == NULL)
return NULL; return NULL;
/*
* Prepare an array with all packages previously found.
*/
if ((array = prop_array_create()) == NULL)
return NULL;
/* /*
* Find out all orphans by looking at the * Find out all orphans by looking at the
* regpkgdb dictionary and iterate in reverse order * regpkgdb dictionary and iterate in reverse order
* in which packages were installed. * in which packages were installed.
*/ */
rv = xbps_callback_array_iter_reverse_in_dict(dict, "packages", rv = xbps_callback_array_iter_reverse_in_dict(dict, "packages",
find_orphan_pkg, NULL); find_orphan_pkg, array);
if (rv != 0) { if (rv != 0) {
errno = rv; errno = rv;
cleanup(); prop_object_release(array);
return NULL; return NULL;
} }
/*
* Prepare an array with all packages previously found.
*/
array = prop_array_create();
if (array == NULL) {
cleanup();
return NULL;
}
while ((orphan = SIMPLEQ_FIRST(&orphan_list)) != NULL) {
if (!prop_array_add(array, orphan->dict)) {
cleanup();
return NULL;
}
SIMPLEQ_REMOVE(&orphan_list, orphan, orphan_pkg, chain);
prop_object_release(orphan->dict);
free(orphan);
}
xbps_regpkgdb_dictionary_release(); xbps_regpkgdb_dictionary_release();
return array; return array;

View File

@ -1,5 +1,5 @@
/*- /*-
* Copyright (c) 2009-2010 Juan Romero Pardines. * Copyright (c) 2009-2011 Juan Romero Pardines.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -54,7 +54,7 @@ remove_pkg_metadata(const char *pkgname)
struct dirent *dp; struct dirent *dp;
DIR *dirp; DIR *dirp;
char *metadir, *path; char *metadir, *path;
int rv = 0, flags = xbps_get_flags(); int rv = 0;
assert(pkgname != NULL); assert(pkgname != NULL);
@ -81,11 +81,10 @@ remove_pkg_metadata(const char *pkgname)
return ENOMEM; return ENOMEM;
} }
if (unlink(path) == -1) { if (unlink(path) == -1)
if (flags & XBPS_FLAG_VERBOSE) xbps_warn_printf("can't remove metadata file: "
printf("WARNING: can't remove %s (%s)\n", "`%s': %s\n", dp->d_name, strerror(errno));
pkgname, strerror(errno));
}
free(path); free(path);
} }
(void)closedir(dirp); (void)closedir(dirp);
@ -130,7 +129,7 @@ int
xbps_purge_pkg(const char *pkgname, bool check_state) xbps_purge_pkg(const char *pkgname, bool check_state)
{ {
prop_dictionary_t dict, pkgd; prop_dictionary_t dict, pkgd;
int rv = 0, flags = xbps_get_flags(); int rv = 0;
pkg_state_t state = 0; pkg_state_t state = 0;
assert(pkgname != NULL); assert(pkgname != NULL);
@ -188,8 +187,7 @@ xbps_purge_pkg(const char *pkgname, bool check_state)
if ((rv = xbps_unregister_pkg(pkgname)) != 0) if ((rv = xbps_unregister_pkg(pkgname)) != 0)
goto out; goto out;
if (flags & XBPS_FLAG_VERBOSE) xbps_printf("Package %s purged successfully.\n", pkgname);
printf("Package %s purged successfully.\n", pkgname);
out: out:
xbps_regpkgdb_dictionary_release(); xbps_regpkgdb_dictionary_release();

View File

@ -1,5 +1,5 @@
/*- /*-
* Copyright (c) 2009-2010 Juan Romero Pardines. * Copyright (c) 2009-2011 Juan Romero Pardines.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -123,31 +123,28 @@ xbps_remove_pkg_files(prop_dictionary_t dict, const char *key)
"sha256", &sha256); "sha256", &sha256);
rv = xbps_check_file_hash(path, sha256); rv = xbps_check_file_hash(path, sha256);
if (rv == ENOENT) { if (rv == ENOENT) {
fprintf(stderr, xbps_warn_printf("'%s' doesn't exist!\n", file);
"WARNING: '%s' doesn't exist!\n", file);
free(path); free(path);
rv = 0; rv = 0;
continue; continue;
} else if (rv == ERANGE) { } else if (rv == ERANGE) {
rv = 0; rv = 0;
if (flags & XBPS_FLAG_VERBOSE) {
if (flags & XBPS_FLAG_FORCE) { if (flags & XBPS_FLAG_FORCE) {
fprintf(stderr, xbps_warn_printf("'%s': SHA256 "
"WARNING: '%s' SHA256 " "mismatch, forcing removal...\n",
"mismatch, forcing " file);
"removal...\n", file); } else {
} else { xbps_warn_printf("'%s': SHA256 "
fprintf(stderr, "mismatch, preserving file...\n",
"WARNING: '%s' SHA256 "
"mismatch, preserving...\n",
file); file);
}
} }
if ((flags & XBPS_FLAG_FORCE) == 0) { if ((flags & XBPS_FLAG_FORCE) == 0) {
free(path); free(path);
continue; continue;
} }
} else if (rv != 0 && rv != ERANGE) { } else if (rv != 0 && rv != ERANGE) {
xbps_error_printf("failed to check hash for "
"`%s': %s\n", file, strerror(rv));
free(path); free(path);
break; break;
} }
@ -156,15 +153,12 @@ xbps_remove_pkg_files(prop_dictionary_t dict, const char *key)
* Remove the object if possible. * Remove the object if possible.
*/ */
if (remove(path) == -1) { if (remove(path) == -1) {
if (flags & XBPS_FLAG_VERBOSE) xbps_warn_printf("can't remove %s `%s': %s\n",
fprintf(stderr, curobj, file, strerror(errno));
"WARNING: can't remove %s %s "
"(%s)\n", curobj, file, strerror(errno));
} else { } else {
/* Success */ /* Success */
if (flags & XBPS_FLAG_VERBOSE) xbps_printf("Removed %s: `%s'\n", curobj, file);
printf("Removed %s: %s\n", curobj, file);
} }
free(path); free(path);
} }
@ -207,8 +201,7 @@ xbps_remove_pkg(const char *pkgname, const char *version, bool update)
rmfile_exists = true; rmfile_exists = true;
if (xbps_file_exec(buf, "pre", pkgname, version, if (xbps_file_exec(buf, "pre", pkgname, version,
update ? "yes" : "no", NULL) != 0) { update ? "yes" : "no", NULL) != 0) {
fprintf(stderr, xbps_error_printf("%s: pre remove script error: %s\n",
"%s: prerm action target error (%s)\n",
pkgname, strerror(errno)); pkgname, strerror(errno));
free(buf); free(buf);
return errno; return errno;
@ -265,9 +258,8 @@ xbps_remove_pkg(const char *pkgname, const char *version, bool update)
*/ */
if (rmfile_exists && if (rmfile_exists &&
(xbps_file_exec(buf, "post", pkgname, version, "no", NULL) != 0)) { (xbps_file_exec(buf, "post", pkgname, version, "no", NULL) != 0)) {
fprintf(stderr, xbps_error_printf("%s: post remove script error: %s\n",
"%s: postrm action target error (%s)\n", pkgname, pkgname, strerror(errno));
strerror(errno));
free(buf); free(buf);
return errno; return errno;
} }

View File

@ -1,5 +1,5 @@
/*- /*-
* Copyright (c) 2009-2010 Juan Romero Pardines. * Copyright (c) 2009-2011 Juan Romero Pardines.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -126,14 +126,13 @@ again:
* Obsolete obj found, remove it. * Obsolete obj found, remove it.
*/ */
if (remove(file) == -1) { if (remove(file) == -1) {
fprintf(stderr, xbps_warn_printf("couldn't remove obsole entry "
"WARNING: couldn't remove obsolete obj: %s (%s)\n", "`%s': %s\n", prop_string_cstring_nocopy(oldstr),
prop_string_cstring_nocopy(oldstr),
strerror(errno)); strerror(errno));
free(file); free(file);
continue; continue;
} }
printf("Removed obsolete obj: %s\n", xbps_printf("Removed obsolete entry: %s\n",
prop_string_cstring_nocopy(oldstr)); prop_string_cstring_nocopy(oldstr));
free(file); free(file);
} }

View File

@ -1,5 +1,5 @@
/*- /*-
* Copyright (c) 2009-2010 Juan Romero Pardines. * Copyright (c) 2009-2011 Juan Romero Pardines.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -32,6 +32,21 @@
#include <xbps_api.h> #include <xbps_api.h>
#include "xbps_api_impl.h" #include "xbps_api_impl.h"
struct state {
const char *string;
pkg_state_t number;
};
static const struct state states[] = {
{ "unpacked", XBPS_PKG_STATE_UNPACKED },
{ "installed", XBPS_PKG_STATE_INSTALLED },
{ "broken", XBPS_PKG_STATE_BROKEN },
{ "config-files", XBPS_PKG_STATE_CONFIG_FILES },
{ "not-installed", XBPS_PKG_STATE_NOT_INSTALLED },
{ NULL, 0 }
};
/** /**
* @file lib/package_state.c * @file lib/package_state.c
* @brief Package state handling routines * @brief Package state handling routines
@ -41,36 +56,23 @@
static int static int
set_new_state(prop_dictionary_t dict, pkg_state_t state) set_new_state(prop_dictionary_t dict, pkg_state_t state)
{ {
const char *pkgname, *state_str; const struct state *stp;
const char *pkgname;
assert(dict != NULL);
switch (state) { for (stp = states; stp->string != NULL; stp++)
case XBPS_PKG_STATE_UNPACKED: if (state == stp->number)
state_str = "unpacked";
break; break;
case XBPS_PKG_STATE_INSTALLED:
state_str = "installed"; if (stp->string == NULL)
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; return -1;
}
if (!prop_dictionary_set_cstring_nocopy(dict, "state", state_str)) if (!prop_dictionary_set_cstring_nocopy(dict, "state", stp->string))
return EINVAL; return EINVAL;
if (prop_dictionary_get_cstring_nocopy(dict, "pkgname", &pkgname)) { if (prop_dictionary_get_cstring_nocopy(dict, "pkgname", &pkgname)) {
xbps_dbg_printf("%s: changed pkg state to '%s'\n", xbps_dbg_printf("%s: changed pkg state to '%s'\n",
pkgname, state_str); pkgname, stp->string);
} }
return 0; return 0;
@ -79,28 +81,19 @@ set_new_state(prop_dictionary_t dict, pkg_state_t state)
static pkg_state_t static pkg_state_t
get_state(prop_dictionary_t dict) get_state(prop_dictionary_t dict)
{ {
const struct state *stp;
const char *state_str; const char *state_str;
pkg_state_t state = 0;
assert(dict != NULL); assert(dict != NULL);
prop_dictionary_get_cstring_nocopy(dict, "state", &state_str); prop_dictionary_get_cstring_nocopy(dict, "state", &state_str);
assert(state_str != NULL); assert(state_str != NULL);
if (strcmp(state_str, "unpacked") == 0) for (stp = states; stp->string != NULL; stp++)
state = XBPS_PKG_STATE_UNPACKED; if (strcmp(state_str, stp->string) == 0)
else if (strcmp(state_str, "installed") == 0) break;
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; return stp->number;
} }
int int

View File

@ -1,5 +1,5 @@
/*- /*-
* Copyright (c) 2008-2010 Juan Romero Pardines. * Copyright (c) 2008-2011 Juan Romero Pardines.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -86,22 +86,90 @@ set_extract_flags(int *flags, bool update)
*flags = lflags; *flags = lflags;
} }
/*
* TODO: remove printfs and return appropiate errors to be interpreted by
* the consumer.
*/
static int static int
unpack_archive_fini(prop_dictionary_t pkg_repod, extract_metafile(struct archive *ar,
struct archive_entry *entry,
const char *file,
const char *pkgname,
const char *version,
bool exec,
int flags)
{
char *buf;
int rv;
buf = xbps_xasprintf(".%s/metadata/%s/%s",
XBPS_META_PATH, pkgname, file);
if (buf == NULL)
return ENOMEM;
archive_entry_set_pathname(entry, buf);
free(buf);
if (exec)
archive_entry_set_perm(entry, 0750);
if (archive_read_extract(ar, entry, flags) != 0) {
if ((rv = archive_errno(ar)) != EEXIST) {
xbps_error_printf("failed to extract metadata file `%s'"
"for `%s-%s': %s\n", file, pkgname, version,
strerror(rv));
}
}
return 0;
}
static int
remove_metafile(const char *file, const char *pkgname, const char *version)
{
char *buf;
buf = xbps_xasprintf(".%s/metadata/%s/%s",
XBPS_META_PATH, file, pkgname);
if (buf == NULL)
return ENOMEM;
if (unlink(buf) == -1) {
if (errno && errno != ENOENT) {
xbps_error_printf("failed to remove metadata file "
"`%s' while unpacking `%s-%s': %s\n", file,
pkgname, version, strerror(errno));
free(buf);
return errno;
}
}
free(buf);
return 0;
}
/*
* Execute the unpack progress function callback if set and its
* private data is also set. It's so sad that
* archive_read_set_progress_callback() from libarchive(3) cannot be used
* here because sometimes it misses some entries by unknown reasons.
*/
#define RUN_PROGRESS_CB() \
do { \
if (progress_cb != NULL && xupd != NULL) \
(*progress_cb)(xupd); \
} while (0)
static int
unpack_archive(prop_dictionary_t pkg_repod,
struct archive *ar, struct archive *ar,
const char *pkgname, const char *pkgname,
const char *version) const char *version,
void (*progress_cb)(void *),
struct xbps_unpack_progress_data *xupd)
{ {
prop_dictionary_t propsd, filesd, old_filesd; prop_dictionary_t propsd, filesd, old_filesd;
prop_array_t array;
struct archive_entry *entry; struct archive_entry *entry;
size_t entry_idx = 0; size_t nmetadata = 0, entry_idx = 0;
const char *rootdir, *entry_pname, *transact; const char *rootdir, *entry_pname, *transact;
char *buf; char *buf;
int rv, flags, lflags; int rv, flags;
bool preserve, update, replace_files_in_pkg_update; bool preserve, update, replace_files_in_pkg_update;
assert(ar != NULL); assert(ar != NULL);
@ -109,17 +177,19 @@ unpack_archive_fini(prop_dictionary_t pkg_repod,
assert(pkgname != NULL); assert(pkgname != NULL);
assert(version != NULL); assert(version != NULL);
preserve = update = replace_files_in_pkg_update = false; preserve = update = false;
rootdir = xbps_get_rootdir(); rootdir = xbps_get_rootdir();
flags = xbps_get_flags();
if (chdir(rootdir) == -1) if (chdir(rootdir) == -1) {
xbps_error_printf("cannot chdir to rootdir for "
"`%s-%s': %s\n", pkgname, version, strerror(errno));
return errno; return errno;
}
prop_dictionary_get_bool(pkg_repod, "preserve", &preserve); prop_dictionary_get_bool(pkg_repod, "preserve", &preserve);
prop_dictionary_get_cstring_nocopy(pkg_repod, prop_dictionary_get_cstring_nocopy(pkg_repod,
"trans-action", &transact); "trans-action", &transact);
assert(transasct != NULL); assert(transact != NULL);
if (strcmp(transact, "update") == 0) if (strcmp(transact, "update") == 0)
update = true; update = true;
@ -130,43 +200,28 @@ unpack_archive_fini(prop_dictionary_t pkg_repod,
* anymore. * anymore.
*/ */
if (update) { if (update) {
buf = xbps_xasprintf(".%s/metadata/%s/INSTALL", if ((rv = remove_metafile("INSTALL", pkgname, version)) != 0)
XBPS_META_PATH, pkgname); return rv;
if (buf == NULL) if ((rv = remove_metafile("REMOVE", pkgname, version)) != 0)
return ENOMEM; return rv;
if (unlink(buf) == -1) {
if (errno && errno != ENOENT) {
free(buf);
return errno;
}
}
free(buf);
buf = xbps_xasprintf(".%s/metadata/%s/REMOVE",
XBPS_META_PATH, pkgname);
if (buf == NULL)
return ENOMEM;
if (unlink(buf) == -1) {
if (errno && errno != ENOENT) {
free(buf);
return errno;
}
}
free(buf);
} }
/* /*
* Process the archive files. * Process the archive files.
*/ */
while (archive_read_next_header(ar, &entry) == ARCHIVE_OK) { while (archive_read_next_header(ar, &entry) == ARCHIVE_OK) {
entry_pname = archive_entry_pathname(entry); entry_pname = archive_entry_pathname(entry);
set_extract_flags(&lflags, update); set_extract_flags(&flags, update);
if (progress_cb != NULL && xupd != NULL) {
xupd->entry = entry_pname;
xupd->entry_size = archive_entry_size(entry);
xupd->entry_is_metadata = false;
xupd->entry_is_conf = false;
}
if (strcmp("./INSTALL", entry_pname) == 0) { if (strcmp("./INSTALL", entry_pname) == 0) {
/* /*
* Extract package INSTALL file into destination * Extract the INSTALL script first to execute
* directory and execute the pre install action. * the pre install target.
*/ */
buf = xbps_xasprintf(".%s/metadata/%s/INSTALL", buf = xbps_xasprintf(".%s/metadata/%s/INSTALL",
XBPS_META_PATH, pkgname); XBPS_META_PATH, pkgname);
@ -174,85 +229,80 @@ unpack_archive_fini(prop_dictionary_t pkg_repod,
rv = ENOMEM; rv = ENOMEM;
goto out; goto out;
} }
archive_entry_set_pathname(entry, buf); rv = extract_metafile(ar, entry, "INSTALL",
archive_entry_set_perm(entry, 0750); pkgname, version, true, flags);
if (archive_read_extract(ar, entry, lflags) != 0) { if (rv != 0) {
if ((rv = archive_errno(ar)) != EEXIST) {
free(buf); free(buf);
goto out; goto out;
} }
}
rv = xbps_file_exec(buf, "pre", rv = xbps_file_exec(buf, "pre",
pkgname, version, update ? "yes" : "no", NULL); pkgname, version, update ? "yes" : "no", NULL);
free(buf); free(buf);
if (rv != 0) { if (rv != 0) {
fprintf(stderr, xbps_error_printf("%s-%s: pre-install script "
"%s: preinst action target error %s\n", "error: %s\n", pkgname, version,
pkgname, strerror(errno)); strerror(rv));
goto out; goto out;
} }
/* Pass to the next entry if successful */ nmetadata++;
entry_idx++; if (xupd != NULL) {
xupd->entry_is_metadata = true;
xupd->entry_extract_count++;
}
RUN_PROGRESS_CB();
continue; continue;
/*
* Unpack metadata files in final directory.
*/
} else if (strcmp("./REMOVE", entry_pname) == 0) { } else if (strcmp("./REMOVE", entry_pname) == 0) {
buf = xbps_xasprintf(".%s/metadata/%s/REMOVE", rv = extract_metafile(ar, entry, "REMOVE",
XBPS_META_PATH, pkgname); pkgname, version, true, flags);
if (buf == NULL) { if (rv != 0)
rv = ENOMEM;
goto out; goto out;
nmetadata++;
if (xupd != NULL) {
xupd->entry_is_metadata = true;
xupd->entry_extract_count++;
} }
archive_entry_set_pathname(entry, buf); RUN_PROGRESS_CB();
free(buf);
archive_entry_set_perm(entry, 0750);
if (archive_read_extract(ar, entry, lflags) != 0) {
if ((rv = archive_errno(ar)) != EEXIST)
goto out;
}
/* Pass to next entry if successful */
entry_idx++;
continue; continue;
} else if (strcmp("./files.plist", entry_pname) == 0) { } else if (strcmp("./files.plist", entry_pname) == 0) {
/* /*
* Now we have a dictionary from the entry * Internalize this entry into a prop_dictionary
* in memory. Will be written to disk later, when * to check for obsolete files if updating a package.
* all files are extracted. * It will be extracted to disk at the end.
*/ */
filesd = xbps_read_dict_from_archive_entry(ar, entry); filesd = xbps_read_dict_from_archive_entry(ar, entry);
if (filesd == NULL) { if (filesd == NULL) {
rv = errno; rv = errno;
goto out; goto out;
} }
/* Pass to next entry */ nmetadata++;
entry_idx++; if (xupd != NULL) {
xupd->entry_is_metadata = true;
xupd->entry_extract_count++;
}
RUN_PROGRESS_CB();
continue; continue;
} else if (strcmp("./props.plist", entry_pname) == 0) { } else if (strcmp("./props.plist", entry_pname) == 0) {
buf = xbps_xasprintf(".%s/metadata/%s/%s", rv = extract_metafile(ar, entry, XBPS_PKGPROPS,
XBPS_META_PATH, pkgname, XBPS_PKGPROPS); pkgname, version, false, flags);
if (buf == NULL) { if (rv != 0)
rv = ENOMEM;
goto out; goto out;
}
archive_entry_set_pathname(entry, buf);
free(buf);
if (archive_read_extract(ar, entry, lflags) != 0) {
rv = archive_errno(ar);
goto out;
}
propsd = propsd = xbps_get_pkg_dict_from_metadata_plist(
xbps_get_pkg_dict_from_metadata_plist(pkgname, pkgname, XBPS_PKGPROPS);
XBPS_PKGPROPS);
if (propsd == NULL) { if (propsd == NULL) {
rv = errno; rv = errno;
goto out; goto out;
} }
/* Pass to next entry if successful */ nmetadata++;
entry_idx++; if (xupd != NULL) {
xupd->entry_is_metadata = true;
xupd->entry_extract_count++;
}
RUN_PROGRESS_CB();
continue; continue;
} }
/* /*
@ -266,12 +316,32 @@ unpack_archive_fini(prop_dictionary_t pkg_repod,
* required metadata files weren't found, bail out. * required metadata files weren't found, bail out.
* This is not an XBPS binary package. * This is not an XBPS binary package.
*/ */
if (entry_idx >= 3) if (entry_idx >= 3) {
xbps_error_printf("invalid binary pkg archive"
"for `%s-%s'\n", pkgname, version);
return ENODEV; return ENODEV;
}
entry_idx++; entry_idx++;
continue; continue;
} }
/*
* Compute total entries in progress data, if set.
* total_entries = metadata + files + conf_files + links.
*/
if (xupd != NULL) {
xupd->entry_total_count = nmetadata;
array = prop_dictionary_get(filesd, "files");
xupd->entry_total_count +=
(ssize_t)prop_array_count(array);
array = prop_dictionary_get(filesd, "conf_files");
xupd->entry_total_count +=
(ssize_t)prop_array_count(array);
array = prop_dictionary_get(filesd, "links");
xupd->entry_total_count +=
(ssize_t)prop_array_count(array);
}
/* /*
* Handle configuration files. Check if current entry is * Handle configuration files. Check if current entry is
* a configuration file and take action if required. Skip * a configuration file and take action if required. Skip
@ -283,6 +353,9 @@ unpack_archive_fini(prop_dictionary_t pkg_repod,
/* error */ /* error */
goto out; goto out;
} else if (rv == 1) { } else if (rv == 1) {
if (xupd != NULL)
xupd->entry_is_conf = true;
rv = xbps_entry_install_conf_file(filesd, rv = xbps_entry_install_conf_file(filesd,
entry, entry_pname, pkgname, version); entry, entry_pname, pkgname, version);
if (rv == -1) { if (rv == -1) {
@ -292,14 +365,15 @@ unpack_archive_fini(prop_dictionary_t pkg_repod,
/* /*
* Configuration file should be installed. * Configuration file should be installed.
*/ */
lflags &= ~ARCHIVE_EXTRACT_NO_OVERWRITE; flags &= ~ARCHIVE_EXTRACT_NO_OVERWRITE;
lflags &= ~ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER; flags &= ~ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER;
} else { } else {
/* /*
* Keep current configuration file * Keep current configuration file
* as is now and pass to next entry. * as is now and pass to next entry.
*/ */
archive_read_data_skip(ar); archive_read_data_skip(ar);
RUN_PROGRESS_CB();
continue; continue;
} }
} }
@ -326,31 +400,31 @@ unpack_archive_fini(prop_dictionary_t pkg_repod,
"replace-files-in-pkg-update", "replace-files-in-pkg-update",
&replace_files_in_pkg_update); &replace_files_in_pkg_update);
if (replace_files_in_pkg_update) { if (replace_files_in_pkg_update) {
lflags &= ~ARCHIVE_EXTRACT_NO_OVERWRITE; flags &= ~ARCHIVE_EXTRACT_NO_OVERWRITE;
lflags &= ~ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER; flags &= ~ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER;
} }
/* /*
* Extract entry from archive. * Extract entry from archive.
*/ */
if (archive_read_extract(ar, entry, lflags) != 0) { if (archive_read_extract(ar, entry, flags) != 0) {
rv = archive_errno(ar); rv = archive_errno(ar);
if (rv && rv != EEXIST) { if (rv != EEXIST) {
fprintf(stderr, "ERROR: extracting `%s' " xbps_error_printf("failed to extract `%s' "
"(%s) ...exiting!\n", entry_pname, "from `%s-%s': %s\n", entry_pname,
archive_error_string(ar)); pkgname, version, strerror(rv));
goto out; goto out;
} else if (rv == EEXIST) { } else {
if (flags & XBPS_FLAG_VERBOSE) { xbps_warn_printf("ignoring existing "
fprintf(stderr,
"WARNING: ignoring existent "
"entry: %s\n", entry_pname); "entry: %s\n", entry_pname);
} RUN_PROGRESS_CB();
continue; continue;
} }
} }
if (flags & XBPS_FLAG_VERBOSE) if (xupd != NULL)
printf(" %s\n", entry_pname); xupd->entry_extract_count++;
RUN_PROGRESS_CB();
} }
if ((rv = archive_errno(ar)) == 0) { if ((rv = archive_errno(ar)) == 0) {
@ -390,8 +464,11 @@ unpack_archive_fini(prop_dictionary_t pkg_repod,
* is reachable. * is reachable.
*/ */
if (!prop_dictionary_externalize_to_zfile(filesd, buf)) { if (!prop_dictionary_externalize_to_zfile(filesd, buf)) {
free(buf);
rv = errno; rv = errno;
xbps_error_printf("failed to extract metadata %s file"
"for `%s-%s': %s\n", XBPS_PKGFILES, pkgname,
version, strerror(rv));
free(buf);
goto out; goto out;
} }
free(buf); free(buf);
@ -405,14 +482,17 @@ out:
return rv; return rv;
} }
#undef RUN_PROGRESS_CB
int int
xbps_unpack_binary_pkg(prop_dictionary_t pkg_repod) xbps_unpack_binary_pkg(prop_dictionary_t pkg_repod,
void (*progress_cb)(void *),
struct xbps_unpack_progress_data *xupd)
{ {
struct archive *ar;
const char *pkgname, *version, *repoloc; const char *pkgname, *version, *repoloc;
struct archive *ar = NULL; char *bpkg;
char *binfile = NULL; int rv = 0;
int pkg_fd, rv = 0;
assert(pkg_repod != NULL); assert(pkg_repod != NULL);
@ -420,50 +500,61 @@ xbps_unpack_binary_pkg(prop_dictionary_t pkg_repod)
prop_dictionary_get_cstring_nocopy(pkg_repod, "version", &version); prop_dictionary_get_cstring_nocopy(pkg_repod, "version", &version);
prop_dictionary_get_cstring_nocopy(pkg_repod, "repository", &repoloc); prop_dictionary_get_cstring_nocopy(pkg_repod, "repository", &repoloc);
binfile = xbps_get_binpkg_repo_uri(pkg_repod, repoloc); bpkg = xbps_get_binpkg_repo_uri(pkg_repod, repoloc);
if (binfile == NULL) if (bpkg == NULL) {
return EINVAL; xbps_error_printf("cannot determine binary pkg file "
"for `%s-%s': %s\n", pkgname, version, strerror(errno));
if ((pkg_fd = open(binfile, O_RDONLY)) == -1) { return errno;
rv = errno;
xbps_dbg_printf("cannot open '%s' for unpacking %s\n",
binfile, strerror(errno));
free(binfile);
goto out;
} }
free(binfile);
ar = archive_read_new(); ar = archive_read_new();
if (ar == NULL) { if (ar == NULL) {
rv = errno; rv = ENOMEM;
goto out; 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 (archive_read_open_fd(ar, pkg_fd, if (archive_read_open_filename(ar, bpkg, ARCHIVE_READ_BLOCKSIZE) != 0) {
ARCHIVE_READ_BLOCKSIZE) != 0) { rv = archive_errno(ar);
rv = errno; xbps_error_printf("failed to open `%s' binpkg: %s\n",
bpkg, strerror(rv));
goto out; goto out;
} }
/*
if ((rv = unpack_archive_fini(pkg_repod, ar, pkgname, version)) != 0) * Set extract progress callback if specified.
*/
if (progress_cb != NULL && xupd != NULL) {
xupd->entry_extract_count = 0;
xupd->entry_total_count = 0;
}
/*
* Extract archive files.
*/
rv = unpack_archive(pkg_repod, ar, pkgname, version,
progress_cb, xupd);
if (rv != 0) {
xbps_error_printf("failed to unpack `%s' binpkg: %s\n",
bpkg, strerror(rv));
goto out; goto out;
}
/* /*
* Set package state to unpacked. * Set package state to unpacked.
*/ */
rv = xbps_set_pkg_state_installed(pkgname, XBPS_PKG_STATE_UNPACKED); rv = xbps_set_pkg_state_installed(pkgname, XBPS_PKG_STATE_UNPACKED);
if (rv != 0) {
xbps_error_printf("failed to set `%s-%s' to unpacked "
"state: %s\n", pkgname, version, strerror(rv));
}
out: out:
if (bpkg)
free(bpkg);
if (ar) if (ar)
archive_read_finish(ar); archive_read_finish(ar);
if (pkg_fd != -1)
(void)close(pkg_fd);
return rv; return rv;
} }

View File

@ -117,12 +117,10 @@ int
xbps_pkgpattern_match(const char *instpkg, char *pattern) xbps_pkgpattern_match(const char *instpkg, char *pattern)
{ {
const char *fname = instpkg; const char *fname = instpkg;
char *basefname, condchar = '\0', *condition; char *basefname = NULL, condchar = '\0', *condition;
size_t len = 0; size_t len = 0;
int rv = 0; int rv = 0;
memset(&basefname, 0, sizeof(basefname));
/* Check for a full match with strcmp, otherwise try csh_match() */ /* Check for a full match with strcmp, otherwise try csh_match() */
if (strcmp(instpkg, pattern) == 0) if (strcmp(instpkg, pattern) == 0)
return 1; return 1;

View File

@ -82,7 +82,9 @@ xbps_get_remote_repo_string(const char *uri)
* size and/or mtime match) and 1 if downloaded successfully. * size and/or mtime match) and 1 if downloaded successfully.
*/ */
int int
xbps_repository_sync_pkg_index(const char *uri) xbps_repository_sync_pkg_index(const char *uri,
void (*progress_cb)(void *),
struct xbps_fetch_progress_data *xfpd)
{ {
struct url *url = NULL; struct url *url = NULL;
struct utsname un; struct utsname un;
@ -160,8 +162,9 @@ xbps_repository_sync_pkg_index(const char *uri)
/* /*
* Download pkg-index.plist file from repository. * Download pkg-index.plist file from repository.
*/ */
if ((rv = xbps_fetch_file(rpidx, fetch_outputdir, rv = xbps_fetch_file(rpidx, fetch_outputdir, true, NULL,
true, NULL)) == -1) { progress_cb, xfpd);
if (rv == -1) {
(void)remove(tmp_metafile); (void)remove(tmp_metafile);
goto out; goto out;
} }

View File

@ -34,11 +34,11 @@ endif
$(BIN).static: $(OBJS) $(BIN).static: $(OBJS)
@printf " [CCLD]\t\t$@\n" @printf " [CCLD]\t\t$@\n"
${SILENT}$(CC) -static $^ $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) \ ${SILENT}$(CC) -static $^ $(CPPFLAGS) -L$(TOPDIR)/lib \
$(STATIC_LIBS) -o $@ $(CFLAGS) $(LDFLAGS) $(STATIC_LIBS) -o $@
$(BIN): $(OBJS) $(BIN): $(OBJS)
@printf " [CCLD]\t\t$@\n" @printf " [CCLD]\t\t$@\n"
${SILENT}$(CC) $^ $(CPPFLAGS) $(CFLAGS) $(PROG_CFLAGS) \ ${SILENT}$(CC) $^ $(CPPFLAGS) -L$(TOPDIR)/lib $(CFLAGS) \
$(LDFLAGS) $(PROG_LDFLAGS) -o $@ $(PROG_CFLAGS) $(LDFLAGS) $(PROG_LDFLAGS) -o $@