Initial import of xbps with code as August '09.

--HG--
extra : convert_revision : juan%40xbps-20090817170720-amxxac4a2e8bza1j
This commit is contained in:
juan 2009-08-17 19:07:20 +02:00
commit 3f3b6d00dd
52 changed files with 8657 additions and 0 deletions

31
Makefile Normal file
View File

@ -0,0 +1,31 @@
include vars.mk
SUBDIRS = lib bin etc
.PHONY: all
all:
for dir in $(SUBDIRS); do \
$(MAKE) -C $$dir; \
done
.PHONY: install
install:
for dir in $(SUBDIRS); do \
$(MAKE) -C $$dir install; \
done
@echo
@echo "Binaries have been installed into $(SBINDIR)."
@echo "Librares have been installed into $(LIBDIR)."
@echo
@echo "WARNING: Don't forget to rerun ldconfig(1)."
@echo
uninstall:
-rm -f $(SBINDIR)/xbps-*
-rm -f $(LIBDIR)/libxbps.so*
.PHONY: clean
clean:
for dir in $(SUBDIRS); do \
$(MAKE) -C $$dir clean; \
done

26
bin/Makefile Normal file
View File

@ -0,0 +1,26 @@
include ../vars.mk
SUBDIRS = xbps-bin
SUBDIRS += xbps-cmpver
SUBDIRS += xbps-digest
SUBDIRS += xbps-pkgdb
SUBDIRS += xbps-repo
SUBDIRS += xbps-src
.PHONY: all
all:
for dir in $(SUBDIRS); do \
$(MAKE) -C $$dir; \
done
.PHONY: install
install:
for dir in $(SUBDIRS); do \
$(MAKE) -C $$dir install; \
done
.PHONY: clean
clean:
for dir in $(SUBDIRS); do \
$(MAKE) -C $$dir clean; \
done

5
bin/xbps-bin/Makefile Normal file
View File

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

275
bin/xbps-bin/check.c Normal file
View File

@ -0,0 +1,275 @@
/*-
* 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 <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;
}
/*
* 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);
}
/*
* 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 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);
}
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;
}

35
bin/xbps-bin/defs.h Normal file
View File

@ -0,0 +1,35 @@
/*-
* 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.
*/
#ifndef _XBPS_BIN_DEFS_H_
#define _XBPS_BIN_DEFS_H_
void xbps_install_pkg(const char *, bool, bool);
void xbps_autoremove_pkgs(void);
void xbps_remove_installed_pkg(const char *, bool);
void xbps_autoupdate_pkgs(bool);
int xbps_check_pkg_integrity(const char *);
#endif /* !_XBPS_BIN_DEFS_H_ */

501
bin/xbps-bin/install.c Normal file
View File

@ -0,0 +1,501 @@
/*-
* 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 <xbps_api.h>
#include "defs.h"
struct transaction {
prop_dictionary_t dict;
prop_object_iterator_t iter;
const char *originpkgname;
bool force;
};
static void cleanup(int);
static int exec_transaction(struct transaction *);
static void show_missing_deps(prop_dictionary_t, const char *);
static int show_missing_dep_cb(prop_object_t, void *, bool *);
static void show_package_list(prop_object_iterator_t, const char *);
static void
show_missing_deps(prop_dictionary_t d, const char *pkgname)
{
printf("Unable to locate some required packages for %s:\n",
pkgname);
(void)xbps_callback_array_iter_in_dict(d, "missing_deps",
show_missing_dep_cb, NULL);
}
static int
show_missing_dep_cb(prop_object_t obj, void *arg, bool *loop_done)
{
const char *pkgname, *version;
(void)arg;
(void)loop_done;
prop_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname);
prop_dictionary_get_cstring_nocopy(obj, "version", &version);
if (pkgname && version) {
printf(" * Missing binary package for: %s >= %s\n",
pkgname, version);
return 0;
}
return EINVAL;
}
static int
check_pkg_hashes(prop_object_iterator_t iter)
{
prop_object_t obj;
const char *pkgname, *repoloc, *filename;
int rv = 0;
pkg_state_t state = 0;
printf("Checking binary package file(s) integrity...\n");
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, "filename", &filename);
rv = xbps_check_pkg_file_hash(obj, repoloc);
if (rv != 0 && rv != ERANGE) {
printf("Unexpected error while checking hash for "
"%s (%s)\n", filename, strerror(rv));
return -1;
} else if (rv != 0 && rv == ERANGE) {
printf("Hash mismatch for %s, exiting.\n",
filename);
return -1;
}
}
prop_object_iterator_reset(iter);
return 0;
}
static void
show_package_list(prop_object_iterator_t iter, const char *match)
{
prop_object_t obj;
size_t cols = 0;
const char *pkgname, *version, *tract;
bool first = false;
while ((obj = prop_object_iterator_next(iter)) != NULL) {
prop_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname);
prop_dictionary_get_cstring_nocopy(obj, "version", &version);
prop_dictionary_get_cstring_nocopy(obj, "trans-action", &tract);
if (strcmp(match, tract))
continue;
cols += strlen(pkgname) + strlen(version) + 4;
if (cols <= 80) {
if (first == false) {
printf(" ");
first = true;
}
} else {
printf("\n ");
cols = strlen(pkgname) + strlen(version) + 4;
}
printf("%s-%s ", pkgname, version);
}
prop_object_iterator_reset(iter);
}
static int
show_transaction_sizes(prop_object_iterator_t iter)
{
prop_object_t obj;
uint64_t tsize = 0, dlsize = 0, instsize = 0;
const char *tract;
char size[64];
bool trans_inst = false, trans_up = false;
/*
* Iterate over the list of packages that are going to be
* installed and check the file hash.
*/
while ((obj = prop_object_iterator_next(iter)) != NULL) {
prop_dictionary_get_uint64(obj, "filename-size", &tsize);
dlsize += tsize;
tsize = 0;
prop_dictionary_get_uint64(obj, "installed_size", &tsize);
instsize += tsize;
tsize = 0;
}
prop_object_iterator_reset(iter);
while ((obj = prop_object_iterator_next(iter))) {
prop_dictionary_get_cstring_nocopy(obj, "trans-action", &tract);
if (strcmp(tract, "install") == 0)
trans_inst = true;
else if (strcmp(tract, "update") == 0)
trans_up = true;
}
prop_object_iterator_reset(iter);
/*
* Show the list of packages that will be installed.
*/
if (trans_inst) {
printf("The following packages will be installed:\n\n");
show_package_list(iter, "install");
printf("\n\n");
}
if (trans_up) {
printf("The following packages will be updated:\n\n");
show_package_list(iter, "update");
printf("\n\n");
}
/*
* Show total download/installed size for all required packages.
*/
if (xbps_humanize_number(size, 5, (int64_t)dlsize,
"", HN_AUTOSCALE, HN_NOSPACE) == -1) {
printf("error: humanize_number returns %s\n",
strerror(errno));
return -1;
}
printf("Total download size: %s\n", size);
if (xbps_humanize_number(size, 5, (int64_t)instsize,
"", HN_AUTOSCALE, HN_NOSPACE) == -1) {
printf("error: humanize_number2 returns %s\n",
strerror(errno));
return -1;
}
printf("Total installed size: %s\n\n", size);
return 0;
}
void
xbps_install_pkg(const char *pkg, bool force, bool update)
{
struct transaction *trans;
prop_dictionary_t pkgd;
prop_array_t array;
int rv = 0;
/*
* Find all required pkgs and sort the package transaction.
*/
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);
if (rv != 0 && rv == EAGAIN) {
printf("unable to locate %s in repository pool.", pkg);
cleanup(rv);
} else if (rv != 0 && rv != ENOENT) {
printf("unexpected error: %s", strerror(rv));
cleanup(rv);
}
}
trans = calloc(1, sizeof(struct transaction));
if (trans == NULL)
goto out;
trans->dict = xbps_get_pkg_props();
if (trans->dict == NULL) {
printf("error: unexistent props dictionary!\n");
goto out1;
}
/*
* Bail out if there are unresolved deps.
*/
array = prop_dictionary_get(trans->dict, "missing_deps");
if (prop_array_count(array) > 0) {
show_missing_deps(trans->dict, pkg);
goto out2;
}
prop_dictionary_get_cstring_nocopy(trans->dict,
"origin", &trans->originpkgname);
/*
* It's time to run the transaction!
*/
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;
}
trans->force = force;
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, *tract;
int rv = 0;
bool essential, isdep, autoinst;
pkg_state_t state = 0;
assert(trans != NULL);
assert(trans->dict != NULL);
assert(trans->iter != NULL);
essential = isdep = autoinst = false;
/*
* Show download/installed size for the transaction.
*/
rv = show_transaction_sizes(trans->iter);
if (rv != 0)
return rv;
/*
* Ask interactively (if -f not set).
*/
if (trans->force == false) {
if (xbps_noyes("Do you want to continue?") == false) {
printf("Aborting!\n");
return 0;
}
}
/*
* Check the SHA256 hash for all required packages.
*/
if ((rv = check_pkg_hashes(trans->iter)) != 0)
return rv;
/*
* Iterate over the transaction dictionary.
*/
while ((obj = prop_object_iterator_next(trans->iter)) != NULL) {
prop_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname);
prop_dictionary_get_cstring_nocopy(obj, "version", &version);
prop_dictionary_get_bool(obj, "essential", &essential);
prop_dictionary_get_cstring_nocopy(obj, "filename", &filename);
prop_dictionary_get_cstring_nocopy(obj, "trans-action", &tract);
if (trans->originpkgname &&
strcmp(trans->originpkgname, pkgname))
isdep = true;
/*
* If dependency is already unpacked skip this phase.
*/
state = 0;
if (xbps_get_pkg_state_dictionary(obj, &state) != 0)
return EINVAL;
if (state == XBPS_PKG_STATE_UNPACKED)
continue;
if (strcmp(tract, "update") == 0) {
instpkgd = xbps_find_pkg_installed_from_plist(pkgname);
if (instpkgd == NULL) {
printf("error: unable to find %s installed "
"dict!\n", pkgname);
return EINVAL;
}
prop_dictionary_get_cstring_nocopy(instpkgd,
"version", &instver);
autoinst = false;
prop_dictionary_get_bool(instpkgd, "automatic-install",
&autoinst);
isdep = autoinst;
prop_object_release(instpkgd);
/*
* 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) {
printf("error: removing %s-%s (%s)\n",
pkgname, instver, strerror(rv));
return rv;
}
}
}
/*
* Unpack binary package.
*/
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,
version, strerror(rv));
return rv;
}
/*
* Register binary package.
*/
if ((rv = xbps_register_pkg(obj, isdep)) != 0) {
printf("error: registering %s-%s! (%s)\n",
pkgname, version, strerror(rv));
return rv;
}
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;
}
prop_object_iterator_reset(trans->iter);
/*
* Configure all unpacked packages.
*/
while ((obj = prop_object_iterator_next(trans->iter)) != NULL) {
prop_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname);
if ((rv = xbps_configure_pkg(pkgname)) != 0) {
printf("Error configuring package %s (%s)\n",
pkgname, strerror(rv));
return rv;
}
}
return 0;
}
void
xbps_autoupdate_pkgs(bool force)
{
struct transaction *trans;
int rv = 0;
/*
* Find new package versions.
*/
if ((rv = xbps_find_new_packages()) != 0) {
if (rv == ENOENT) {
printf("No packages currently registered.\n");
cleanup(0);
}
goto out;
}
/*
* Prepare transaction data.
*/
trans = calloc(1, sizeof(struct transaction));
if (trans == NULL)
goto out;
/*
* Get package transaction dictionary.
*/
trans->dict = xbps_get_pkg_props();
if (trans->dict == NULL) {
if (errno == 0) {
printf("All packages are up-to-date.\n");
goto out;
}
printf("Error while checking for new pkgs: %s\n",
strerror(errno));
goto out1;
}
/*
* Sort the package transaction dictionary.
*/
if ((rv = xbps_sort_pkg_deps(trans->dict)) != 0) {
printf("Error while sorting packages: %s\n",
strerror(rv));
goto out2;
}
/*
* It's time to run the transaction!
*/
trans->iter = xbps_get_array_iter_from_dict(trans->dict, "packages");
if (trans->iter == NULL) {
printf("error: allocating array mem! (%s)\n", strerror(errno));
goto out2;
}
trans->force = force;
rv = exec_transaction(trans);
prop_object_iterator_release(trans->iter);
out2:
prop_object_release(trans->dict);
out1:
free(trans);
out:
cleanup(rv);
}
static void
cleanup(int rv)
{
xbps_release_repolist_data();
xbps_release_regpkgdb_dict();
exit(rv == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}

276
bin/xbps-bin/main.c Normal file
View File

@ -0,0 +1,276 @@
/*-
* Copyright (c) 2008-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 <xbps_api.h>
#include "defs.h"
#include "../xbps-repo/util.h"
static void usage(void);
static int list_pkgs_in_dict(prop_object_t, void *, bool *);
static void
usage(void)
{
printf("Usage: xbps-bin [options] [target] [arguments]\n\n"
" Available targets:\n"
" autoremove, autoupdate, check, files, install, list\n"
" purge, remove, show, update\n"
" Targets with arguments:\n"
" check\t<pkgname>\n"
" files\t<pkgname>\n"
" install\t<pkgname>\n"
" purge\t[<pkgname>|<all>]\n"
" reconfigure\t[<pkgname>|<all>]\n"
" remove\t<pkgname>\n"
" show\t<pkgname>\n"
" update\t<pkgname>\n"
" Options shared by all targets:\n"
" -r\t\t<rootdir>\n"
" -v\t\t<verbose>\n"
" Options used by the (auto)remove and install target:\n"
" -f\t\tForce installation or removal of packages.\n"
" \t\tBeware with this option if you use autoremove!\n"
"\n");
exit(EXIT_FAILURE);
}
static int
list_pkgs_in_dict(prop_object_t obj, void *arg, bool *loop_done)
{
const char *pkgname, *version, *short_desc;
(void)arg;
(void)loop_done;
assert(prop_object_type(obj) == PROP_TYPE_DICTIONARY);
prop_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname);
prop_dictionary_get_cstring_nocopy(obj, "version", &version);
prop_dictionary_get_cstring_nocopy(obj, "short_desc", &short_desc);
if (pkgname && version && short_desc) {
printf("%s-%s\t%s\n", pkgname, version, short_desc);
return 0;
}
return EINVAL;
}
int
main(int argc, char **argv)
{
prop_dictionary_t dict;
prop_object_t obj;
prop_object_iterator_t iter;
const char *curpkgname;
int c, flags = 0, rv = 0;
bool force = false, verbose = false;
while ((c = getopt(argc, argv, "Cfr:v")) != -1) {
switch (c) {
case 'f':
flags |= XBPS_FLAG_FORCE;
force = true;
break;
case 'r':
/* To specify the root directory */
xbps_set_rootdir(optarg);
break;
case 'v':
verbose = true;
flags |= XBPS_FLAG_VERBOSE;
break;
case '?':
default:
usage();
}
}
argc -= optind;
argv += optind;
if (argc < 1)
usage();
if (flags != 0)
xbps_set_flags(flags);
if ((dict = xbps_prepare_regpkgdb_dict()) == NULL) {
if (errno != ENOENT) {
rv = errno;
printf("Couldn't initialized regpkgdb dict: %s\n",
strerror(errno));
goto out;
}
}
if (strcasecmp(argv[0], "list") == 0) {
/* Lists packages currently registered in database. */
if (argc != 1)
usage();
if (dict == NULL) {
printf("No packages currently installed.\n");
goto out;
}
if (!xbps_callback_array_iter_in_dict(dict, "packages",
list_pkgs_in_dict, NULL)) {
rv = errno;
goto out;
}
} else if (strcasecmp(argv[0], "install") == 0) {
/* Installs a binary package and required deps. */
if (argc != 2)
usage();
xbps_install_pkg(argv[1], force, false);
} else if (strcasecmp(argv[0], "update") == 0) {
/* Update an installed package. */
if (argc != 2)
usage();
xbps_install_pkg(argv[1], force, true);
} else if (strcasecmp(argv[0], "remove") == 0) {
/* Removes a binary package. */
if (argc != 2)
usage();
xbps_remove_installed_pkg(argv[1], force);
} else if (strcasecmp(argv[0], "show") == 0) {
/* Shows info about an installed binary package. */
if (argc != 2)
usage();
rv = show_pkg_info_from_metadir(argv[1]);
if (rv != 0) {
printf("Package %s not installed.\n", argv[1]);
exit(EXIT_FAILURE);
}
} else if (strcasecmp(argv[0], "files") == 0) {
/* Shows files installed by a binary package. */
if (argc != 2)
usage();
rv = show_pkg_files_from_metadir(argv[1]);
if (rv != 0) {
printf("Package %s not installed.\n", argv[1]);
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) {
/*
* To update all packages currently installed.
*/
if (argc != 1)
usage();
xbps_autoupdate_pkgs(force);
} else if (strcasecmp(argv[0], "autoremove") == 0) {
/*
* Removes orphan pkgs. These packages were installed
* as dependency and any installed package does not depend
* on it currently.
*/
if (argc != 1)
usage();
xbps_autoremove_pkgs();
} else if (strcasecmp(argv[0], "purge") == 0) {
/*
* Purge a package completely.
*/
if (argc != 2)
usage();
if (strcasecmp(argv[1], "all") == 0) {
iter = xbps_get_array_iter_from_dict(dict, "packages");
if (iter == NULL)
goto out;
while ((obj = prop_object_iterator_next(iter))) {
prop_dictionary_get_cstring_nocopy(obj,
"pkgname", &curpkgname);
if ((rv = xbps_purge_pkg(curpkgname)) != 0)
break;
}
prop_object_iterator_release(iter);
} else {
rv = xbps_purge_pkg(argv[1]);
}
} else if (strcasecmp(argv[0], "reconfigure") == 0) {
/*
* Reconfigure a package.
*/
if (argc != 2)
usage();
if (strcasecmp(argv[1], "all") == 0) {
iter = xbps_get_array_iter_from_dict(dict, "packages");
if (iter == NULL)
goto out;
while ((obj = prop_object_iterator_next(iter))) {
prop_dictionary_get_cstring_nocopy(obj,
"pkgname", &curpkgname);
if ((rv = xbps_configure_pkg(curpkgname)) != 0)
break;
}
prop_object_iterator_release(iter);
} else {
rv = xbps_configure_pkg(argv[1]);
}
} else {
usage();
}
out:
xbps_release_regpkgdb_dict();
if (rv != 0)
exit(EXIT_FAILURE);
exit(EXIT_SUCCESS);
}

162
bin/xbps-bin/remove.c Normal file
View File

@ -0,0 +1,162 @@
/*-
* Copyright (c) 2008-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 <xbps_api.h>
#include "defs.h"
#include "../xbps-repo/util.h"
void
xbps_autoremove_pkgs(void)
{
prop_array_t orphans;
prop_object_t obj;
prop_object_iterator_t iter;
const char *pkgname, *version;
size_t cols = 0;
int rv = 0;
bool first = false;
/*
* Removes orphan pkgs. These packages were installed
* as dependency and any installed package does not depend
* on it currently.
*/
orphans = xbps_find_orphan_packages();
if (orphans == NULL)
exit(EXIT_FAILURE);
if (orphans != NULL && prop_array_count(orphans) == 0) {
printf("There are not orphaned packages currently.\n");
exit(EXIT_SUCCESS);
}
iter = prop_array_iterator(orphans);
if (iter == NULL)
goto out;
printf("The following packages were installed automatically\n"
"(as dependencies) and aren't needed anymore:\n\n");
while ((obj = prop_object_iterator_next(iter)) != NULL) {
prop_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname);
prop_dictionary_get_cstring_nocopy(obj, "version", &version);
cols += strlen(pkgname) + strlen(version) + 4;
if (cols <= 80) {
if (first == false) {
printf(" ");
first = true;
}
} else {
printf("\n ");
cols = strlen(pkgname) + strlen(version) + 4;
}
printf("%s-%s ", pkgname, version);
}
prop_object_iterator_reset(iter);
printf("\n\n");
if (xbps_noyes("Do you want to remove them?") == false) {
printf("Cancelled!\n");
goto out2;
}
while ((obj = prop_object_iterator_next(iter)) != NULL) {
prop_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname);
prop_dictionary_get_cstring_nocopy(obj, "version", &version);
printf("Removing package %s-%s ...\n", pkgname, version);
if ((rv = xbps_remove_pkg(pkgname, version, false)) != 0)
goto out2;
}
out2:
prop_object_iterator_release(iter);
out:
prop_object_release(orphans);
if (rv != 0)
exit(EXIT_FAILURE);
exit(EXIT_SUCCESS);
}
void
xbps_remove_installed_pkg(const char *pkgname, bool force)
{
prop_array_t reqby;
prop_dictionary_t dict;
const char *version;
int rv = 0;
/*
* First check if package is required by other packages.
*/
dict = xbps_find_pkg_installed_from_plist(pkgname);
if (dict == NULL) {
printf("Package %s is not installed.\n", pkgname);
goto out;
}
prop_dictionary_get_cstring_nocopy(dict, "version", &version);
reqby = prop_dictionary_get(dict, "requiredby");
if (reqby != NULL && prop_array_count(reqby) > 0) {
printf("WARNING! %s-%s is required by the following "
"packages:\n\n", pkgname, version);
(void)xbps_callback_array_iter_in_dict(dict,
"requiredby", list_strings_in_array, NULL);
printf("\n\n");
if (!force) {
if (!xbps_noyes("Do you want to remove %s?", pkgname)) {
printf("Cancelling!\n");
goto out;
}
}
printf("Forcing %s-%s for deletion!\n", pkgname, version);
} else {
if (!force) {
if (!xbps_noyes("Do you want to remove %s?", pkgname)) {
printf("Cancelling!\n");
goto out;
}
}
}
printf("Removing package %s-%s ...\n", pkgname, version);
if ((rv = xbps_remove_pkg(pkgname, version, false)) != 0) {
printf("Unable to remove %s-%s (%s).\n",
pkgname, version, strerror(errno));
goto out;
}
out:
xbps_release_regpkgdb_dict();
if (rv != 0)
exit(EXIT_FAILURE);
exit(EXIT_SUCCESS);
}

4
bin/xbps-cmpver/Makefile Normal file
View File

@ -0,0 +1,4 @@
BIN = xbps-cmpver
TOPDIR = ../..
include $(TOPDIR)/prog.mk

19
bin/xbps-cmpver/main.c Normal file
View File

@ -0,0 +1,19 @@
/*
* Compare package and version strings
* @ 2008
* Author: pancake <youterm.com>
*/
#include <xbps_api.h>
int main(int argc, char **argv)
{
if (argc < 3) {
printf("Usage: xbps-cmpver [installed] [required]\n");
printf(" xbps-cmpver foo-1.2 foo-2.2 # $? = 1\n");
printf(" xbps-cmpver foo-1.2 foo-1.1.0 # $? = 0\n");
printf(" xbps-cmpver foo-1.2 foo-1.2 # $? = 0\n");
return 1;
}
return xbps_cmpver(argv[1], argv[2]);
}

4
bin/xbps-digest/Makefile Normal file
View File

@ -0,0 +1,4 @@
BIN = xbps-digest
TOPDIR = ../..
include $(TOPDIR)/prog.mk

76
bin/xbps-digest/main.c Normal file
View File

@ -0,0 +1,76 @@
/*-
* Copyright (c) 2008 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 <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <xbps_api.h>
static void
usage(void)
{
fprintf(stderr, "usage: xbps-digest <file> <file1+N> ...\n");
exit(EXIT_FAILURE);
}
int
main(int argc, char **argv)
{
SHA256_CTX ctx;
uint8_t buffer[BUFSIZ * 20], *digest;
ssize_t bytes;
int i, fd;
if (argc < 2)
usage();
for (i = 1; i < argc; i++) {
if ((fd = open(argv[i], O_RDONLY)) == -1) {
printf("xbps-digest: cannot open %s (%s)\n", argv[i],
strerror(errno));
exit(EXIT_FAILURE);
}
digest = malloc(SHA256_DIGEST_STRING_LENGTH);
if (digest == NULL) {
printf("xbps-digest: malloc failed (%s)\n",
strerror(errno));
exit(EXIT_FAILURE);
}
SHA256_Init(&ctx);
while ((bytes = read(fd, buffer, sizeof(buffer))) > 0)
SHA256_Update(&ctx, buffer, (size_t)bytes);
printf("%s\n", SHA256_End(&ctx, digest));
free(digest);
close(fd);
}
exit(EXIT_SUCCESS);
}

4
bin/xbps-pkgdb/Makefile Normal file
View File

@ -0,0 +1,4 @@
BIN = xbps-pkgdb
TOPDIR = ../..
include $(TOPDIR)/prog.mk

246
bin/xbps-pkgdb/main.c Normal file
View File

@ -0,0 +1,246 @@
/*-
* Copyright (c) 2008-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 <xbps_api.h>
static void
write_plist_file(prop_dictionary_t dict, const char *file)
{
assert(dict != NULL || file != NULL);
if (!prop_dictionary_externalize_to_file(dict, file)) {
prop_object_release(dict);
printf("=> ERROR: couldn't write to %s (%s)",
file, strerror(errno));
exit(EXIT_FAILURE);
}
}
static void
usage(void)
{
printf("usage: xbps-pkgdb [options] [action] [args]\n"
"\n"
" Available actions:\n"
" getpkgname, getpkgrevision, getpkgversion, register\n"
" sanitize-plist, unregister, version\n"
"\n"
" Action arguments:\n"
" getpkgname\t\t<string>\n"
" getpkgrevision\t<string>\n"
" getpkgversion\t<string>\n"
" register\t\t<pkgname> <version> <shortdesc>\n"
" sanitize-plist\t<plist>\n"
" unregister\t\t<pkgname> <version>\n"
" version\t\t<pkgname>\n"
"\n"
" Options shared by all actions:\n"
" -r\t\t\t<rootdir>\n"
"\n"
" Options used by the register action:\n"
" -a\t\t\tSet automatic installation flag.\n"
"\n"
" Examples:\n"
" $ xbps-pkgdb getpkgname foo-2.0\n"
" $ xbps-pkgdb getpkgrevision foo-2.0_1\n"
" $ xbps-pkgdb getpkgversion foo-2.0\n"
" $ xbps-pkgdb register pkgname 2.0 \"A short description\"\n"
" $ xbps-pkgdb sanitize-plist /blah/foo.plist\n"
" $ xbps-pkgdb unregister pkgname 2.0\n"
" $ xbps-pkgdb version pkgname\n");
exit(EXIT_FAILURE);
}
int
main(int argc, char **argv)
{
prop_dictionary_t dict;
const char *version;
char *plist, *pkgname, *in_chroot_env, *root = NULL;
bool automatic = false, in_chroot = false;
int c, rv = 0;
while ((c = getopt(argc, argv, "ar:")) != -1) {
switch (c) {
case 'a':
/* Set automatic install flag */
automatic = true;
break;
case 'r':
/* To specify the root directory */
root = strdup(optarg);
if (root == NULL)
exit(EXIT_FAILURE);
xbps_set_rootdir(root);
break;
case '?':
default:
usage();
}
}
argc -= optind;
argv += optind;
if (argc < 1)
usage();
plist = xbps_xasprintf("%s/%s/%s", root, XBPS_META_PATH, XBPS_REGPKGDB);
if (plist == NULL) {
printf("=> ERROR: couldn't find regpkdb file (%s)\n",
strerror(errno));
exit(EXIT_FAILURE);
}
in_chroot_env = getenv("in_chroot");
if (in_chroot_env != NULL)
in_chroot = true;
if (strcasecmp(argv[0], "register") == 0) {
/* Registers a package into the database */
if (argc != 4)
usage();
dict = prop_dictionary_create();
if (dict == NULL)
exit(EXIT_FAILURE);
prop_dictionary_set_cstring_nocopy(dict, "pkgname", argv[1]);
prop_dictionary_set_cstring_nocopy(dict, "version", argv[2]);
prop_dictionary_set_cstring_nocopy(dict, "short_desc", argv[3]);
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) {
printf("%s=> %s-%s already registered.\n",
in_chroot ? "[chroot] " : "", argv[1], argv[2]);
} else if (rv != 0) {
printf("%s=> couldn't register %s-%s (%s).\n",
in_chroot ? "[chroot] " : "" , argv[1], argv[2],
strerror(rv));
} else {
printf("%s=> %s-%s registered successfully.\n",
in_chroot ? "[chroot] " : "", argv[1], argv[2]);
}
} else if (strcasecmp(argv[0], "unregister") == 0) {
/* Unregisters a package from the database */
if (argc != 3)
usage();
rv = xbps_remove_pkg_dict_from_file(argv[1], plist);
if (rv == ENOENT) {
printf("=> ERROR: %s not registered in database.\n",
argv[1]);
} else if (rv != 0) {
printf("=> ERROR: couldn't unregister %s "
"from database (%s)\n", argv[1], strerror(rv));
exit(EXIT_FAILURE);
}
printf("%s=> %s-%s unregistered successfully.\n",
in_chroot ? "[chroot] " : "", argv[1], argv[2]);
} else if (strcasecmp(argv[0], "version") == 0) {
/* Prints version of an installed package */
if (argc != 2)
usage();
dict = xbps_find_pkg_from_plist(plist, argv[1]);
if (dict == NULL)
exit(EXIT_FAILURE);
if (!prop_dictionary_get_cstring_nocopy(dict, "version",
&version))
exit(EXIT_FAILURE);
printf("%s\n", version);
prop_object_release(dict);
} else if (strcasecmp(argv[0], "sanitize-plist") == 0) {
/* Sanitize a plist file (properly indent the file) */
if (argc != 2)
usage();
dict = prop_dictionary_internalize_from_file(argv[1]);
if (dict == NULL) {
printf("=> ERROR: couldn't sanitize %s plist file "
"(%s)\n", argv[1], strerror(errno));
exit(EXIT_FAILURE);
}
write_plist_file(dict, argv[1]);
} else if (strcasecmp(argv[0], "getpkgversion") == 0) {
/* Returns the version of a pkg string */
if (argc != 2)
usage();
version = xbps_get_pkg_version(argv[1]);
if (version == NULL) {
printf("Invalid string, expected <string>-<version>\n");
exit(EXIT_FAILURE);
}
printf("%s\n", version);
} else if (strcasecmp(argv[0], "getpkgname") == 0) {
/* Returns the name of a pkg string */
if (argc != 2)
usage();
pkgname = xbps_get_pkg_name(argv[1]);
if (pkgname == NULL) {
printf("Invalid string, expected <string>-<version>\n");
exit(EXIT_FAILURE);
}
printf("%s\n", pkgname);
free(pkgname);
} else if (strcasecmp(argv[0], "getpkgrevision") == 0) {
/* Returns the revision of a pkg string */
if (argc != 2)
usage();
version = xbps_get_pkg_revision(argv[1]);
if (version == NULL)
exit(EXIT_SUCCESS);
printf("%s\n", version);
} else {
usage();
}
exit(EXIT_SUCCESS);
}

5
bin/xbps-repo/Makefile Normal file
View File

@ -0,0 +1,5 @@
BIN = xbps-repo
OBJS = main.o util.o index.o
TOPDIR = ../..
include $(TOPDIR)/prog.mk

289
bin/xbps-repo/index.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 <errno.h>
#include <dirent.h>
#include <sys/utsname.h>
#include <sys/stat.h>
#include <xbps_api.h>
#include "index.h"
/* Array of valid architectures */
static const char *archdirs[] = { "i686", "x86_64", "noarch", NULL };
static prop_dictionary_t
repoidx_getdict(const char *pkgdir)
{
prop_dictionary_t dict;
prop_array_t array;
char *plist;
plist = xbps_get_pkg_index_plist(pkgdir);
if (plist == NULL)
return NULL;
dict = prop_dictionary_internalize_from_file(plist);
if (dict == NULL) {
dict = prop_dictionary_create();
if (dict == NULL)
goto out;
array = prop_array_create();
if (array == NULL) {
prop_object_release(dict);
goto out;
}
prop_dictionary_set(dict, "packages", array);
prop_object_release(array);
prop_dictionary_set_cstring_nocopy(dict,
"location-local", pkgdir);
prop_dictionary_set_cstring_nocopy(dict,
"pkgindex-version", XBPS_PKGINDEX_VERSION);
}
out:
free(plist);
return dict;
}
static int
repoidx_addpkg(const char *file, const char *filename, const char *pkgdir)
{
prop_dictionary_t newpkgd, idxdict, curpkgd;
prop_array_t pkgar;
struct archive *ar;
struct archive_entry *entry;
struct stat st;
const char *pkgname, *version, *regver;
char *sha256, *plist;
int rv = 0;
ar = archive_read_new();
if (ar == NULL) {
rv = errno;
goto out;
}
/* Enable support for tar format and all compression methods */
archive_read_support_compression_all(ar);
archive_read_support_format_tar(ar);
if ((rv = archive_read_open_filename(ar, file,
ARCHIVE_READ_BLOCKSIZE)) == -1) {
rv = errno;
goto out1;
}
/* Get existing or create repo index dictionary */
idxdict = repoidx_getdict(pkgdir);
if (idxdict == NULL) {
rv = errno;
goto out1;
}
plist = xbps_get_pkg_index_plist(pkgdir);
if (plist == NULL) {
prop_dictionary_remove(idxdict, "packages");
rv = ENOMEM;
goto out2;
}
/*
* Open the binary package and read the props.plist
* into a buffer.
*/
while (archive_read_next_header(ar, &entry) == ARCHIVE_OK) {
if (strstr(archive_entry_pathname(entry), XBPS_PKGPROPS) == 0) {
archive_read_data_skip(ar);
continue;
}
newpkgd = xbps_read_dict_from_archive_entry(ar, entry);
if (newpkgd == NULL) {
printf("%s: can't read %s metadata file, skipping!\n",
file, XBPS_PKGPROPS);
break;
}
prop_dictionary_get_cstring_nocopy(newpkgd, "pkgname",
&pkgname);
prop_dictionary_get_cstring_nocopy(newpkgd, "version",
&version);
/*
* Check if this package exists already in the index, but first
* checking the version. If current package version is greater
* than current registered package, update the index; otherwise
* pass to the next one.
*/
curpkgd = xbps_find_pkg_in_dict(idxdict, "packages", pkgname);
if (curpkgd) {
prop_dictionary_get_cstring_nocopy(curpkgd,
"version", &regver);
if (xbps_cmpver(version, regver) <= 0) {
printf("Skipping %s. Version %s already "
"registered.\n", filename, regver);
prop_object_release(newpkgd);
archive_read_data_skip(ar);
break;
}
/*
* Current package is newer than the one that is
* registered actually, remove old package from
* the index.
*/
rv = xbps_remove_pkg_from_dict(idxdict,
"packages", pkgname);
if (rv != 0) {
prop_object_release(newpkgd);
break;
}
}
/*
* We have the dictionary now, add the required
* objects for the index.
*/
prop_dictionary_set_cstring_nocopy(newpkgd, "filename",
filename);
sha256 = xbps_get_file_hash(file);
if (sha256 == NULL) {
prop_object_release(newpkgd);
rv = errno;
break;
}
prop_dictionary_set_cstring(newpkgd, "filename-sha256",
sha256);
free(sha256);
if (stat(file, &st) == -1) {
prop_object_release(newpkgd);
rv = errno;
break;
}
prop_dictionary_set_uint64(newpkgd, "filename-size",
(uint64_t)st.st_size);
/*
* Add dictionary into the index and update package count.
*/
pkgar = prop_dictionary_get(idxdict, "packages");
if (pkgar == NULL) {
prop_object_release(newpkgd);
rv = errno;
break;
}
if (!xbps_add_obj_to_array(pkgar, newpkgd)) {
prop_object_release(newpkgd);
rv = EINVAL;
break;
}
prop_dictionary_set_uint64(idxdict, "total-pkgs",
prop_array_count(pkgar));
if (!prop_dictionary_externalize_to_file(idxdict, plist)) {
rv = errno;
break;
}
printf("Registered %s-%s in package index.\n",
pkgname, version);
break;
}
free(plist);
out2:
prop_object_release(idxdict);
out1:
archive_read_finish(ar);
out:
return rv;
}
int
xbps_repo_genindex(const char *pkgdir)
{
struct dirent *dp;
DIR *dirp;
struct utsname un;
char *binfile, *path;
size_t i;
int rv = 0;
bool foundpkg = false;
if (uname(&un) == -1)
return errno;
/*
* Iterate over the known architecture directories to find
* binary packages.
*/
for (i = 0; archdirs[i] != NULL; i++) {
if ((strcmp(archdirs[i], un.machine)) &&
(strcmp(archdirs[i], "noarch")))
continue;
path = xbps_xasprintf("%s/%s", pkgdir, archdirs[i]);
if (path == NULL)
return errno;
dirp = opendir(path);
if (dirp == NULL) {
free(path);
continue;
}
while ((dp = readdir(dirp)) != NULL) {
if ((strcmp(dp->d_name, ".") == 0) ||
(strcmp(dp->d_name, "..") == 0))
continue;
/* Ignore unknown files */
if (strstr(dp->d_name, ".xbps") == NULL)
continue;
foundpkg = true;
binfile = xbps_xasprintf("%s/%s", path, dp->d_name);
if (binfile == NULL) {
(void)closedir(dirp);
free(path);
return errno;
}
rv = repoidx_addpkg(binfile, dp->d_name, pkgdir);
free(binfile);
if (rv != 0) {
(void)closedir(dirp);
free(path);
return rv;
}
}
(void)closedir(dirp);
free(path);
}
if (foundpkg == false)
rv = ENOENT;
return rv;
}

31
bin/xbps-repo/index.h Normal file
View File

@ -0,0 +1,31 @@
/*-
* 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.
*/
#ifndef _XBPS_REPO_INDEX_H_
#define _XBPS_REPO_INDEX_H_
int xbps_repo_genindex(const char *);
#endif /* !_XBPS_REPO_INDEX_H_ */

288
bin/xbps-repo/main.c Normal file
View File

@ -0,0 +1,288 @@
/*-
* Copyright (c) 2008-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 <libgen.h>
#include <xbps_api.h>
#include "index.h"
#include "util.h"
typedef struct repository_info {
const char *index_version;
const char *location_local;
const char *location_remote;
uint64_t total_pkgs;
} repo_info_t;
static bool sanitize_localpath(char *, const char *);
static bool pkgindex_getinfo(prop_dictionary_t, repo_info_t *);
static void usage(void);
static void
usage(void)
{
printf("Usage: xbps-repo [options] [action] [arguments]\n\n"
" Available actions:\n"
" add, genindex, list, remove, search, show\n"
" Actions with arguments:\n"
" add\t\t<URI>\n"
" genindex\t<path>\n"
" remove\t<URI>\n"
" search\t<string>\n"
" show\t<pkgname>\n"
" Options shared by all actions:\n"
" -r\t\t<rootdir>\n"
"\n"
" Examples:\n"
" $ xbps-repo add /path/to/directory\n"
" $ xbps-repo add http://www.location.org/xbps-repo\n"
" $ xbps-repo list\n"
" $ xbps-repo remove /path/to/directory\n"
" $ xbps-repo search klibc\n"
" $ xbps-repo show klibc\n"
" $ xbps-repo genindex /path/to/packages/dir\n");
exit(EXIT_FAILURE);
}
static bool
pkgindex_getinfo(prop_dictionary_t dict, repo_info_t *ri)
{
assert(dict != NULL || ri != NULL);
if (!prop_dictionary_get_cstring_nocopy(dict,
"pkgindex-version", &ri->index_version))
return false;
if (!prop_dictionary_get_cstring_nocopy(dict,
"location-local", &ri->location_local))
return false;
/* This one is optional, thus don't panic */
prop_dictionary_get_cstring_nocopy(dict, "location-remote",
&ri->location_remote);
if (!prop_dictionary_get_uint64(dict, "total-pkgs",
&ri->total_pkgs))
return false;
/* Reject empty repositories, how could this happen? :-) */
if (ri->total_pkgs <= 0)
return false;
return true;
}
static bool
sanitize_localpath(char *buf, const char *path)
{
char *dirnp, *basenp, *dir, *base, *tmp;
bool rv = false;
dir = strdup(path);
if (dir == NULL)
return false;
base = strdup(path);
if (base == NULL) {
free(dir);
return false;
}
dirnp = dirname(dir);
if (strcmp(dirnp, ".") == 0)
goto out;
basenp = basename(base);
if (strcmp(basenp, base) == 0)
goto out;
tmp = strncpy(buf, dirnp, PATH_MAX - 1);
if (sizeof(*tmp) >= PATH_MAX)
goto out;
buf[strlen(buf) + 1] = '\0';
if (strcmp(dirnp, "/"))
strncat(buf, "/", 1);
strncat(buf, basenp, PATH_MAX - strlen(buf) - 1);
rv = true;
out:
free(dir);
free(base);
return rv;
}
int
main(int argc, char **argv)
{
prop_dictionary_t dict;
repo_info_t *rinfo = NULL;
char dpkgidx[PATH_MAX], *plist, *root = NULL;
int c, rv = 0;
while ((c = getopt(argc, argv, "r:")) != -1) {
switch (c) {
case 'r':
/* To specify the root directory */
root = optarg;
xbps_set_rootdir(root);
break;
case '?':
default:
usage();
}
}
argc -= optind;
argv += optind;
if (argc < 1)
usage();
if (strcasecmp(argv[0], "add") == 0) {
/* Adds a new repository to the pool. */
if (argc != 2)
usage();
if (!sanitize_localpath(dpkgidx, argv[1]))
exit(EXIT_FAILURE);
/* Temp buffer to verify pkgindex file. */
plist = xbps_get_pkg_index_plist(dpkgidx);
if (plist == NULL)
exit(EXIT_FAILURE);
dict = prop_dictionary_internalize_from_file(plist);
if (dict == NULL) {
printf("Directory %s does not contain any "
"xbps pkgindex file.\n", dpkgidx);
free(plist);
exit(EXIT_FAILURE);
}
rinfo = malloc(sizeof(*rinfo));
if (rinfo == NULL) {
prop_object_release(dict);
free(plist);
exit(EXIT_FAILURE);
}
if (!pkgindex_getinfo(dict, rinfo)) {
printf("'%s' is incomplete.\n", plist);
prop_object_release(dict);
free(rinfo);
free(plist);
exit(EXIT_FAILURE);
}
if ((rv = xbps_register_repository(dpkgidx)) != 0) {
printf("ERROR: couldn't register repository (%s)\n",
strerror(rv));
prop_object_release(dict);
free(rinfo);
free(plist);
exit(EXIT_FAILURE);
}
printf("Added repository at %s (%s) with %ju packages.\n",
rinfo->location_local, rinfo->index_version,
rinfo->total_pkgs);
prop_object_release(dict);
free(rinfo);
free(plist);
} else if (strcasecmp(argv[0], "list") == 0) {
/* Lists all repositories registered in pool. */
if (argc != 1)
usage();
(void)xbps_callback_array_iter_in_repolist(
list_strings_sep_in_array, NULL);
} else if ((strcasecmp(argv[0], "rm") == 0) ||
(strcasecmp(argv[0], "remove") == 0)) {
/* Remove a repository from the pool. */
if (argc != 2)
usage();
if (!sanitize_localpath(dpkgidx, argv[1]))
exit(EXIT_FAILURE);
if ((rv = xbps_unregister_repository(dpkgidx)) != 0) {
if (rv == ENOENT)
printf("Repository '%s' not actually "
"registered.\n", dpkgidx);
else
printf("ERROR: couldn't unregister "
"repository (%s)\n", strerror(rv));
exit(EXIT_FAILURE);
}
} else if (strcasecmp(argv[0], "search") == 0) {
/*
* Search for a package by looking at pkgname/short_desc
* by using shell style match patterns (fnmatch(3)).
*/
if (argc != 2)
usage();
(void)xbps_callback_array_iter_in_repolist(
search_string_in_pkgs, argv[1]);
} else if (strcasecmp(argv[0], "show") == 0) {
/* Shows info about a binary package. */
if (argc != 2)
usage();
rv = xbps_callback_array_iter_in_repolist(
show_pkg_info_from_repolist, argv[1]);
if (rv == 0 && errno == ENOENT) {
printf("Unable to locate package '%s' from "
"repository pool.\n", argv[1]);
exit(EXIT_FAILURE);
}
} else if (strcasecmp(argv[0], "genindex") == 0) {
/* Generates a package repository index plist file. */
if (argc != 2)
usage();
rv = xbps_repo_genindex(argv[1]);
exit(rv);
} else {
usage();
}
exit(EXIT_SUCCESS);
}

377
bin/xbps-repo/util.c Normal file
View File

@ -0,0 +1,377 @@
/*-
* Copyright (c) 2008-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 <fnmatch.h>
#include <xbps_api.h>
#include "util.h"
static void show_pkg_info(prop_dictionary_t);
static int show_pkg_namedesc(prop_object_t, void *, bool *);
static void
show_pkg_info(prop_dictionary_t dict)
{
prop_object_t obj;
const char *sep;
char size[64];
int rv = 0;
assert(dict != NULL);
assert(prop_dictionary_count(dict) != 0);
obj = prop_dictionary_get(dict, "pkgname");
if (obj && prop_object_type(obj) == PROP_TYPE_STRING)
printf("Package: %s\n", prop_string_cstring_nocopy(obj));
obj = prop_dictionary_get(dict, "installed_size");
if (obj && prop_object_type(obj) == PROP_TYPE_NUMBER) {
printf("Installed size: ");
rv = xbps_humanize_number(size, 5,
(int64_t)prop_number_unsigned_integer_value(obj),
"", HN_AUTOSCALE, HN_B|HN_DECIMAL|HN_NOSPACE);
if (rv == -1)
printf("%ju\n",
prop_number_unsigned_integer_value(obj));
else
printf("%s\n", size);
}
obj = prop_dictionary_get(dict, "maintainer");
if (obj && prop_object_type(obj) == PROP_TYPE_STRING)
printf("Maintainer: %s\n", prop_string_cstring_nocopy(obj));
obj = prop_dictionary_get(dict, "architecture");
if (obj && prop_object_type(obj) == PROP_TYPE_STRING)
printf("Architecture: %s\n", prop_string_cstring_nocopy(obj));
obj = prop_dictionary_get(dict, "version");
if (obj && prop_object_type(obj) == PROP_TYPE_STRING)
printf("Version: %s\n", prop_string_cstring_nocopy(obj));
obj = prop_dictionary_get(dict, "filename");
if (obj && prop_object_type(obj) == PROP_TYPE_STRING) {
printf("Filename: %s", prop_string_cstring_nocopy(obj));
obj = prop_dictionary_get(dict, "filename-size");
if (obj && prop_object_type(obj) == PROP_TYPE_NUMBER) {
rv = xbps_humanize_number(size, 5,
(int64_t)prop_number_unsigned_integer_value(obj),
"", HN_AUTOSCALE, HN_B|HN_DECIMAL|HN_NOSPACE);
if (rv == -1)
printf(" (size: %ju)\n",
prop_number_unsigned_integer_value(obj));
else
printf(" (size: %s)\n", size);
} else
printf("\n");
}
obj = prop_dictionary_get(dict, "filename-sha256");
if (obj && prop_object_type(obj) == PROP_TYPE_STRING)
printf("SHA256: %s\n", prop_string_cstring_nocopy(obj));
obj = prop_dictionary_get(dict, "run_depends");
if (obj && prop_object_type(obj) == PROP_TYPE_ARRAY) {
printf("Dependencies:\n");
(void)xbps_callback_array_iter_in_dict(dict, "run_depends",
list_strings_in_array, NULL);
printf("\n\n");
}
obj = prop_dictionary_get(dict, "conf_files");
if (obj && prop_object_type(obj) == PROP_TYPE_ARRAY) {
printf("Configuration files:\n");
sep = " ";
(void)xbps_callback_array_iter_in_dict(dict, "conf_files",
list_strings_sep_in_array, __UNCONST(sep));
printf("\n");
}
obj = prop_dictionary_get(dict, "keep_dirs");
if (obj && prop_object_type(obj) == PROP_TYPE_ARRAY) {
printf("Permanent directories:\n");
sep = " ";
(void)xbps_callback_array_iter_in_dict(dict, "keep_dirs",
list_strings_sep_in_array, __UNCONST(sep));
printf("\n");
}
obj = prop_dictionary_get(dict, "short_desc");
if (obj && prop_object_type(obj) == PROP_TYPE_STRING)
printf("Description: %s", prop_string_cstring_nocopy(obj));
obj = prop_dictionary_get(dict, "long_desc");
if (obj && prop_object_type(obj) == PROP_TYPE_STRING)
printf(" %s\n", prop_string_cstring_nocopy(obj));
}
int
search_string_in_pkgs(prop_object_t obj, void *arg, bool *loop_done)
{
prop_dictionary_t dict;
const char *repofile;
char *plist;
(void)loop_done;
assert(prop_object_type(obj) == PROP_TYPE_STRING);
/* Get the location of pkgindex file. */
repofile = prop_string_cstring_nocopy(obj);
assert(repofile != NULL);
plist = xbps_get_pkg_index_plist(repofile);
if (plist == NULL) {
errno = ENOENT;
return 0;
}
dict = prop_dictionary_internalize_from_file(plist);
if (dict == NULL) {
free(plist);
return 0;
}
printf("From %s repository ...\n", repofile);
xbps_callback_array_iter_in_dict(dict, "packages",
show_pkg_namedesc, arg);
prop_object_release(dict);
free(plist);
return 0;
}
int
show_pkg_info_from_metadir(const char *pkgname)
{
prop_dictionary_t pkgd;
const char *rootdir;
char *plist;
rootdir = xbps_get_rootdir();
plist = xbps_xasprintf("%s/%s/metadata/%s/%s", rootdir,
XBPS_META_PATH, pkgname, XBPS_PKGPROPS);
if (plist == NULL)
return EINVAL;
pkgd = prop_dictionary_internalize_from_file(plist);
if (pkgd == NULL) {
free(plist);
return errno;
}
show_pkg_info(pkgd);
prop_object_release(pkgd);
free(plist);
return 0;
}
int
show_pkg_files_from_metadir(const char *pkgname)
{
prop_dictionary_t pkgd;
prop_array_t array;
prop_object_iterator_t iter = NULL;
prop_object_t obj;
const char *destdir, *file;
char *plist, *array_str = "files";
int i, rv = 0;
destdir = xbps_get_rootdir();
plist = xbps_xasprintf("%s/%s/metadata/%s/%s", destdir,
XBPS_META_PATH, pkgname, XBPS_PKGFILES);
if (plist == NULL)
return EINVAL;
pkgd = prop_dictionary_internalize_from_file(plist);
if (pkgd == NULL) {
free(plist);
return errno;
}
free(plist);
/* Links. */
array = prop_dictionary_get(pkgd, "links");
if (array && prop_array_count(array) > 0) {
iter = xbps_get_array_iter_from_dict(pkgd, "links");
if (iter == NULL) {
rv = EINVAL;
goto out;
}
while ((obj = prop_object_iterator_next(iter))) {
prop_dictionary_get_cstring_nocopy(obj, "file", &file);
printf("%s\n", file);
}
prop_object_iterator_release(iter);
}
/* Files and configuration files. */
for (i = 0; i < 2; i++) {
if (i == 0)
array_str = "conf_files";
else
array_str = "files";
array = prop_dictionary_get(pkgd, array_str);
if (array == NULL || prop_array_count(array) == 0)
continue;
iter = xbps_get_array_iter_from_dict(pkgd, array_str);
if (iter == NULL) {
rv = EINVAL;
goto out;
}
while ((obj = prop_object_iterator_next(iter))) {
prop_dictionary_get_cstring_nocopy(obj, "file", &file);
printf("%s\n", file);
}
prop_object_iterator_release(iter);
}
out:
prop_object_release(pkgd);
return rv;
}
int
show_pkg_info_from_repolist(prop_object_t obj, void *arg, bool *loop_done)
{
prop_dictionary_t dict, pkgdict;
prop_string_t oloc;
const char *repofile, *repoloc;
char *plist;
assert(prop_object_type(obj) == PROP_TYPE_STRING);
/* Get the location */
repofile = prop_string_cstring_nocopy(obj);
plist = xbps_get_pkg_index_plist(repofile);
if (plist == NULL)
return EINVAL;
dict = prop_dictionary_internalize_from_file(plist);
if (dict == NULL || prop_dictionary_count(dict) == 0) {
free(plist);
errno = ENOENT;
return 0;
}
pkgdict = xbps_find_pkg_in_dict(dict, "packages", arg);
if (pkgdict == NULL) {
prop_object_release(dict);
free(plist);
errno = ENOENT;
return 0;
}
oloc = prop_dictionary_get(dict, "location-remote");
if (oloc == NULL)
oloc = prop_dictionary_get(dict, "location-local");
if (oloc && prop_object_type(oloc) == PROP_TYPE_STRING)
repoloc = prop_string_cstring_nocopy(oloc);
else {
prop_object_release(dict);
free(plist);
return EINVAL;
}
printf("Repository: %s\n", repoloc);
show_pkg_info(pkgdict);
*loop_done = true;
prop_object_release(dict);
free(plist);
return 0;
}
static int
show_pkg_namedesc(prop_object_t obj, void *arg, bool *loop_done)
{
const char *pkgname, *desc, *ver, *pattern = arg;
(void)loop_done;
assert(prop_object_type(obj) == PROP_TYPE_DICTIONARY);
assert(pattern != NULL);
prop_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname);
prop_dictionary_get_cstring_nocopy(obj, "short_desc", &desc);
prop_dictionary_get_cstring_nocopy(obj, "version", &ver);
assert(ver != NULL);
if ((fnmatch(pattern, pkgname, 0) == 0) ||
(fnmatch(pattern, desc, 0) == 0))
printf(" %s-%s - %s\n", pkgname, ver, desc);
return 0;
}
int
list_strings_in_array(prop_object_t obj, void *arg, bool *loop_done)
{
static size_t cols;
static bool first;
(void)arg;
(void)loop_done;
assert(prop_object_type(obj) == PROP_TYPE_STRING);
cols += strlen(prop_string_cstring_nocopy(obj)) + 4;
if (cols <= 80) {
if (first == false) {
printf(" ");
first = true;
}
} else {
printf("\n ");
cols = strlen(prop_string_cstring_nocopy(obj)) + 4;
}
printf("%s ", prop_string_cstring_nocopy(obj));
return 0;
}
int
list_strings_sep_in_array(prop_object_t obj, void *arg, bool *loop_done)
{
const char *sep = arg;
(void)loop_done;
assert(prop_object_type(obj) == PROP_TYPE_STRING);
printf("%s%s\n", sep ? sep : "", prop_string_cstring_nocopy(obj));
return 0;
}

36
bin/xbps-repo/util.h Normal file
View File

@ -0,0 +1,36 @@
/*-
* Copyright (c) 2008-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.
*/
#ifndef _XBPS_REPO_UTIL_H_
#define _XBPS_REPO_UTIL_H_
int search_string_in_pkgs(prop_object_t, void *, bool *);
int show_pkg_info_from_metadir(const char *);
int show_pkg_files_from_metadir(const char *);
int show_pkg_info_from_repolist(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 *);
#endif /* !_XBPS_REPO_UTIL_H_ */

18
bin/xbps-src/Makefile Normal file
View File

@ -0,0 +1,18 @@
TOPDIR = ../..
include $(TOPDIR)/vars.mk
BIN = xbps-src
.PHONY: all
all:
sed -e "s|@@XBPS_INSTALL_PREFIX@@|$(PREFIX)|g" \
-e "s|@@XBPS_INSTALL_ETCDIR@@|$(ETCDIR)|g" \
main.sh > xbps-src
.PHONY: clean
clean:
-rm -f $(BIN)
install: all
install -d $(SBINDIR)
install -m 755 $(BIN) $(SBINDIR)

291
bin/xbps-src/main.sh Executable file
View File

@ -0,0 +1,291 @@
#!/bin/sh
#
# xbps - A simple, minimal, fast and uncomplete build package system.
#-
# Copyright (c) 2008 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.
#-
trap "echo && exit 1" INT QUIT
: ${XBPS_CONFIG_FILE:=@@XBPS_INSTALL_ETCDIR@@/xbps.conf}
: ${progname:=$(basename $0)}
: ${fakeroot_cmd:=fakeroot}
: ${fetch_cmd:=wget}
: ${xbps_machine:=$(uname -m)}
usage()
{
cat << _EOF
$progname: [-C] [-c <config_file>] [-u] <target> <pkg>
Targets:
build <pkg> Build a package (fetch + extract + configure + build).
build-pkg [<pkg>|all] Build a binary package from <pkg>.
Package must be installed into destdir. If the <all>
keyword is used instead of <pkg>, all packages
currently installed will be used.
chroot Enter to the chroot in masterdir.
configure <pkg> Configure a package (fetch + extract + configure).
extract <pkg> Extract distribution file(s) into build directory.
fetch <pkg> Download distribution file(s).
info <pkg> Show information about <pkg>.
install-destdir <pkg> build + install into destdir.
install <pkg> install-destdir + stow.
list List installed packages in masterdir.
listfiles <pkg> List installed files from <pkg>.
remove <pkg> Remove package completely (destdir + masterdir).
stow <pkg> Copy <pkg> files from destdir into masterdir and
register package in database.
unstow <pkg> Remove <pkg> files from masterdir and unregister
package from database.
Options:
-C Do not remove build directory after successful installation.
-c Path to global configuration file:
if not specified @@XBPS_INSTALL_ETCDIR@@/xbps.conf is used.
-u Update the checksum in template file if used in 'fetch' target.
_EOF
exit 1
}
check_path()
{
eval local orig="$1"
case "$orig" in
/) ;;
/*) orig="${orig%/}" ;;
*) orig="$(pwd)/${orig%/}" ;;
esac
path_fixed="$orig"
}
run_file()
{
local file="$1"
check_path "$file"
. $path_fixed
}
set_defvars()
{
local DDIRS i
: ${XBPS_TEMPLATESDIR:=$XBPS_DISTRIBUTIONDIR/templates}
: ${XBPS_TRIGGERSDIR:=$XBPS_DISTRIBUTIONDIR/triggers}
: ${XBPS_HELPERSDIR:=$XBPS_TEMPLATESDIR/helpers}
: ${XBPS_DBDIR:=$XBPS_MASTERDIR/var/db/xbps}
: ${XBPS_META_PATH:=$XBPS_DBDIR/}
: ${XBPS_PKGMETADIR:=$XBPS_DBDIR/metadata}
: ${XBPS_SHUTILSDIR:=$XBPS_DISTRIBUTIONDIR/shutils}
DDIRS="XBPS_TEMPLATESDIR XBPS_TRIGGERSDIR"
DDIRS="$DDIRS XBPS_HELPERSDIR XBPS_SHUTILSDIR"
for i in ${DDIRS}; do
eval val="\$$i"
[ ! -d "$val" ] && msg_error "cannot find $i, aborting."
done
XBPS_REGPKGDB_CMD="xbps-pkgdb -r $XBPS_MASTERDIR"
XBPS_BIN_CMD="xbps-bin -r $XBPS_MASTERDIR"
}
#
# Checks that all required variables specified in the configuration
# file are properly working.
#
check_config_vars()
{
local cffound=
local f=
if [ -z "$config_file_specified" ]; then
config_file_paths="$XBPS_CONFIG_FILE ./etc/xbps.conf"
for f in $config_file_paths; do
[ -f $f ] && XBPS_CONFIG_FILE=$f && \
cffound=yes && break
done
[ -z "$cffound" ] && msg_error "cannot find a config file"
fi
run_file ${XBPS_CONFIG_FILE}
XBPS_CONFIG_FILE=$path_fixed
if [ ! -f "$XBPS_CONFIG_FILE" ]; then
msg_error "cannot find configuration file: $XBPS_CONFIG_FILE"
fi
local XBPS_VARS="XBPS_MASTERDIR XBPS_DESTDIR XBPS_BUILDDIR \
XBPS_SRCDISTDIR"
for f in ${XBPS_VARS}; do
eval val="\$$f"
[ -z "$val" ] && msg_error "'$f' not set in configuration file"
if [ ! -d "$val" ]; then
mkdir "$val"
[ $? -ne 0 ] && msg_error "couldn't create '$f' directory"
fi
done
export PATH="$PATH:@@XBPS_INSTALL_PREFIX@@/sbin"
}
#
# main()
#
while getopts "Cc:u" opt; do
case $opt in
C) dontrm_builddir=yes;;
c) config_file_specified=yes; XBPS_CONFIG_FILE="$OPTARG";;
u) update_checksum=yes;;
--) shift; break;;
esac
done
shift $(($OPTIND - 1))
[ $# -eq 0 -o $# -gt 2 ] && usage
target="$1"
if [ -z "$target" ]; then
echo "=> ERROR: missing target."
usage
fi
#
# Check configuration vars before anyting else, and set defaults vars.
#
check_config_vars
set_defvars
. $XBPS_SHUTILSDIR/common_funcs.sh
# Main switch
case "$target" in
build|configure)
. $XBPS_SHUTILSDIR/tmpl_funcs.sh
setup_tmpl $2
if [ -z "$base_chroot" -a -z "$in_chroot" ]; then
. $XBPS_SHUTILSDIR/chroot.sh
if [ "$target" = "build" ]; then
xbps_chroot_handler build $2
else
xbps_chroot_handler configure $2
fi
else
. $XBPS_SHUTILSDIR/fetch_funcs.sh
fetch_distfiles $2
if [ ! -f "$XBPS_EXTRACT_DONE" ]; then
. $XBPS_SHUTILSDIR/extract_funcs.sh
extract_distfiles $2
fi
if [ "$target" = "configure" ]; then
. $XBPS_SHUTILSDIR/configure_funcs.sh
configure_src_phase $2
else
if [ ! -f "$XBPS_CONFIGURE_DONE" ]; then
. $XBPS_SHUTILSDIR/configure_funcs.sh
configure_src_phase $2
fi
. $XBPS_SHUTILSDIR/build_funcs.sh
build_src_phase $2
fi
fi
;;
build-pkg)
. $XBPS_SHUTILSDIR/make-binpkg.sh
. $XBPS_SHUTILSDIR/tmpl_funcs.sh
if [ "$2" = "all" ]; then
for f in $($XBPS_BIN_CMD list|awk '{print $1}'); do
pkg=$(xbps-pkgdb getpkgname $f)
setup_tmpl ${pkg}
xbps_make_binpkg ${pkg}
reset_tmpl_vars
done
else
setup_tmpl $2
xbps_make_binpkg $2
fi
;;
chroot)
. $XBPS_SHUTILSDIR/chroot.sh
xbps_chroot_handler chroot dummy
;;
extract|fetch|info)
. $XBPS_SHUTILSDIR/tmpl_funcs.sh
setup_tmpl $2
if [ "$target" = "info" ]; then
. $XBPS_SHUTILSDIR/tmpl_funcs.sh
info_tmpl $2
exit $?
fi
if [ "$target" = "fetch" ]; then
. $XBPS_SHUTILSDIR/fetch_funcs.sh
fetch_distfiles $2 $update_checksum
exit $?
fi
. $XBPS_SHUTILSDIR/extract_funcs.sh
extract_distfiles $2
;;
install|install-destdir)
[ -z "$2" ] && msg_error "missing package name after target."
[ "$target" = "install-destdir" ] && install_destdir_target=yes
. $XBPS_SHUTILSDIR/pkgtarget_funcs.sh
install_pkg $2
;;
list|listfiles)
if [ "$target" = "list" ]; then
$XBPS_BIN_CMD list
exit $?
fi
. $XBPS_SHUTILSDIR/pkgtarget_funcs.sh
list_pkg_files $2
;;
remove)
[ -z "$2" ] && msg_error "missing package name after target."
. $XBPS_SHUTILSDIR/pkgtarget_funcs.sh
remove_pkg $2
;;
stow)
stow_flag=yes
. $XBPS_SHUTILSDIR/tmpl_funcs.sh
setup_tmpl $2
. $XBPS_SHUTILSDIR/stow_funcs.sh
stow_pkg $2
;;
unstow)
. $XBPS_SHUTILSDIR/tmpl_funcs.sh
setup_tmpl $2
. $XBPS_SHUTILSDIR/stow_funcs.sh
unstow_pkg $2
;;
*)
echo "=> ERROR: invalid target: $target."
usage
esac
# Agur
exit $?

105
doc/BINPKG_INFO Normal file
View File

@ -0,0 +1,105 @@
------------------------------------------------------------------------------
BRIEF INTRODUCTION
------------------------------------------------------------------------------
A binary package built with xbps is a normal tar(1) archive, compressed
with bzip2 and has the following structure:
Package metadata
-----------------
/INSTALL
/REMOVE
/files.plist
/props.plist
Package data
-----------------
/usr
/var
/etc
...
Metadata info is stored in the "/var/db/xbps/metadata/$pkgname"
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
will install, as well as SHA256 hashes for files.
The props.plist file contains package metadata properties and has the
following structure:
<dict>
<key>pkgname</key>
<string>foo</string>
<key>version</key>
<string>3.40</string>
<key>maintainer</key>
<string>The Master BOFH <bofh@baobab.org> </string>
<key>short_desc</key>
<string>Foo is a virtual package</string>
<key>long_desc</key>
<string>
Foo is a virtual package to show how the metadata props.plist file works
with xbps handling binary packages.</string>
<key>architecture</key>
<string>x86_64</string>
<key>installed_size</key>
<integer>500000</integer>
<key>configuration_files</key>
<array>
<string>/etc/foo.conf</string>
...
</array>
<key>run_depends</key>
<array>
<string>bofh-2.0</string>
<string>blab-1.1</string>
...
</array>
...
</dict>
The INSTALL/REMOVE executables allows you to trigger any action
at pre/post installation/removal of the binary package.
The package's dictionary will also be written into the repository's package
index file, that describes information about a binary package on it.
See the BINPKG_REPOSITORY file for more info about repositories.
------------------------------------------------------------------------------
HOW TO USE BINARY PACKAGES
------------------------------------------------------------------------------
To install binary packages, firstly a repository must be created as well as
some binary packages for it. The flow for this task is:
1- xbps-src install <package>
2- xbps-src build-pkg all [requires sudo access]
3- xbps-repo genindex $XBPS_PACKAGES
4- xbps-repo add $XBPS_PACKAGES
5- xbps-bin install -r /rootdir <package>
So the tasks are: install the package into destdir (and all its dependencies),
build the binary package from the required package, generate the repository
index, add the repository into the pool and install the binary package.
Please note that by default, the xbps-* utils accept the -r flag, to specify
the root directory for all operations, in that case the package will be
installed into <rootdir> and metadata files into <rootdir>/var/db/xbps.
Don't forget to set this flag if you aren't using xbps as the primary
package manager in your system, otherwise it could overwrite some files!
See the BINPKG_REPOSITORY file for more info about repositories for
binary packages or SRCPKG_INFO for source packages.
------------------------------------------------------------------------------
Juan Romero Pardines <xtraeme@gmail.com>

116
doc/BINPKG_REPOSITORY Normal file
View File

@ -0,0 +1,116 @@
------------------------------------------------------------------------------
BRIEF INTRODUCTION
------------------------------------------------------------------------------
A repository for binary packages contains the packages itself, and
an index file describing the information about available packages.
The structure for this file is just the same than the plist file used
to register installed packages, aka "an array of dictionaries" and
a "dictionary per package". Additional objects are added into the
main dictionary to specify more info, like:
- pkgindex-version: version used to build the index.
- location-local: local path to the repository.
- location-remote: remote URI repository.
- total-pkgs: total of number of available packages.
"location-local" will always be created, and it might be exported via
a remote location specified with "location-remote".
The package dictionary will be the same than the one available in
package's metadata directory "/var/db/xbps/metadata/$pkgname/props.plist",
but some additional objects are added to provide enough info for
the repository itself:
- filename: name (and path relative to current dir) for the binary
package.
- filename-sha256: SHA256 hash of the binary package.
Here's how the package index plist file shall look like in a repository:
<dict>
<key>pkgindex-version</key>
<string>1.0</string>
<key>location-local</key>
<string>/xbps/repo/local</string>
<key>location-remote</key>
<string>http://www.xbps-remote.org/repo/public</string>
<key>total-pkgs</key>
<integer>666</integer>
<key>available-packages</key>
<array>
<dict>
<key>pkgname</key>
<string>klibc</string>
<key>version</key>
<string>1.5.17</string>
<key>filename</key>
<string>klibc-1.5.17.x86_64.xbps</string>
<key>filename-sha256</key>
<string>7b0de0521983037107cc33f2b1514126432f86ac2be1ef9b9dc51a1e959ea777</string>
<key>architecture</key>
<string>x86_64</string>
<key>installed_size</key>
<integer>9471141</integer>
<key>maintainer</key>
<string>Juan RP xtraeme@gmail.com</string>
<key>short_desc</key>
<string>Minimal libc subset for use with initramfs</key>
<key>long_desc</key>
<string>
klibc is intended to be a minimalistic libc subset for use with initramfs.
It is deliberately written for small size, minimal entanglement, and
portability, not speed. It is definitely a work in progress and a lot of
things are still missing.</string>
...
</dict>
...
</array>
</dict>
------------------------------------------------------------------------------
HOW TO USE BINPKGS WITH REPOSITORIES
------------------------------------------------------------------------------
To build binary packages from all currently installed packages in
XBPS_MASTERDIR:
$ xbps-src build-pkg all
To generate the repository package index for your $XBPS_PACKAGESDIR
setting in the configuration file:
$ xbps-repo genindex /path/to/dir
After this you can add your own local repository with binary packages:
$ xbps-repo add /path/to/dir
Added repository at /path/to/dir (1.0) with 6 packages.
$
Once it's registered, you can start searching/installing/removing
binary packages. You can add multiple repositories, the order for searching
is the same than they were added; check it with:
$ xbps-repo list
/storage/xbps/binpkgs
/path/to/dir
$
The first repository that has the metadata for a package wins, if not found
it will search in all them until it's found. A repository can also be
unregistered from the pool:
$ xbps-repo remove /path/to/dir
To show information about available packages in the repository pool:
$ xbps-repo show package
To search for binary packages by specifying a string:
$ xbps-repo search mypkg
------------------------------------------------------------------------------
Juan Romero Pardines <xtraeme@gmail.com>

68
doc/README Normal file
View File

@ -0,0 +1,68 @@
-----------------------------------------------------------------------------
WHAT IS IT?
-----------------------------------------------------------------------------
xbps - xtraeme's build package system.
It is a simple build package system that installs packages inside of
a chroot in a destination directory. Once the package has been installed
into this directory, you can make it appear/unappear at the master directory
at any time. It's in spirit the same than GNU stow, but the files are just
copied (there are no soft/hard links).
xbps has been designed for Linux, and for the moment I'm not interested to
make it work on any other random OS. I've been a NetBSD developer for some
years and I do not want to come back... also the experience has helped to
me to start xbps and not to use pkgsrc, which is very portable but also
not so fast.
-----------------------------------------------------------------------------
REQUIREMENTS
-----------------------------------------------------------------------------
xbps uses proplib, a property container object library and it's almost the
same one available for NetBSD. Be sure to have it installed before using
xbps. You can get it at:
http://code.google.com/p/portableproplib/
I'm also the human maintaining the portable proplib package. I'd suggest you
to install it into /usr/local to avoid issues with your distribution packages.
Additionally the following software is required to be able to build and install
xbps binary/source packages:
* GNU GCC C++
* GNU Make
* fakeroot
* wget
* libarchive (development package)
* perl
* sudo
Super-user privileges are required as well, because all packages are built
in a chroot (except the ones that are included in a virtual package to be
able to build a minimal system for the chroot).
PLEASE NOTE THAT fakechroot or fakeroot-ng DO NOT WORK.
------------------------------------------------------------------------------
HOW TO USE IT
------------------------------------------------------------------------------
Before using xbps, some required utilities need to be built and installed
into $(PREFIX); by default they are installed into /usr/local.
You can do this by issuing "make" and "make install" as root in the top
level directory. See the REQUIREMENTS section above for required packages.
Once the xbps distfiles are installed into prefix, you can start building
packages from source, add local repositories with binary packages, install or
remove them, etc.
If you are only interested in building/using packages from source, see the
SRCPKG_INFO file.
For information about binary packages, see the BINPKG_INFO file.
------------------------------------------------------------------------------
Juan Romero Pardines <xtraeme@gmail.com>

110
doc/SRCPKG_INFO Normal file
View File

@ -0,0 +1,110 @@
-----------------------------------------------------------------------------
REQUIREMENTS
-----------------------------------------------------------------------------
To be able to build packages from source the following software is required
in the host system:
* GNU GCC C++
* GNU Make
* fakeroot
* wget
* libarchive (development package)
* perl
* sudo
Super-user privileges are required as well, because all packages are built
in a chroot (except the ones that are included in a virtual package to be
able to build a minimal system for the chroot).
------------------------------------------------------------------------------
HOW TO BUILD/HANDLE PACKAGES FROM SOURCE
------------------------------------------------------------------------------
Before using xbps-src, some required utilities need to be built and installed
into $(PREFIX); by default they are installed into /usr/local.
You can do this by issuing "make" and "make install" as root in the top
level directory.
If configuration file is not specified from the command line with the
-c flag, it will first try to use the default location at
/usr/local/etc/xbps.conf (or the installation prefix that was specified
to the make(1) command), and as last resort in the etc directory of the
current directory.
To avoid problems with libtool and configure scripts finding stuff that is
available in the host system, almost all packages must be built inside of a
chroot. So the first thing would be to create the binary packages with:
$ xbps-src install xbps-base-chroot
This will build all required packages via fakeroot in masterdir, therefore you
can run it as normal user. Next commands will require super-user privileges
and all package handling will be done within the chroot. I believe it's the
most easier and faster way to handle clean dependencies; another reason would
be that xbps packages are meant to be used in a system and not just for
ordinary users. So once all packages are built, you can create and enter
to the chroot with:
$ sudo xbps-src chroot
Press Control + D to exit from the chroot. The following targets will require
to be done in the chroot:
build, configure, install, install-destdir, remove, stow and unstow.
Now let's explain some more about the targets that you can use. To start
installing packages you should use the install target:
$ sudo xbps-src install glib
If the package is properly installed, it will be "stowned" automatically.
``stowned´´ means that this package is available in the master directory,
on which xpbs has copied all files from DESTDIR/<pkgname>.
To remove a currently installed (and stowned) package, you can use:
$ sudo xbps-src remove glib
Please note that when you remove it, the package will also be removed
from XBPS_DESTDIR and previously "unstowned".
To stow an already installed package (from XBPS_DESTDIR/<pkgname>):
$ sudo xbps-src stow glib
and to unstow an already installed (stowned) package:
$ sudo xbps-src unstow glib
You can also print some stuff about any template build file, e.g:
$ xbps-src info glib
To list installed (stowned) packages, use this:
$ xbps-src list
To only extract the distfiles, without configuring/building/installing:
$ xbps-src extract foo
To not remove the build directory after successful installation:
$ sudo xbps-src -C install blah
To only fetch the distfile:
$ xbps-src fetch blah
To only install the package, _without_ stowning it into the master directory:
$ sudo xbps-src install-destdir blob
To list files installed by a package, note that package must be installed
into destination directory first:
$ xbps-src listfiles blob
------------------------------------------------------------------------------
Juan Romero Pardines <xtraeme@gmail.com>

46
doc/TODO Normal file
View File

@ -0,0 +1,46 @@
xbps-src:
* Personalized scripts per template to unpack distfiles.
* Multiple URLs to download source distribution files, aliases, etc.
Something like ${sourceforge} to pick up any specified mirror on the list.
* Fix -C flag while building packages via chroot.
Packages:
* Create /etc/issue.
* Add a trigger for fc-cache.
* Add a trigger to (un)register users/groups. Currently packages that
require user/groups use custom INSTALL/REMOVE scripts, which adds
a lot of duplicated work.
* Add support to stop and restart package's OpenRC service while
removing and upgrading a package.
[PARTIAL: at pre-remove the services are stopped but not yet restarted]
* How to handle kernel package upgrades? dpkg seems to keep previous
package and its initramfs, and a dummy package depends on the latest one.
I think this is the best option.
* Fix initramfs-tools trigger for $pkgname != kernel.
* Fix initramfs-tools 'update-initramfs -a'.
* Fix HAL/PolicyKit for nonroot to be able to admin tasks.
* Fix loadkeys(1) incorrectly loading the olpc keymap vs qwerty.
xbps-bin:
* Add support to install binary packages without any repository.
* Add a flag to reinstall a package version that is already installed,
overwritting files on disk and updating required_by if required.
Perhaps change the automatic-install object to false, like pkg_install
from NetBSD do.
* Implement shell style match patterns with fnmatch() for install, update
and remove.
* Make -f flag to overwrite files when installing, and to ignore
files with wrong checksum or unexistent when removing.
[PARTIAL: only unexistent files are ignored when removing]
libxbps:
* Add support to upgrade packages but overwritting current files;
this will fix libc, sh and others. An "essential" boolean obj
seems to be a good way to find such packages, like dpkg.
[PARTIAL: files are overwritten but obsolete files are not
taken into account yet]
xbps-repo:
* Add support to add only specified packages, rather than looking
at all files in a directory.
* Add support for remote repositories, requires libfetch.

18
etc/Makefile Normal file
View File

@ -0,0 +1,18 @@
include ../vars.mk
CONF_FILE = xbps.conf
.PHONY: all
all:
.PHONY: clean
clean:
install:
if [ ! -d $(ETCDIR) ]; then \
install -d $(ETCDIR); \
fi
if [ ! -f $(ETCDIR)/$(CONF_FILE) ]; then \
install -m 644 $(CONF_FILE) $(ETCDIR); \
fi

54
etc/xbps.conf Normal file
View File

@ -0,0 +1,54 @@
#
# Configuration file for xbps-src.
#
#
# Global directory where the xbps distribution files are stored.
# Templates, patches and helper files should all be in that directory.
#
XBPS_DISTRIBUTIONDIR=$HOME/xbps
#
# Master directory: this is where all symlinks will be
# created pointing at packages installed in XBPS_DESTDIR.
#
XBPS_MASTERDIR=$XBPS_DISTRIBUTIONDIR/depot
#
# Destination directory: this is where all package files will be
# installed.
#
XBPS_DESTDIR=$XBPS_DISTRIBUTIONDIR/destdir
#
# Binary packages directory: this is where the binary packages will
# be created to.
#
XBPS_PACKAGESDIR=$XBPS_DISTRIBUTIONDIR/packages
#
# Directory where source files will be extracted to.
#
XBPS_BUILDDIR=$XBPS_DISTRIBUTIONDIR/builddir
#
# Directory where source distribution files are stored.
#
XBPS_SRCDISTDIR=$XBPS_DISTRIBUTIONDIR/srcdistdir
#
# Compilation flags for cc and c++.
#
XBPS_CFLAGS="-O2 -pipe"
XBPS_CXXFLAGS="$XBPS_CFLAGS"
#
# Number of jobs when running GNU or BSD make style packages.
#
#XBPS_MAKEJOBS=4
#
# Cross compilation stuff.
#
#XBPS_CROSS_TARGET=i686-pc-linux-gnu
#XBPS_CROSS_DIR=/storage/mktoolchain/$XBPS_CROSS_TARGET

51
include/sha256.h Normal file
View File

@ -0,0 +1,51 @@
/*
* Written by Aaron D. Gifford <me@aarongifford.com>
*
* Copyright 2000 Aaron D. Gifford. 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.
* 3. Neither the name of the copyright holder nor the names of contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTOR(S) ``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(S) OR CONTRIBUTOR(S) 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.
*
*/
#ifndef _SHA2_DIGEST_H_
#define _SHA2_DIGEST_H_
/*** SHA-256 Various Length Definitions ***********************/
#define SHA256_BLOCK_LENGTH 64
#define SHA256_DIGEST_LENGTH 32
#define SHA256_DIGEST_STRING_LENGTH (SHA256_DIGEST_LENGTH * 2 + 1)
/*** SHA-256 Context Structures *******************************/
typedef struct _SHA256_CTX {
uint32_t state[8];
uint64_t bitcount;
uint8_t buffer[SHA256_BLOCK_LENGTH];
} SHA256_CTX;
int SHA256_Init(SHA256_CTX *);
int SHA256_Update(SHA256_CTX *, const uint8_t *, size_t);
char *SHA256_End(SHA256_CTX *, uint8_t *);
#endif /* !_SHA2_DIGEST_H_ */

203
include/xbps_api.h Normal file
View File

@ -0,0 +1,203 @@
/*-
* Copyright (c) 2008-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.
*/
#ifndef _XBPS_API_H_
#define _XBPS_API_H_
#include <stdio.h>
#include <inttypes.h>
#include <sys/queue.h>
#define NDEBUG
#include <assert.h>
#include <prop/proplib.h>
#include <archive.h>
#include <archive_entry.h>
#include "sha256.h"
/* Default root PATH for xbps to store metadata info. */
#define XBPS_META_PATH "/var/db/xbps"
/* Filename for the repositories plist file. */
#define XBPS_REPOLIST "repositories.plist"
/* Filename of the package index plist for a repository. */
#define XBPS_PKGINDEX "pkg-index.plist"
/* Filename of the packages register. */
#define XBPS_REGPKGDB "regpkgdb.plist"
/* Package metadata files. */
#define XBPS_PKGPROPS "props.plist"
#define XBPS_PKGFILES "files.plist"
/* Current version of the package index format. */
#define XBPS_PKGINDEX_VERSION "1.0"
/* Verbose messages */
#define XBPS_FLAG_VERBOSE 0x00000001
#define XBPS_FLAG_FORCE 0x00000002
#define ARCHIVE_READ_BLOCKSIZE 10240
#ifndef __UNCONST
#define __UNCONST(a) ((void *)(unsigned long)(const void *)(a))
#endif
/* From lib/configure.c */
int xbps_configure_pkg(const char *);
/* from lib/cmpver.c */
int xbps_cmpver(const char *, const char *);
/* From lib/fexec.c */
int xbps_file_exec(const char *, ...);
int xbps_file_exec_skipempty(const char *, ...);
int xbps_file_chdir_exec(const char *, const char *, ...);
/* From lib/humanize_number.c */
#define HN_DECIMAL 0x01
#define HN_NOSPACE 0x02
#define HN_B 0x04
#define HN_DIVISOR_1000 0x08
#define HN_GETSCALE 0x10
#define HN_AUTOSCALE 0x20
int xbps_humanize_number(char *, size_t, int64_t, const char *,
int, int);
/* From lib/findpkg.c */
struct repository_data {
SIMPLEQ_ENTRY(repository_data) chain;
prop_dictionary_t rd_repod;
};
SIMPLEQ_HEAD(, repository_data) repodata_queue;
int xbps_prepare_pkg(const char *);
int xbps_find_new_pkg(const char *, prop_dictionary_t);
int xbps_find_new_packages(void);
int xbps_prepare_repolist_data(void);
void xbps_release_repolist_data(void);
prop_dictionary_t xbps_get_pkg_props(void);
/* From lib/depends.c */
int xbps_find_deps_in_pkg(prop_dictionary_t, prop_dictionary_t);
/* From lib/orphans.c */
prop_array_t xbps_find_orphan_packages(void);
/* From lib/plist.c */
bool xbps_add_obj_to_dict(prop_dictionary_t, prop_object_t,
const char *);
bool xbps_add_obj_to_array(prop_array_t, prop_object_t);
int xbps_callback_array_iter_in_dict(prop_dictionary_t,
const char *,
int (*fn)(prop_object_t, void *, bool *),
void *);
int xbps_callback_array_iter_reverse_in_dict(prop_dictionary_t,
const char *,
int (*fn)(prop_object_t, void *, bool *),
void *);
int xbps_callback_array_iter_in_repolist(int (*fn)(prop_object_t,
void *, bool *), void *);
prop_dictionary_t xbps_find_pkg_in_dict(prop_dictionary_t,
const char *, const char *);
prop_dictionary_t xbps_find_pkg_from_plist(const char *, const char *);
prop_dictionary_t xbps_find_pkg_installed_from_plist(const char *);
bool xbps_find_string_in_array(prop_array_t, const char *);
prop_dictionary_t xbps_prepare_regpkgdb_dict(void);
void xbps_release_regpkgdb_dict(void);
prop_object_iterator_t xbps_get_array_iter_from_dict(prop_dictionary_t,
const char *);
prop_dictionary_t xbps_read_dict_from_archive_entry(struct archive *,
struct archive_entry *);
int xbps_remove_pkg_dict_from_file(const char *, const char *);
int xbps_remove_pkg_from_dict(prop_dictionary_t, const char *,
const char *);
int xbps_remove_string_from_array(prop_array_t, const char *);
/* From lib/purge.c */
int xbps_purge_pkg(const char *);
/* From lib/register.c */
int xbps_register_pkg(prop_dictionary_t, bool);
int xbps_unregister_pkg(const char *);
/* From lib/remove.c */
int xbps_remove_pkg(const char *, const char *, bool);
/* From lib/repository.c */
int xbps_register_repository(const char *);
int xbps_unregister_repository(const char *);
/* From lib/requiredby.c */
int xbps_requiredby_pkg_add(prop_array_t, prop_dictionary_t);
int xbps_requiredby_pkg_remove(const char *);
/* From lib/sortdeps.c */
int xbps_sort_pkg_deps(prop_dictionary_t);
/* From lib/state.c */
typedef enum pkg_state {
XBPS_PKG_STATE_UNPACKED = 1,
XBPS_PKG_STATE_INSTALLED,
XBPS_PKG_STATE_BROKEN,
XBPS_PKG_STATE_CONFIG_FILES,
XBPS_PKG_STATE_NOT_INSTALLED
} pkg_state_t;
int xbps_get_pkg_state_installed(const char *, pkg_state_t *);
int xbps_get_pkg_state_dictionary(prop_dictionary_t, pkg_state_t *);
int xbps_set_pkg_state_installed(const char *, pkg_state_t);
int xbps_set_pkg_state_dictionary(prop_dictionary_t, pkg_state_t);
/* From lib/unpack.c */
int xbps_unpack_binary_pkg(prop_dictionary_t, bool);
/* From lib/util.c */
char * xbps_xasprintf(const char *, ...);
char * xbps_get_file_hash(const char *);
int xbps_check_file_hash(const char *, const char *);
int xbps_check_pkg_file_hash(prop_dictionary_t, const char *);
int xbps_check_is_installed_pkg(const char *);
bool xbps_check_is_installed_pkgname(const char *);
char * xbps_get_pkg_index_plist(const char *);
char * xbps_get_pkg_name(const char *);
const char * xbps_get_pkg_version(const char *);
const char * xbps_get_pkg_revision(const char *);
bool xbps_pkg_has_rundeps(prop_dictionary_t);
void xbps_set_rootdir(const char *);
const char * xbps_get_rootdir(void);
void xbps_set_flags(int);
int xbps_get_flags(void);
bool xbps_yesno(const char *, ...);
bool xbps_noyes(const char *, ...);
#endif /* !_XBPS_API_H_ */

44
lib/Makefile Normal file
View File

@ -0,0 +1,44 @@
include ../vars.mk
# The shared library.
MAJOR = 0
MINOR = 0
MICRO = 0
LIBXBPS_SO = $(LIBXBPS).$(MAJOR).$(MINOR).$(MICRO)
LIBXBPS = libxbps.so
LIBXBPS_STATIC = libxbps.a
LIBXBPS_LDFLAGS = -larchive -lprop -shared -Wl,-soname,$(LIBXBPS).$(MAJOR)
OBJECTS = configure.o cmpver.o depends.o fexec.o findpkg.o
OBJECTS += humanize_number.o orphans.o plist.o purge.o register.o remove.o
OBJECTS += repository.o requiredby.o sha256.o sortdeps.o state.o unpack.o
OBJECTS += util.o
all: $(LIBXBPS) $(LIBXBPS_STATIC)
.PHONY: all
$(LIBXBPS): $(OBJECTS)
$(CC) $(LIBXBPS_LDFLAGS) $^ -o $(LIBXBPS_SO)
-ln -sf $(LIBXBPS_SO) $(LIBXBPS).$(MAJOR)
-ln -sf $(LIBXBPS_SO) $(LIBXBPS)
$(LIBXBPS_STATIC): $(OBJECTS)
$(AR) rcs $@ $^
ranlib $@
install: $(LIBXBPS) $(LIBXBPS_STATIC)
install -d $(LIBDIR)
install -m 644 $(LIBXBPS_STATIC) $(LIBDIR)
install -m 644 $(LIBXBPS_SO) $(LIBDIR)
cp -a $(LIBXBPS) $(LIBDIR)
cp -a $(LIBXBPS).$(MAJOR) $(LIBDIR)
.PHONY: clean
clean: clean-lib clean-objs
clean-lib:
-rm -f $(LIBXBPS)*
-rm -f $(LIBXBPS_STATIC)
clean-objs:
-rm -f *.o

282
lib/cmpver.c Normal file
View File

@ -0,0 +1,282 @@
/*
* FreeBSD install - a package for the installation and maintenance
* of non-core utilities.
*
* 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.
*
* Maxim Sobolev
* 31 July 2001
*
* Written by Oliver Eikemeier
* Based on work of Jeremy D. Lea.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <xbps_api.h>
/*
* split_version(pkgname, endname, epoch, revision) returns a pointer to
* the version portion of a package name and the two special components.
*
* Syntax is: ${PKGNAME}-${VERSION}[_${PKGREVISION}][-${EPOCH}]
*
*/
static const char *
split_version(const char *pkgname, const char **endname, unsigned long *epoch,
unsigned long *revision)
{
char *ch;
const char *versionstr;
const char *endversionstr;
assert(pkgname != NULL);
/* Look for the last '-' the the pkgname */
ch = strrchr(pkgname, '-');
/* Cheat if we are just passed a version, not a valid package name */
versionstr = ch ? ch + 1 : pkgname;
/* Look for the last '_' in the version string, advancing the end pointer */
ch = strrchr(versionstr, '_');
if (revision != NULL) {
*revision = ch ? strtoul(ch + 1, NULL, 10) : 0;
}
endversionstr = ch;
/* Look for the last '-' in the remaining version string */
ch = strrchr(endversionstr ? endversionstr + 1 : versionstr, '-');
if (epoch != NULL) {
*epoch = ch ? strtoul(ch + 1, NULL, 10) : 0;
}
if (ch && !endversionstr)
endversionstr = ch;
/*
* set the pointer behind the last character of the version without
* revision or epoch
*/
if (endname)
*endname = endversionstr ? endversionstr : strrchr(versionstr, '\0');
return versionstr;
}
/*
* VERSIONs are composed of components separated by dots. A component
* consists of a version number, a letter and a patchlevel number.
*/
typedef struct {
long n;
long pl;
int a;
} version_component;
/*
* get_component(position, component) gets the value of the next component
* (number - letter - number triple) and returns a pointer to the next character
* after any leading separators
*
* - components are separated by dots
* - characters !~ [a-zA-Z0-9.+*] are treated as separators
* (1.0:2003.09.16 = 1.0.2003.09.16), this may not be what you expect:
* 1.0.1:2003.09.16 < 1.0:2003.09.16
* - consecutive separators are collapsed (10..1 = 10.1)
* - missing separators are inserted, essentially
* letter number letter => letter number . letter (10a1b2 = 10a1.b2)
* - missing components are assumed to be equal to 0 (10 = 10.0 = 10.0.0)
* - the letter sort order is: [none], a, b, ..., z; numbers without letters
* sort first (10 < 10a < 10b)
* - missing version numbers (in components starting with a letter) sort as -1
* (a < 0, 10.a < 10)
* - a separator is inserted before the special strings "pl", "alpha", "beta",
* "pre" and "rc".
* - "pl" sorts before every other letter, "alpha", "beta", "pre" and "rc"
* sort as a, b, p and r. (10alpha = 10.a < 10, but 10 < 10a; pl11 < alpha3
* < 0.1beta2 = 0.1.b2 < 0.1)
* - other strings use only the first letter for sorting, case is ignored
* (1.d2 = 1.dev2 = 1.Development2)
* - The special component `*' is guaranteed to be the smallest possible
* component (2.* < 2pl1 < 2alpha3 < 2.9f7 < 3.*)
* - components separated by `+' are handled by version_cmp below
*/
static const struct {
const char *name;
size_t namelen;
int value;
} stage[] = {
{ "pl", 2, 0 },
{ "alpha", 5, 'a'-'a'+1 },
{ "beta", 4, 'b'-'a'+1 },
{ "pre", 3, 'p'-'a'+1 },
{ "rc", 2, 'r'-'a'+1 },
{ NULL, 0, -1 }
};
static const char *
get_component(const char *position, version_component *component)
{
const char *pos = position;
int hasstage = 0, haspatchlevel = 0;
assert(pos != NULL);
/* handle version number */
if (isdigit((unsigned char)*pos)) {
char *endptr;
component->n = strtol(pos, &endptr, 10);
/* should we test for errno == ERANGE? */
pos = endptr;
} else if (*pos == '*') {
component->n = -2;
do {
pos++;
} while(*pos && *pos != '+');
} else {
component->n = -1;
hasstage = 1;
}
/* handle letter */
if (isalpha((unsigned char)*pos)) {
int c = tolower((unsigned char)*pos);
haspatchlevel = 1;
/* handle special suffixes */
if (isalpha((unsigned char)pos[1])) {
int i;
for (i = 0; stage[i].name; i++) {
if (strncasecmp(pos, stage[i].name, stage[i].namelen) == 0
&& !isalpha((unsigned char)pos[stage[i].namelen])) {
if (hasstage) {
/* stage to value */
component->a = stage[i].value;
pos += stage[i].namelen;
} else {
/* insert dot */
component->a = 0;
haspatchlevel = 0;
}
c = 0;
break;
}
}
}
/* unhandled above */
if (c) {
/* use the first letter and skip following */
component->a = c - 'a' + 1;
do {
++pos;
} while (isalpha((unsigned char)*pos));
}
} else {
component->a = 0;
haspatchlevel = 0;
}
if (haspatchlevel) {
/* handle patch number */
if (isdigit((unsigned char)*pos)) {
char *endptr;
component->pl = strtol(pos, &endptr, 10);
/* should we test for errno == ERANGE? */
pos = endptr;
} else {
component->pl = -1;
}
} else {
component->pl = 0;
}
/* skip trailing separators */
while (*pos && !isdigit((unsigned char)*pos) &&
!isalpha((unsigned char)*pos) &&
*pos != '+' && *pos != '*') {
pos++;
}
return pos;
}
/*
* version_cmp(pkg1, pkg2) returns -1, 0 or 1 depending on if the version
* components of pkg1 is less than, equal to or greater than pkg2. No
* comparison of the basenames is done.
*
* The port version is defined by:
* ${VERSION}[_${PKGREVISION}][-${EPOCH}]
* ${EPOCH} supersedes ${VERSION} supersedes ${PKGREVISION}.
*
* The epoch and revision are defined to be a single number, while the rest
* of the version should conform to the porting guidelines. It can contain
* multiple components, separated by a period, including letters.
*/
int
xbps_cmpver(const char *pkg1, const char *pkg2)
{
const char *v1, *v2, *ve1, *ve2;
unsigned long e1, e2, r1, r2;
int result = 0;
v1 = split_version(pkg1, &ve1, &e1, &r1);
v2 = split_version(pkg2, &ve2, &e2, &r2);
/* Check epoch, version, and pkgrevision, in that order. */
if (e1 != e2) {
result = (e1 < e2 ? -1 : 1);
}
/* Shortcut check for equality before invoking the parsing routines. */
if (result == 0 && (ve1 - v1 != ve2 - v2 ||
strncasecmp(v1, v2, (size_t)ve1 - (size_t)v1) != 0)) {
/* Loop over different components (the parts separated by dots).
* If any component differs, we have the basis for an inequality. */
while(result == 0 && (v1 < ve1 || v2 < ve2)) {
int block_v1 = 0;
int block_v2 = 0;
version_component vc1 = {0, 0, 0};
version_component vc2 = {0, 0, 0};
if (v1 < ve1 && *v1 != '+') {
v1 = get_component(v1, &vc1);
} else {
block_v1 = 1;
}
if (v2 < ve2 && *v2 != '+') {
v2 = get_component(v2, &vc2);
} else {
block_v2 = 1;
}
if (block_v1 && block_v2) {
if (v1 < ve1)
v1++;
if (v2 < ve2)
v2++;
} else if (vc1.n != vc2.n) {
result = (vc1.n < vc2.n ? -1 : 1);
} else if (vc1.a != vc2.a) {
result = (vc1.a < vc2.a ? -1 : 1);
} else if (vc1.pl != vc2.pl) {
result = (vc1.pl < vc2.pl ? -1 : 1);
}
}
}
/* Compare revision numbers. */
if (result == 0 && r1 != r2) {
result = (r1 < r2 ? -1 : 1);
}
return result;
}

102
lib/configure.c Normal file
View File

@ -0,0 +1,102 @@
/*-
* 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 <stdlib.h>
#include <string.h>
#include <errno.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)
{
prop_dictionary_t pkgd;
const char *rootdir, *version;
char *buf;
int rv = 0, flags = 0;
pkg_state_t state = 0;
bool reconfigure = false;
assert(pkgname != NULL);
rootdir = xbps_get_rootdir();
flags = xbps_get_flags();
if ((rv = xbps_get_pkg_state_installed(pkgname, &state)) != 0)
return rv;
if (state == XBPS_PKG_STATE_INSTALLED) {
if ((flags & XBPS_FLAG_FORCE) == 0)
return 0;
reconfigure = true;
} else if (state != XBPS_PKG_STATE_UNPACKED)
return EINVAL;
pkgd = xbps_find_pkg_installed_from_plist(pkgname);
if (pkgd == NULL)
return ENOENT;
prop_dictionary_get_cstring_nocopy(pkgd, "version", &version);
prop_object_release(pkgd);
printf("%sonfiguring package %s-%s...\n",
reconfigure ? "Rec" : "C", pkgname, version);
buf = xbps_xasprintf(".%s/metadata/%s/INSTALL",
XBPS_META_PATH, pkgname);
if (buf == NULL)
return errno;
if (access(buf, R_OK) == 0) {
if (strcmp(rootdir, "") == 0)
rootdir = "/";
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);
}

349
lib/depends.c Normal file
View File

@ -0,0 +1,349 @@
/*-
* Copyright (c) 2008-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 <stdlib.h>
#include <string.h>
#include <errno.h>
#include <xbps_api.h>
static int add_missing_reqdep(prop_dictionary_t, const char *, const char *);
static int find_repo_deps(prop_dictionary_t, prop_dictionary_t, prop_array_t);
static int find_repo_missing_deps(prop_dictionary_t, prop_dictionary_t);
static int
store_dependency(prop_dictionary_t master, prop_dictionary_t depd,
prop_dictionary_t repod)
{
prop_dictionary_t dict;
prop_array_t array;
const char *repoloc, *pkgname;
int rv = 0;
pkg_state_t state = 0;
assert(master != NULL);
assert(depd != NULL);
assert(repod != NULL);
/*
* Get some info about dependencies and current repository.
*/
prop_dictionary_get_cstring_nocopy(depd, "pkgname", &pkgname);
prop_dictionary_get_cstring_nocopy(repod, "location-local", &repoloc);
dict = prop_dictionary_copy(depd);
if (dict == NULL)
return errno;
array = prop_dictionary_get(master, "unsorted_deps");
if (array == NULL) {
prop_object_release(dict);
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.
*/
prop_dictionary_set_cstring(dict, "repository", repoloc);
/*
* Remove some unneeded objects.
*/
prop_dictionary_remove(dict, "conf_files");
prop_dictionary_remove(dict, "keep_dirs");
prop_dictionary_remove(dict, "maintainer");
prop_dictionary_remove(dict, "long_desc");
/*
* Add the dictionary into the array.
*/
if (!xbps_add_obj_to_array(array, dict)) {
prop_object_release(dict);
return EINVAL;
}
return 0;
}
static int
add_missing_reqdep(prop_dictionary_t master, const char *pkgname,
const char *version)
{
prop_array_t array;
prop_dictionary_t depd;
assert(master != NULL);
assert(pkgname != NULL);
assert(version != NULL);
/*
* Adds a package into the missing deps array.
*/
if (xbps_find_pkg_in_dict(master, "missing_deps", pkgname))
return EEXIST;
array = prop_dictionary_get(master, "missing_deps");
depd = prop_dictionary_create();
if (depd == NULL)
return ENOMEM;
prop_dictionary_set_cstring(depd, "pkgname", pkgname);
prop_dictionary_set_cstring(depd, "version", version);
if (!xbps_add_obj_to_array(array, depd)) {
prop_object_release(depd);
return EINVAL;
}
return 0;
}
int
xbps_find_deps_in_pkg(prop_dictionary_t master, prop_dictionary_t pkg)
{
prop_array_t pkg_rdeps, missing_rdeps;
struct repository_data *rdata;
int rv = 0;
assert(pkg != NULL);
assert(iter != NULL);
pkg_rdeps = prop_dictionary_get(pkg, "run_depends");
if (pkg_rdeps == NULL)
return 0;
/*
* Iterate over the repository pool and find out if we have
* all available binary packages.
*/
SIMPLEQ_FOREACH(rdata, &repodata_queue, chain) {
/*
* This will find direct and indirect deps,
* if any of them is not there it will be added
* into the missing_deps array.
*/
rv = find_repo_deps(master, rdata->rd_repod, pkg_rdeps);
if (rv != 0) {
if (rv == ENOENT) {
rv = 0;
continue;
}
break;
}
}
missing_rdeps = prop_dictionary_get(master, "missing_deps");
if (prop_array_count(missing_rdeps) == 0)
return 0;
/*
* If there are missing deps, iterate one more time
* just in case that indirect deps weren't found.
*/
SIMPLEQ_FOREACH(rdata, &repodata_queue, chain) {
rv = find_repo_missing_deps(master, rdata->rd_repod);
if (rv != 0 && rv != ENOENT)
return rv;
}
return 0;
}
static int
find_repo_missing_deps(prop_dictionary_t master, prop_dictionary_t repo)
{
prop_array_t array;
prop_dictionary_t curpkgd;
prop_object_t obj;
prop_object_iterator_t iter;
const char *pkgname, *version;
int rv = 0;
assert(repo != NULL);
assert(pkg != NULL);
array = prop_dictionary_get(master, "missing_deps");
if (prop_array_count(array) == 0)
return 0;
iter = prop_array_iterator(array);
if (iter == NULL)
return ENOMEM;
while ((obj = prop_object_iterator_next(iter)) != NULL) {
prop_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname);
prop_dictionary_get_cstring_nocopy(obj, "version", &version);
/*
* If required package is not in repo, add it into the
* missing deps array and pass to the next one.
*/
curpkgd = xbps_find_pkg_in_dict(repo, "packages", pkgname);
if (curpkgd == NULL) {
rv = add_missing_reqdep(master, pkgname, version);
if (rv != 0 && rv != EEXIST)
break;
else {
rv = ENOENT;
continue;
}
}
/*
* Package is on repo, add it into the dictionary.
*/
if ((rv = store_dependency(master, curpkgd, repo)) != 0)
break;
/*
* Remove package from missing_deps array now.
*/
rv = xbps_remove_pkg_from_dict(master,
"missing_deps", pkgname);
if (rv != 0 && rv != ENOENT)
break;
prop_object_iterator_reset(iter);
}
prop_object_iterator_release(iter);
return rv;
}
static int
find_repo_deps(prop_dictionary_t master, prop_dictionary_t repo,
prop_array_t pkg_rdeps)
{
prop_dictionary_t curpkgd, tmpd = NULL;
prop_array_t curpkg_rdeps;
prop_object_t obj;
prop_object_iterator_t iter;
const char *reqpkg, *reqvers;
char *pkgname;
int rv = 0;
iter = prop_array_iterator(pkg_rdeps);
if (iter == NULL)
return ENOMEM;
/*
* Iterate over the list of required run dependencies for
* current package.
*/
while ((obj = prop_object_iterator_next(iter))) {
reqpkg = prop_string_cstring_nocopy(obj);
pkgname = xbps_get_pkg_name(reqpkg);
reqvers = xbps_get_pkg_version(reqpkg);
/*
* Check if required dep is satisfied and installed.
*/
if (xbps_check_is_installed_pkg(reqpkg) >= 0) {
free(pkgname);
continue;
}
/*
* Check if package is already added in the
* array of unsorted deps.
*/
if (xbps_find_pkg_in_dict(master, "unsorted_deps", pkgname)) {
free(pkgname);
continue;
}
/*
* If required package is not in repo, add it into the
* missing deps array and pass to the next one.
*/
curpkgd = xbps_find_pkg_in_dict(repo, "packages", pkgname);
if (curpkgd == NULL) {
rv = add_missing_reqdep(master, pkgname, reqvers);
free(pkgname);
if (rv != 0 && rv != EEXIST)
break;
else {
rv = ENOENT;
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.
*/
if ((rv = store_dependency(master, curpkgd, repo)) != 0) {
free(pkgname);
break;
}
/*
* Remove package from missing_deps now it's been found.
*/
rv = xbps_remove_pkg_from_dict(master,
"missing_deps", pkgname);
if (rv != 0 && rv != ENOENT) {
free(pkgname);
break;
}
free(pkgname);
/*
* If package doesn't have rundeps, pass to the next one.
*/
curpkg_rdeps = prop_dictionary_get(curpkgd, "run_depends");
if (curpkg_rdeps == NULL)
continue;
/*
* Iterate on required pkg to find more deps.
*/
if (!find_repo_deps(master, repo, curpkg_rdeps))
continue;
}
prop_object_iterator_release(iter);
return rv;
}

168
lib/fexec.c Normal file
View File

@ -0,0 +1,168 @@
/*-
* Copyright (c) 2003 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Matthias Scheler.
*
* 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``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 FOUNDATION OR CONTRIBUTORS
* 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 <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <xbps_api.h>
static int vfcexec(const char *, int, const char *, va_list);
static int pfcexec(const char *, const char *, const char **);
/*
* Fork, then if /bin/sh exists change root directory to
* path; otherwise just change current working directory.
* Execute the command and arguments in the argv array.
* wait for the command to finish, then return the exit status.
*/
static int
pfcexec(const char *path, const char *file, const char **argv)
{
pid_t child;
int status;
child = vfork();
switch (child) {
case 0:
if (path != NULL) {
/*
* If root and /bin/sh exists chroot to
* destdir and exec the command. Otherwise
* just change CWD to destdir.
*/
if (getuid() == 0 && access("./bin/sh", R_OK) == 0) {
if (chroot(path) == -1)
_exit(127);
if (chdir("/") == -1)
_exit(127);
} else {
if (chdir(path) == -1)
_exit(127);
}
}
(void)execvp(file, (char ** const)__UNCONST(argv));
_exit(127);
/* NOTREACHED */
case -1:
return -1;
}
while (waitpid(child, &status, 0) < 0) {
if (errno != EINTR)
return -1;
}
if (!WIFEXITED(status))
return -1;
return WEXITSTATUS(status);
}
static int
vfcexec(const char *path, int skipempty, const char *arg, va_list ap)
{
const char **argv;
size_t argv_size, argc;
int retval;
argv_size = 16;
if ((argv = malloc(argv_size * sizeof(*argv))) == NULL) {
errno = ENOMEM;
return -1;
}
argv[0] = arg;
argc = 1;
do {
if (argc == argv_size) {
argv_size *= 2;
argv = realloc(argv, argv_size * sizeof(*argv));
if (argv == NULL) {
errno = ENOMEM;
return -1;
}
}
arg = va_arg(ap, const char *);
if (skipempty && arg && strlen(arg) == 0)
continue;
argv[argc++] = arg;
} while (arg != NULL);
retval = pfcexec(path, argv[0], argv);
free(argv);
return retval;
}
int
xbps_file_exec(const char *arg, ...)
{
va_list ap;
int result;
va_start(ap, arg);
result = vfcexec(NULL, 0, arg, ap);
va_end(ap);
return result;
}
int
xbps_file_exec_skipempty(const char *arg, ...)
{
va_list ap;
int result;
va_start(ap, arg);
result = vfcexec(NULL, 1, arg, ap);
va_end(ap);
return result;
}
int
xbps_file_chdir_exec(const char *path, const char *arg, ...)
{
va_list ap;
int result;
va_start(ap, arg);
result = vfcexec(path, 0, arg, ap);
va_end(ap);
return result;
}

458
lib/findpkg.c Normal file
View File

@ -0,0 +1,458 @@
/*-
* 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 <xbps_api.h>
static prop_dictionary_t pkg_props;
static bool pkg_props_initialized;
static int set_pkg_state(prop_dictionary_t, const char *);
static int
create_pkg_props_dictionary(void)
{
prop_array_t unsorted, missing;
int rv = 0;
if (pkg_props_initialized)
return 0;
pkg_props = prop_dictionary_create();
if (pkg_props == NULL)
return ENOMEM;
missing = prop_array_create();
if (missing == NULL) {
rv = ENOMEM;
goto fail;
}
unsorted = prop_array_create();
if (unsorted == NULL) {
rv = ENOMEM;
goto fail2;
}
if (!xbps_add_obj_to_dict(pkg_props, missing, "missing_deps")) {
rv = EINVAL;
goto fail3;
}
if (!xbps_add_obj_to_dict(pkg_props, unsorted, "unsorted_deps")) {
rv = EINVAL;
goto fail3;
}
pkg_props_initialized = true;
return rv;
fail3:
prop_object_release(unsorted);
fail2:
prop_object_release(missing);
fail:
prop_object_release(pkg_props);
return rv;
}
prop_dictionary_t
xbps_get_pkg_props(void)
{
if (pkg_props_initialized == false)
return NULL;
return pkg_props;
}
int
xbps_prepare_repolist_data(void)
{
prop_dictionary_t dict = NULL;
prop_array_t array;
prop_object_t obj;
prop_object_iterator_t iter;
struct repository_data *rdata;
const char *rootdir;
char *plist;
int rv = 0;
static bool repodata_initialized;
if (repodata_initialized)
return 0;
SIMPLEQ_INIT(&repodata_queue);
rootdir = xbps_get_rootdir();
if (rootdir == NULL)
rootdir = "";
plist = xbps_xasprintf("%s/%s/%s", rootdir,
XBPS_META_PATH, XBPS_REPOLIST);
if (plist == NULL) {
rv = EINVAL;
goto out;
}
dict = prop_dictionary_internalize_from_file(plist);
if (dict == NULL) {
free(plist);
rv = errno;
goto out;
}
free(plist);
array = prop_dictionary_get(dict, "repository-list");
if (array == NULL) {
rv = EINVAL;
goto out1;
}
iter = prop_array_iterator(array);
if (iter == NULL) {
rv = ENOMEM;
goto out1;
}
while ((obj = prop_object_iterator_next(iter)) != NULL) {
/*
* Iterate over the repository pool and add the dictionary
* for current repository into the queue.
*/
plist =
xbps_get_pkg_index_plist(prop_string_cstring_nocopy(obj));
if (plist == NULL) {
rv = EINVAL;
goto out2;
}
rdata = malloc(sizeof(struct repository_data));
if (rdata == NULL) {
rv = errno;
goto out2;
}
rdata->rd_repod = prop_dictionary_internalize_from_file(plist);
if (rdata->rd_repod == NULL) {
free(plist);
rv = errno;
goto out2;
}
free(plist);
SIMPLEQ_INSERT_TAIL(&repodata_queue, rdata, chain);
}
repodata_initialized = true;
out2:
prop_object_iterator_release(iter);
out1:
prop_object_release(dict);
out:
if (rv != 0)
xbps_release_repolist_data();
return rv;
}
void
xbps_release_repolist_data(void)
{
struct repository_data *rdata;
while ((rdata = SIMPLEQ_FIRST(&repodata_queue)) != NULL) {
SIMPLEQ_REMOVE(&repodata_queue, rdata, repository_data, chain);
prop_object_release(rdata->rd_repod);
free(rdata);
}
}
int
xbps_find_new_packages(void)
{
prop_dictionary_t dict;
prop_object_t obj;
prop_object_iterator_t iter;
const char *pkgname;
int rv = 0;
/*
* Prepare dictionary with all registered packages.
*/
dict = xbps_prepare_regpkgdb_dict();
if (dict == NULL)
return ENOENT;
/*
* Prepare dictionary with all registered repositories.
*/
if ((rv = xbps_prepare_repolist_data()) != 0)
return rv;
iter = xbps_get_array_iter_from_dict(dict, "packages");
if (iter == NULL)
return EINVAL;
/*
* Find out if there is a newer version for all currently
* installed packages.
*/
while ((obj = prop_object_iterator_next(iter)) != NULL) {
prop_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname);
if ((rv = xbps_find_new_pkg(pkgname, obj)) != 0) {
prop_object_iterator_release(iter);
return rv;
}
}
prop_object_iterator_release(iter);
return rv;
}
int
xbps_find_new_pkg(const char *pkgname, prop_dictionary_t instpkg)
{
prop_dictionary_t pkgrd = NULL;
prop_array_t unsorted;
struct repository_data *rdata;
const char *repoloc, *repover, *instver;
int rv = 0;
assert(pkgname != NULL);
assert(instpkg != NULL);
SIMPLEQ_FOREACH(rdata, &repodata_queue, chain) {
/*
* Get the package dictionary from current repository.
* If it's not there, pass to the next repository.
*/
pkgrd = xbps_find_pkg_in_dict(rdata->rd_repod,
"packages", pkgname);
if (pkgrd != NULL) {
/*
* Check if installed version is >= than the
* one available in current repository.
*/
prop_dictionary_get_cstring_nocopy(instpkg,
"version", &instver);
prop_dictionary_get_cstring_nocopy(pkgrd,
"version", &repover);
if (xbps_cmpver(instver, repover) >= 0)
goto out;
break;
}
}
if (pkgrd == NULL)
return 0;
/*
* Create master pkg dictionary.
*/
if ((rv = create_pkg_props_dictionary()) != 0)
goto out;
/*
* Set repository in pkg dictionary.
*/
if (!prop_dictionary_get_cstring_nocopy(rdata->rd_repod,
"location-local", &repoloc)) {
rv = EINVAL;
goto out;
}
prop_dictionary_set_cstring(pkgrd, "repository", repoloc);
/*
* Construct the dependency chain for this package.
*/
if ((rv = xbps_find_deps_in_pkg(pkg_props, pkgrd)) != 0)
goto out;
/*
* Add required package dictionary into the packages
* dictionary.
*/
unsorted = prop_dictionary_get(pkg_props, "unsorted_deps");
if (unsorted == NULL) {
rv = EINVAL;
goto out;
}
/*
* Always set "not-installed" package state. Will be overwritten
* to its correct state later.
*/
if ((rv = set_pkg_state(pkgrd, pkgname)) != 0)
goto out;
prop_dictionary_set_cstring_nocopy(pkgrd, "trans-action", "update");
if (!prop_array_add(unsorted, pkgrd))
rv = errno;
out:
if (rv != 0)
xbps_release_repolist_data();
return rv;
}
static int
set_pkg_state(prop_dictionary_t pkgd, const char *pkgname)
{
pkg_state_t state = 0;
int rv = 0;
rv = xbps_set_pkg_state_dictionary(pkgd, XBPS_PKG_STATE_NOT_INSTALLED);
if (rv != 0)
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(pkgd, state)) != 0)
return rv;
} else if (rv == ENOENT)
rv = 0;
return rv;
}
int
xbps_prepare_pkg(const char *pkgname)
{
prop_dictionary_t pkgrd = NULL;
prop_array_t pkgs_array;
struct repository_data *rdata;
const char *repoloc;
int rv = 0;
assert(pkgname != NULL);
if ((rv = xbps_prepare_repolist_data()) != 0)
return rv;
SIMPLEQ_FOREACH(rdata, &repodata_queue, chain) {
/*
* Get the package dictionary from current repository.
* If it's not there, pass to the next repository.
*/
pkgrd = xbps_find_pkg_in_dict(rdata->rd_repod,
"packages", pkgname);
if (pkgrd != NULL)
break;
}
if (pkgrd == NULL) {
rv = EAGAIN;
goto out;
}
/*
* Create master pkg dictionary.
*/
if ((rv = create_pkg_props_dictionary()) != 0)
goto out;
/*
* Set repository in pkg dictionary.
*/
if (!prop_dictionary_get_cstring_nocopy(rdata->rd_repod,
"location-local", &repoloc)) {
rv = EINVAL;
goto out;
}
prop_dictionary_set_cstring(pkgrd, "repository", repoloc);
prop_dictionary_set_cstring(pkg_props, "origin", pkgname);
/*
* Check if this package needs dependencies.
*/
if (xbps_pkg_has_rundeps(pkgrd)) {
/*
* Construct the dependency chain for this package.
*/
if ((rv = xbps_find_deps_in_pkg(pkg_props, pkgrd)) != 0)
goto out;
/*
* Sort the dependency chain for this package.
*/
if ((rv = xbps_sort_pkg_deps(pkg_props)) != 0)
goto out;
} else {
/*
* Package has no deps, so we have to create the
* "packages" array.
*/
pkgs_array = prop_array_create();
if (pkgs_array == NULL) {
rv = errno;
goto out;
}
if (!prop_dictionary_set(pkg_props, "packages",
pkgs_array)) {
rv = errno;
goto out;
}
}
/*
* Add required package dictionary into the packages
* dictionary.
*/
pkgs_array = prop_dictionary_get(pkg_props, "packages");
if (pkgs_array == NULL ||
prop_object_type(pkgs_array) != PROP_TYPE_ARRAY) {
rv = EINVAL;
goto out;
}
/*
* Always set "not-installed" package state. Will be overwritten
* to its correct state later.
*/
if ((rv = set_pkg_state(pkgrd, pkgname)) != 0)
goto out;
prop_dictionary_set_cstring_nocopy(pkgrd, "trans-action", "install");
if (!prop_array_add(pkgs_array, pkgrd))
rv = errno;
out:
xbps_release_repolist_data();
return rv;
}

143
lib/humanize_number.c Normal file
View File

@ -0,0 +1,143 @@
/* $NetBSD: humanize_number.c,v 1.14 2008/04/28 20:22:59 martin Exp $ */
/*
* Copyright (c) 1997, 1998, 1999, 2002 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
* NASA Ames Research Center, by Luke Mewburn and by Tomas Svensson.
*
* 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``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 FOUNDATION OR CONTRIBUTORS
* 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 <assert.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <locale.h>
#include <xbps_api.h>
int
xbps_humanize_number(char *buf, size_t len, int64_t bytes,
const char *suffix, int scale, int flags)
{
const char *prefixes, *sep;
int b, i, r, maxscale, s1, s2, sign;
int64_t divisor, max;
size_t baselen;
assert(buf != NULL);
assert(suffix != NULL);
assert(scale >= 0);
if (flags & HN_DIVISOR_1000) {
/* SI for decimal multiplies */
divisor = 1000;
if (flags & HN_B)
prefixes = "B\0k\0M\0G\0T\0P\0E";
else
prefixes = "\0\0k\0M\0G\0T\0P\0E";
} else {
/*
* binary multiplies
* XXX IEC 60027-2 recommends Ki, Mi, Gi...
*/
divisor = 1024;
if (flags & HN_B)
prefixes = "B\0K\0M\0G\0T\0P\0E";
else
prefixes = "\0\0K\0M\0G\0T\0P\0E";
}
#define SCALE2PREFIX(scale) (&prefixes[(scale) << 1])
maxscale = 7;
if (scale >= maxscale &&
(scale & (HN_AUTOSCALE | HN_GETSCALE)) == 0)
return (-1);
if (buf == NULL || suffix == NULL)
return (-1);
if (len > 0)
buf[0] = '\0';
if (bytes < 0) {
sign = -1;
bytes *= -100;
baselen = 3; /* sign, digit, prefix */
} else {
sign = 1;
bytes *= 100;
baselen = 2; /* digit, prefix */
}
if (flags & HN_NOSPACE)
sep = "";
else {
sep = " ";
baselen++;
}
baselen += strlen(suffix);
/* Check if enough room for `x y' + suffix + `\0' */
if (len < baselen + 1)
return (-1);
if (scale & (HN_AUTOSCALE | HN_GETSCALE)) {
/* See if there is additional columns can be used. */
for (max = 100, i = (int)(len - baselen); i-- > 0;)
max *= 10;
/*
* Divide the number until it fits the given column.
* If there will be an overflow by the rounding below,
* divide once more.
*/
for (i = 0; bytes >= max - 50 && i < maxscale; i++)
bytes /= divisor;
if (scale & HN_GETSCALE)
return (i);
} else
for (i = 0; i < scale && i < maxscale; i++)
bytes /= divisor;
/* If a value <= 9.9 after rounding and ... */
if (bytes < 995 && i > 0 && flags & HN_DECIMAL) {
/* baselen + \0 + .N */
if (len < baselen + 1 + 2)
return (-1);
b = ((int)bytes + 5) / 10;
s1 = b / 10;
s2 = b % 10;
r = snprintf(buf, len, "%d%s%d%s%s%s",
sign * s1, localeconv()->decimal_point, s2,
sep, SCALE2PREFIX(i), suffix);
} else
r = snprintf(buf, len, "%" PRId64 "%s%s%s",
sign * ((bytes + 50) / 100),
sep, SCALE2PREFIX(i), suffix);
return (r);
}

152
lib/orphans.c Normal file
View File

@ -0,0 +1,152 @@
/*-
* 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 <xbps_api.h>
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
find_orphan_pkg(prop_object_t obj, void *arg, bool *loop_done)
{
prop_array_t reqby;
prop_object_t obj2;
prop_object_iterator_t iter;
struct orphan_pkg *orphan;
char *pkgname;
unsigned int ndep = 0, cnt = 0;
bool automatic = false;
(void)arg;
(void)loop_done;
if (!prop_dictionary_get_bool(obj, "automatic-install", &automatic))
return EINVAL;
if (!automatic)
return 0;
reqby = prop_dictionary_get(obj, "requiredby");
if (reqby == NULL)
return 0;
else if (prop_object_type(reqby) != PROP_TYPE_ARRAY)
return EINVAL;
if ((cnt = prop_array_count(reqby)) == 0)
goto add_orphan;
iter = prop_array_iterator(reqby);
if (iter == NULL)
return errno;
while ((obj2 = prop_object_iterator_next(iter)) != NULL) {
pkgname = xbps_get_pkg_name(prop_string_cstring_nocopy(obj2));
SIMPLEQ_FOREACH(orphan, &orphan_list, chain) {
if (strcmp(orphan->pkgname, pkgname) == 0) {
ndep++;
break;
}
}
free(pkgname);
}
prop_object_iterator_release(iter);
if (ndep != cnt)
return 0;
add_orphan:
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;
}
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);
}
}
prop_array_t
xbps_find_orphan_packages(void)
{
prop_array_t array;
prop_dictionary_t dict;
struct orphan_pkg *orphan;
int rv = 0;
if ((dict = xbps_prepare_regpkgdb_dict()) == NULL)
return NULL;
/*
* Find out all orphans by looking at the
* regpkgdb dictionary and iterate in reverse order
* in which packages were installed.
*/
rv = xbps_callback_array_iter_reverse_in_dict(dict, "packages",
find_orphan_pkg, NULL);
if (rv != 0) {
cleanup();
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) {
prop_array_add(array, orphan->dict);
SIMPLEQ_REMOVE(&orphan_list, orphan, orphan_pkg, chain);
prop_object_release(orphan->dict);
free(orphan);
}
return array;
}

458
lib/plist.c Normal file
View File

@ -0,0 +1,458 @@
/*-
* Copyright (c) 2008-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 <xbps_api.h>
static prop_dictionary_t regpkgdb_dict;
static bool regpkgdb_initialized;
bool
xbps_add_obj_to_dict(prop_dictionary_t dict, prop_object_t obj,
const char *key)
{
assert(dict != NULL);
assert(obj != NULL);
assert(key != NULL);
if (!prop_dictionary_set(dict, key, obj)) {
prop_object_release(dict);
return false;
}
prop_object_release(obj);
return true;
}
bool
xbps_add_obj_to_array(prop_array_t array, prop_object_t obj)
{
assert(array != NULL);
assert(obj != NULL);
if (!prop_array_add(array, obj)) {
prop_object_release(array);
return false;
}
prop_object_release(obj);
return true;
}
int
xbps_callback_array_iter_in_repolist(int (*fn)(prop_object_t, void *, bool *),
void *arg)
{
prop_dictionary_t repolistd;
const char *rootdir;
char *plist;
int rv = 0;
assert(fn != NULL);
rootdir = xbps_get_rootdir();
plist = xbps_xasprintf("%s/%s/%s", rootdir,
XBPS_META_PATH, XBPS_REPOLIST);
if (plist == NULL)
return EINVAL;
/*
* Get the dictionary with the list of registered repositories.
*/
repolistd = prop_dictionary_internalize_from_file(plist);
if (repolistd == NULL)
return EINVAL;
/*
* Iterate over the repository pool and run the associated
* callback function. The loop is stopped when the bool
* argument is true or the cb returns non 0.
*/
rv = xbps_callback_array_iter_in_dict(repolistd, "repository-list",
fn, arg);
prop_object_release(repolistd);
free(plist);
return rv;
}
int
xbps_callback_array_iter_in_dict(prop_dictionary_t dict, const char *key,
int (*fn)(prop_object_t, void *, bool *),
void *arg)
{
prop_object_iterator_t iter;
prop_object_t obj;
int rv = 0;
bool cbloop_done = false;
assert(dict != NULL);
assert(key != NULL);
assert(fn != NULL);
iter = xbps_get_array_iter_from_dict(dict, key);
if (iter == NULL)
return EINVAL;
while ((obj = prop_object_iterator_next(iter))) {
rv = (*fn)(obj, arg, &cbloop_done);
if (rv != 0 || cbloop_done)
break;
}
prop_object_iterator_release(iter);
return rv;
}
int
xbps_callback_array_iter_reverse_in_dict(prop_dictionary_t dict,
const char *key, int (*fn)(prop_object_t, void *, bool *), void *arg)
{
prop_array_t array;
prop_object_t obj;
int rv = 0;
bool cbloop_done = false;
unsigned int cnt = 0;
assert(dict != NULL);
assert(key != NULL);
assert(fn != NULL);
array = prop_dictionary_get(dict, key);
if (array == NULL || prop_object_type(array) != PROP_TYPE_ARRAY)
return EINVAL;
if ((cnt = prop_array_count(array)) == 0)
return 0;
while (cnt--) {
obj = prop_array_get(array, cnt);
rv = (*fn)(obj, arg, &cbloop_done);
if (rv != 0 || cbloop_done)
break;
}
return rv;
}
prop_dictionary_t
xbps_find_pkg_from_plist(const char *plist, const char *pkgname)
{
prop_dictionary_t dict, obj, res;
assert(plist != NULL);
assert(pkgname != NULL);
dict = prop_dictionary_internalize_from_file(plist);
if (dict == NULL) {
errno = ENOENT;
return NULL;
}
obj = xbps_find_pkg_in_dict(dict, "packages", pkgname);
if (obj == NULL) {
prop_object_release(dict);
errno = ENOENT;
return NULL;
}
res = prop_dictionary_copy(obj);
prop_object_release(dict);
return res;
}
prop_dictionary_t
xbps_find_pkg_installed_from_plist(const char *pkgname)
{
prop_dictionary_t d, pkgd;
pkg_state_t state = 0;
d = xbps_prepare_regpkgdb_dict();
if (d == NULL)
return NULL;
pkgd = xbps_find_pkg_in_dict(d, "packages", pkgname);
if (pkgd == NULL)
return NULL;
if (xbps_get_pkg_state_installed(pkgname, &state) != 0)
return NULL;
switch (state) {
case XBPS_PKG_STATE_INSTALLED:
case XBPS_PKG_STATE_UNPACKED:
return prop_dictionary_copy(pkgd);
default:
return NULL;
}
}
prop_dictionary_t
xbps_find_pkg_in_dict(prop_dictionary_t dict, const char *key,
const char *pkgname)
{
prop_object_iterator_t iter;
prop_object_t obj;
const char *dpkgn;
assert(dict != NULL);
assert(pkgname != NULL);
assert(key != NULL);
iter = xbps_get_array_iter_from_dict(dict, key);
if (iter == NULL)
return NULL;
while ((obj = prop_object_iterator_next(iter))) {
prop_dictionary_get_cstring_nocopy(obj, "pkgname", &dpkgn);
if (strcmp(dpkgn, pkgname) == 0)
break;
}
prop_object_iterator_release(iter);
return obj;
}
prop_dictionary_t
xbps_prepare_regpkgdb_dict(void)
{
const char *rootdir;
char *plist;
if (regpkgdb_initialized == false) {
rootdir = xbps_get_rootdir();
plist = xbps_xasprintf("%s/%s/%s", rootdir,
XBPS_META_PATH, XBPS_REGPKGDB);
if (plist == NULL)
return NULL;
regpkgdb_dict = prop_dictionary_internalize_from_file(plist);
if (regpkgdb_dict == NULL) {
free(plist);
return NULL;
}
free(plist);
regpkgdb_initialized = true;
}
return regpkgdb_dict;
}
void
xbps_release_regpkgdb_dict(void)
{
if (regpkgdb_initialized == false)
return;
prop_object_release(regpkgdb_dict);
regpkgdb_dict = NULL;
regpkgdb_initialized = false;
}
bool
xbps_find_string_in_array(prop_array_t array, const char *val)
{
prop_object_iterator_t iter;
prop_object_t obj;
assert(array != NULL);
assert(val != NULL);
iter = prop_array_iterator(array);
if (iter == NULL)
return false;
while ((obj = prop_object_iterator_next(iter)) != NULL) {
if (prop_object_type(obj) != PROP_TYPE_STRING)
continue;
if (prop_string_equals_cstring(obj, val)) {
prop_object_iterator_release(iter);
return true;
}
}
prop_object_iterator_release(iter);
return false;
}
prop_object_iterator_t
xbps_get_array_iter_from_dict(prop_dictionary_t dict, const char *key)
{
prop_array_t array;
assert(dict != NULL);
assert(key != NULL);
array = prop_dictionary_get(dict, key);
if (array == NULL || prop_object_type(array) != PROP_TYPE_ARRAY)
return NULL;
return prop_array_iterator(array);
}
int
xbps_remove_string_from_array(prop_array_t array, const char *str)
{
prop_object_t obj;
prop_object_iterator_t iter;
size_t idx = 0;
bool found = false;
assert(array != NULL);
assert(str != NULL);
iter = prop_array_iterator(array);
if (iter == NULL)
return ENOMEM;
while ((obj = prop_object_iterator_next(iter)) != NULL) {
if (prop_object_type(obj) != PROP_TYPE_STRING)
continue;
if (prop_string_equals_cstring(obj, str)) {
found = true;
break;
}
idx++;
}
prop_object_iterator_release(iter);
if (found == false)
return ENOENT;
prop_array_remove(array, idx);
return 0;
}
int
xbps_remove_pkg_from_dict(prop_dictionary_t dict, const char *key,
const char *pkgname)
{
prop_array_t array;
prop_object_t obj;
prop_object_iterator_t iter;
const char *curpkgname;
size_t i = 0;
bool found = false;
assert(dict != NULL);
assert(key != NULL);
assert(pkgname != NULL);
array = prop_dictionary_get(dict, key);
if (array == NULL || prop_object_type(array) != PROP_TYPE_ARRAY)
return EINVAL;
iter = prop_array_iterator(array);
if (iter == NULL)
return errno;
/* Iterate over the array of dictionaries to find its index. */
while ((obj = prop_object_iterator_next(iter))) {
prop_dictionary_get_cstring_nocopy(obj, "pkgname",
&curpkgname);
if ((curpkgname && (strcmp(curpkgname, pkgname) == 0))) {
found = true;
break;
}
i++;
}
prop_object_iterator_release(iter);
if (found == true)
prop_array_remove(array, i);
else
return ENOENT;
return 0;
}
int
xbps_remove_pkg_dict_from_file(const char *pkg, const char *plist)
{
prop_dictionary_t pdict;
int rv = 0;
assert(pkg != NULL);
assert(plist != NULL);
pdict = prop_dictionary_internalize_from_file(plist);
if (pdict == NULL)
return errno;
rv = xbps_remove_pkg_from_dict(pdict, "packages", pkg);
if (rv != 0) {
prop_object_release(pdict);
return rv;
}
if (!prop_dictionary_externalize_to_file(pdict, plist)) {
prop_object_release(pdict);
return errno;
}
prop_object_release(pdict);
return 0;
}
prop_dictionary_t
xbps_read_dict_from_archive_entry(struct archive *ar,
struct archive_entry *entry)
{
prop_dictionary_t d;
size_t buflen = 0;
ssize_t nbytes = -1;
char *buf;
assert(ar != NULL);
assert(entry != NULL);
buflen = (size_t)archive_entry_size(entry);
buf = malloc(buflen);
if (buf == NULL)
return NULL;
nbytes = archive_read_data(ar, buf, buflen);
if ((size_t)nbytes != buflen) {
free(buf);
return NULL;
}
d = prop_dictionary_internalize(buf);
free(buf);
if (d == NULL)
return NULL;
else if (prop_object_type(d) != PROP_TYPE_DICTIONARY) {
prop_object_release(d);
return NULL;
}
return d;
}

203
lib/purge.c Normal file
View File

@ -0,0 +1,203 @@
/*-
* 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 <stdlib.h>
#include <string.h>
#include <errno.h>
#include <dirent.h>
#include <xbps_api.h>
static int remove_pkg_metadata(const char *);
/*
* Purge a package that is currently in "config-files" state.
* This removes configuration files if they weren't modified,
* removes metadata files and fully unregisters the package.
*/
int
xbps_purge_pkg(const char *pkgname)
{
prop_dictionary_t dict;
prop_array_t array;
prop_object_t obj;
prop_object_iterator_t iter;
const char *rootdir, *file, *sha256;
char *path;
int rv = 0, flags;
pkg_state_t state = 0;
assert(pkgname != NULL);
rootdir = xbps_get_rootdir();
flags = xbps_get_flags();
/*
* Skip packages that aren't in "config-files" state.
*/
if ((rv = xbps_get_pkg_state_installed(pkgname, &state)) != 0)
return rv;
if (state != XBPS_PKG_STATE_CONFIG_FILES)
return 0;
/*
* Iterate over the pkg file list dictionary and remove all
* unmodified configuration files.
*/
path = xbps_xasprintf("%s/%s/metadata/%s/%s",
rootdir, XBPS_META_PATH, pkgname, XBPS_PKGFILES);
if (path == NULL)
return errno;
dict = prop_dictionary_internalize_from_file(path);
if (dict == NULL) {
free(path);
return errno;
}
free(path);
array = prop_dictionary_get(dict, "conf_files");
if (array == NULL) {
goto out;
} else if (prop_object_type(array) != PROP_TYPE_ARRAY) {
prop_object_release(dict);
return EINVAL;
} else if (prop_array_count(array) == 0) {
goto out;
}
iter = xbps_get_array_iter_from_dict(dict, "conf_files");
if (iter == NULL)
return EINVAL;
while ((obj = prop_object_iterator_next(iter))) {
if (!prop_dictionary_get_cstring_nocopy(obj, "file", &file)) {
prop_object_iterator_release(iter);
prop_object_release(dict);
return EINVAL;
}
path = xbps_xasprintf("%s/%s", rootdir, file);
if (path == NULL) {
prop_object_iterator_release(iter);
prop_object_release(dict);
return EINVAL;
}
prop_dictionary_get_cstring_nocopy(obj, "sha256", &sha256);
rv = xbps_check_file_hash(path, sha256);
if (rv == ENOENT) {
printf("Configuration file %s doesn't exist!\n", file);
free(path);
continue;
} else if (rv == ERANGE) {
if (flags & XBPS_FLAG_VERBOSE)
printf("Configuration file %s has been "
"modified, preserving...\n", file);
free(path);
continue;
} else if (rv != 0 && rv != ERANGE) {
free(path);
prop_object_iterator_release(iter);
prop_object_release(dict);
return rv;
}
if ((rv = remove(path)) == -1) {
if (flags & XBPS_FLAG_VERBOSE)
printf("WARNING: can't remove %s (%s)\n",
file, strerror(errno));
free(path);
continue;
}
if (flags & XBPS_FLAG_VERBOSE)
printf("Removed configuration file %s\n", file);
free(path);
}
prop_object_iterator_release(iter);
out:
prop_object_release(dict);
if ((rv = remove_pkg_metadata(pkgname)) == 0) {
if ((rv = xbps_unregister_pkg(pkgname)) == 0)
printf("Package %s has been purged successfully.\n",
pkgname);
}
return rv;
}
static int
remove_pkg_metadata(const char *pkgname)
{
struct dirent *dp;
DIR *dirp;
const char *rootdir;
char *metadir, *path;
int flags = 0, rv = 0;
assert(pkgname != NULL);
rootdir = xbps_get_rootdir();
flags = xbps_get_flags();
metadir = xbps_xasprintf("%s/%s/metadata/%s", rootdir,
XBPS_META_PATH, pkgname);
if (metadir == NULL)
return errno;
dirp = opendir(metadir);
if (dirp == NULL) {
free(metadir);
return errno;
}
while ((dp = readdir(dirp)) != NULL) {
if ((strcmp(dp->d_name, ".") == 0) ||
(strcmp(dp->d_name, "..") == 0))
continue;
path = xbps_xasprintf("%s/%s", metadir, dp->d_name);
if (path == NULL) {
(void)closedir(dirp);
free(metadir);
return -1;
}
if ((rv = unlink(path)) == -1) {
if (flags & XBPS_FLAG_VERBOSE)
printf("WARNING: can't remove %s (%s)\n",
pkgname, strerror(errno));
}
free(path);
}
(void)closedir(dirp);
rv = rmdir(metadir);
free(metadir);
return rv;
}

114
lib/register.c Normal file
View File

@ -0,0 +1,114 @@
/*-
* Copyright (c) 2008-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 <stdlib.h>
#include <string.h>
#include <errno.h>
#include <xbps_api.h>
int
xbps_register_pkg(prop_dictionary_t pkgrd, bool automatic)
{
prop_dictionary_t dict, pkgd;
prop_array_t array;
const char *pkgname, *version, *desc, *rootdir;
char *plist;
int rv = 0;
rootdir = xbps_get_rootdir();
plist = xbps_xasprintf("%s/%s/%s", rootdir,
XBPS_META_PATH, XBPS_REGPKGDB);
if (plist == NULL)
return EINVAL;
prop_dictionary_get_cstring_nocopy(pkgrd, "pkgname", &pkgname);
prop_dictionary_get_cstring_nocopy(pkgrd, "version", &version);
prop_dictionary_get_cstring_nocopy(pkgrd, "short_desc", &desc);
dict = prop_dictionary_internalize_from_file(plist);
if (dict != NULL) {
pkgd = xbps_find_pkg_in_dict(dict, "packages", pkgname);
if (pkgd == NULL) {
rv = ENOENT;
goto out;
}
prop_dictionary_set_cstring_nocopy(pkgd, "version", version);
prop_dictionary_set_cstring_nocopy(pkgd, "short_desc", desc);
prop_dictionary_set_bool(pkgd, "automatic-install", automatic);
/*
* Add the requiredby objects for dependent packages.
*/
if (pkgrd && xbps_pkg_has_rundeps(pkgrd)) {
array = prop_dictionary_get(dict, "packages");
if (array == NULL) {
prop_object_release(pkgd);
rv = ENOENT;
goto out;
}
rv = xbps_requiredby_pkg_add(array, pkgrd);
if (rv != 0) {
prop_object_release(pkgd);
goto out;
}
}
/*
* Write plist file to storage.
*/
if (!prop_dictionary_externalize_to_file(dict, plist))
rv = errno;
} else {
free(plist);
return ENOENT;
}
out:
prop_object_release(dict);
free(plist);
return rv;
}
int
xbps_unregister_pkg(const char *pkgname)
{
const char *rootdir;
char *plist;
int rv = 0;
assert(pkgname != NULL);
rootdir = xbps_get_rootdir();
plist = xbps_xasprintf("%s/%s/%s", rootdir,
XBPS_META_PATH, XBPS_REGPKGDB);
if (plist == NULL)
return EINVAL;
rv = xbps_remove_pkg_dict_from_file(pkgname, plist);
free(plist);
return rv;
}

288
lib/remove.c Normal file
View File

@ -0,0 +1,288 @@
/*-
* 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 <dirent.h>
#include <xbps_api.h>
static int remove_pkg_files(prop_dictionary_t);
static int
remove_pkg_files(prop_dictionary_t dict)
{
prop_array_t array;
prop_object_iterator_t iter;
prop_object_t obj;
prop_bool_t bobj;
const char *file, *rootdir, *sha256;
char *path = NULL;
int flags = 0, rv = 0;
rootdir = xbps_get_rootdir();
flags = xbps_get_flags();
/* Links */
array = prop_dictionary_get(dict, "links");
if (array == NULL || prop_array_count(array) == 0)
goto files;
iter = xbps_get_array_iter_from_dict(dict, "links");
if (iter == NULL)
return EINVAL;
while ((obj = prop_object_iterator_next(iter))) {
if (!prop_dictionary_get_cstring_nocopy(obj, "file", &file)) {
prop_object_iterator_release(iter);
return EINVAL;
}
path = xbps_xasprintf("%s/%s", rootdir, file);
if (path == NULL) {
prop_object_iterator_release(iter);
return EINVAL;
}
if ((rv = remove(path)) == -1) {
if (flags & XBPS_FLAG_VERBOSE)
printf("WARNING: can't remove link %s (%s)\n",
file, strerror(errno));
free(path);
continue;
}
if (flags & XBPS_FLAG_VERBOSE)
printf("Removed link: %s\n", file);
free(path);
}
prop_object_iterator_release(iter);
path = NULL;
files:
/* Regular files */
array = prop_dictionary_get(dict, "files");
if (array == NULL || prop_array_count(array) == 0)
goto dirs;
iter = xbps_get_array_iter_from_dict(dict, "files");
if (iter == NULL)
return EINVAL;
while ((obj = prop_object_iterator_next(iter))) {
if (!prop_dictionary_get_cstring_nocopy(obj, "file", &file)) {
prop_object_iterator_release(iter);
return EINVAL;
}
path = xbps_xasprintf("%s/%s", rootdir, file);
if (path == NULL) {
prop_object_iterator_release(iter);
return EINVAL;
}
prop_dictionary_get_cstring_nocopy(obj, "sha256", &sha256);
rv = xbps_check_file_hash(path, sha256);
if (rv == ENOENT) {
printf("WARNING: '%s' doesn't exist!\n", file);
free(path);
continue;
} else if (rv == ERANGE) {
if (flags & XBPS_FLAG_VERBOSE)
printf("WARNING: SHA256 doesn't match "
"for file %s, ignoring...\n", file);
free(path);
continue;
} else if (rv != 0 && rv != ERANGE) {
free(path);
prop_object_iterator_release(iter);
return rv;
}
if ((rv = remove(path)) == -1) {
if (flags & XBPS_FLAG_VERBOSE)
printf("WARNING: can't remove file %s (%s)\n",
file, strerror(errno));
free(path);
continue;
}
if (flags & XBPS_FLAG_VERBOSE)
printf("Removed file: %s\n", file);
free(path);
}
prop_object_iterator_release(iter);
path = NULL;
dirs:
/* Directories */
array = prop_dictionary_get(dict, "dirs");
if (array == NULL || prop_array_count(array) == 0)
return 0;
iter = xbps_get_array_iter_from_dict(dict, "dirs");
if (iter == NULL)
return EINVAL;
while ((obj = prop_object_iterator_next(iter))) {
if ((bobj = prop_dictionary_get(obj, "keep")) != NULL) {
/* Skip permanent directory. */
continue;
}
if (!prop_dictionary_get_cstring_nocopy(obj, "file", &file)) {
prop_object_iterator_release(iter);
return EINVAL;
}
path = xbps_xasprintf("%s/%s", rootdir, file);
if (path == NULL) {
prop_object_iterator_release(iter);
return EINVAL;
}
if ((rv = rmdir(path)) == -1) {
if (errno == ENOTEMPTY) {
free(path);
continue;
}
if (flags & XBPS_FLAG_VERBOSE) {
printf("WARNING: can't remove "
"directory %s (%s)\n", file,
strerror(errno));
free(path);
continue;
}
}
if (flags & XBPS_FLAG_VERBOSE)
printf("Removed directory: %s\n", file);
free(path);
}
prop_object_iterator_release(iter);
return 0;
}
int
xbps_remove_pkg(const char *pkgname, const char *version, bool update)
{
prop_dictionary_t dict;
const char *rootdir = xbps_get_rootdir();
char *path, *buf;
int rv = 0;
bool prepostf = false;
assert(pkgname != NULL);
assert(version != NULL);
/*
* Check if pkg is installed before anything else.
*/
if (xbps_check_is_installed_pkgname(pkgname) == false)
return ENOENT;
if (strcmp(rootdir, "") == 0)
rootdir = "/";
if (chdir(rootdir) == -1)
return errno;
buf = xbps_xasprintf(".%s/metadata/%s/REMOVE",
XBPS_META_PATH, pkgname);
if (buf == NULL)
return errno;
/*
* Find out if the REMOVE file exists.
*/
if (access(buf, R_OK) == 0) {
/*
* Run the pre remove action.
*/
prepostf = true;
rv = xbps_file_chdir_exec(rootdir, buf, "pre", pkgname,
version, NULL);
if (rv != 0) {
printf("%s: prerm action target error (%s)\n", pkgname,
strerror(errno));
free(buf);
return rv;
}
}
/*
* Iterate over the pkg file list dictionary and remove all
* files, configuration files, links and dirs.
*/
path = xbps_xasprintf("%s/%s/metadata/%s/%s",
rootdir, XBPS_META_PATH, pkgname, XBPS_PKGFILES);
if (path == NULL) {
free(buf);
return errno;
}
dict = prop_dictionary_internalize_from_file(path);
if (dict == NULL) {
free(buf);
free(path);
return errno;
}
free(path);
rv = remove_pkg_files(dict);
if (rv != 0) {
free(buf);
prop_object_release(dict);
return rv;
}
prop_object_release(dict);
/*
* Run the post remove action if REMOVE file is there
* and we aren't updating a package.
*/
if (update == false && prepostf) {
if ((rv = xbps_file_chdir_exec(rootdir, buf, "post",
pkgname, version, NULL)) != 0) {
printf("%s: postrm action target error (%s)\n",
pkgname, strerror(errno));
free(buf);
return rv;
}
}
free(buf);
/*
* Update the requiredby array of all required dependencies.
*/
if ((rv = xbps_requiredby_pkg_remove(pkgname)) != 0)
return rv;
/*
* Set package state to "config-files".
*/
rv = xbps_set_pkg_state_installed(pkgname,
XBPS_PKG_STATE_CONFIG_FILES);
return rv;
}

151
lib/repository.c Normal file
View File

@ -0,0 +1,151 @@
/*-
* Copyright (c) 2008-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 <stdlib.h>
#include <string.h>
#include <errno.h>
#include <xbps_api.h>
int
xbps_register_repository(const char *uri)
{
prop_dictionary_t dict;
prop_array_t array;
prop_object_t obj = NULL;
const char *rootdir;
char *plist;
int rv = 0;
assert(uri != NULL);
rootdir = xbps_get_rootdir();
plist = xbps_xasprintf("%s/%s/%s", rootdir,
XBPS_META_PATH, XBPS_REPOLIST);
if (plist == NULL)
return errno;
/* First check if we have the repository plist file. */
dict = prop_dictionary_internalize_from_file(plist);
if (dict == NULL) {
/* Looks like not, create it. */
dict = prop_dictionary_create();
if (dict == NULL) {
rv = errno;
goto out2;
}
/* Create the array and add the repository URI on it. */
array = prop_array_create();
if (array == NULL) {
rv = errno;
goto out;
}
if (!prop_array_set_cstring_nocopy(array, 0, uri)) {
rv = errno;
goto out;
}
/* Add the array obj into the main dictionary. */
if (!xbps_add_obj_to_dict(dict, array, "repository-list")) {
rv = errno;
goto out;
}
} else {
/* Append into the array, the plist file exists. */
array = prop_dictionary_get(dict, "repository-list");
if (array == NULL) {
rv = errno;
goto out;
}
/* It seems that this object is already there */
if (xbps_find_string_in_array(array, uri)) {
errno = EEXIST;
goto out;
}
obj = prop_string_create_cstring(uri);
if (!xbps_add_obj_to_array(array, obj)) {
prop_object_release(obj);
rv = errno;
goto out;
}
}
/* Write dictionary into plist file. */
if (!prop_dictionary_externalize_to_file(dict, plist)) {
if (obj)
prop_object_release(obj);
rv = errno;
}
out:
prop_object_release(dict);
out2:
free(plist);
return rv;
}
int
xbps_unregister_repository(const char *uri)
{
prop_dictionary_t dict;
prop_array_t array;
const char *rootdir;
char *plist;
int rv = 0;
assert(uri != NULL);
rootdir = xbps_get_rootdir();
plist = xbps_xasprintf("%s/%s/%s", rootdir,
XBPS_META_PATH, XBPS_REPOLIST);
if (plist == NULL)
return errno;
dict = prop_dictionary_internalize_from_file(plist);
if (dict == NULL) {
free(plist);
return errno;
}
array = prop_dictionary_get(dict, "repository-list");
if (array == NULL) {
rv = errno;
goto out;
}
rv = xbps_remove_string_from_array(array, uri);
if (rv == 0) {
/* Update plist file. */
if (!prop_dictionary_externalize_to_file(dict, plist))
rv = errno;
}
out:
prop_object_release(dict);
free(plist);
return rv;
}

215
lib/requiredby.c Normal file
View File

@ -0,0 +1,215 @@
/*-
* 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 <xbps_api.h>
static int
add_pkg_into_reqby(prop_dictionary_t pkgd, const char *reqname)
{
prop_array_t array;
prop_string_t reqstr;
bool alloc = false;
array = prop_dictionary_get(pkgd, "requiredby");
if (array == NULL) {
alloc = true;
array = prop_array_create();
if (array == NULL)
return ENOMEM;
}
if (xbps_find_string_in_array(array, reqname))
return EEXIST;
reqstr = prop_string_create_cstring(reqname);
if (reqstr == NULL) {
if (alloc)
prop_object_release(array);
return errno;
}
if (!xbps_add_obj_to_array(array, reqstr)) {
if (alloc)
prop_object_release(array);
prop_object_release(reqstr);
return EINVAL;
}
if (!alloc)
return 0;
if (!xbps_add_obj_to_dict(pkgd, array, "requiredby")) {
if (alloc)
prop_object_release(array);
return EINVAL;
}
return 0;
}
static int
remove_pkg_from_reqby(prop_object_t obj, void *arg, bool *loop_done)
{
prop_array_t array;
prop_object_t obj2;
prop_object_iterator_t iter;
const char *pkgname = arg;
char *curpkgname;
size_t idx = 0;
bool found = false;
(void)loop_done;
array = prop_dictionary_get(obj, "requiredby");
if (array == NULL || prop_array_count(array) == 0)
return 0;
iter = prop_array_iterator(array);
if (iter == NULL)
return ENOMEM;
while ((obj2 = prop_object_iterator_next(iter)) != NULL) {
curpkgname =
xbps_get_pkg_name(prop_string_cstring_nocopy(obj2));
if (strcmp(curpkgname, pkgname) == 0) {
free(curpkgname);
found = true;
break;
}
free(curpkgname);
idx++;
}
prop_object_iterator_release(iter);
if (found)
prop_array_remove(array, idx);
return 0;
}
int
xbps_requiredby_pkg_remove(const char *pkgname)
{
prop_dictionary_t dict;
const char *rootdir;
char *plist;
int rv = 0;
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) {
free(plist);
return errno;
}
rv = xbps_callback_array_iter_in_dict(dict, "packages",
remove_pkg_from_reqby, __UNCONST(pkgname));
if (rv == 0) {
if (!prop_dictionary_externalize_to_file(dict, plist))
rv = errno;
}
prop_object_release(dict);
free(plist);
return rv;
}
int
xbps_requiredby_pkg_add(prop_array_t regar, prop_dictionary_t pkg)
{
prop_array_t rdeps;
prop_object_t obj, obj2;
prop_object_iterator_t iter, iter2;
const char *reqname, *pkgname, *version;
char *rdepname, *fpkgn;
int rv = 0;
prop_dictionary_get_cstring_nocopy(pkg, "pkgname", &pkgname);
prop_dictionary_get_cstring_nocopy(pkg, "version", &version);
fpkgn = xbps_xasprintf("%s-%s", pkgname, version);
if (fpkgn == NULL)
return ENOMEM;
rdeps = prop_dictionary_get(pkg, "run_depends");
if (rdeps == NULL || prop_array_count(rdeps) == 0) {
free(fpkgn);
return EINVAL;
}
iter = prop_array_iterator(rdeps);
if (iter == NULL) {
free(fpkgn);
return ENOMEM;
}
while ((obj = prop_object_iterator_next(iter)) != NULL) {
rdepname = xbps_get_pkg_name(prop_string_cstring_nocopy(obj));
iter2 = prop_array_iterator(regar);
if (iter2 == NULL) {
free(rdepname);
rv = ENOMEM;
goto out;
}
/*
* Iterate over the array to find the dictionary for the
* current run dependency.
*/
while ((obj2 = prop_object_iterator_next(iter2)) != NULL) {
prop_dictionary_get_cstring_nocopy(obj2, "pkgname",
&reqname);
if (strcmp(rdepname, reqname) == 0) {
rv = add_pkg_into_reqby(obj2, fpkgn);
if (rv != 0) {
free(rdepname);
prop_object_iterator_release(iter2);
goto out;
}
break;
}
}
prop_object_iterator_release(iter2);
free(rdepname);
}
out:
free(fpkgn);
prop_object_iterator_release(iter);
return rv;
}

466
lib/sha256.c Normal file
View File

@ -0,0 +1,466 @@
/* $NetBSD: sha2.c,v 1.18 2009/06/25 14:05:18 joerg Exp $ */
/* $KAME: sha2.c,v 1.9 2003/07/20 00:28:38 itojun Exp $ */
/*
* sha2.c
*
* Version 1.0.0beta1
*
* Written by Aaron D. Gifford <me@aarongifford.com>
*
* Copyright 2000 Aaron D. Gifford. 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.
* 3. Neither the name of the copyright holder nor the names of contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTOR(S) ``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(S) OR CONTRIBUTOR(S) 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 <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <inttypes.h>
#include <libgen.h>
#include "xbps_api.h"
/*** SHA-256 Various Length Definitions ***********************/
/* NOTE: Most of these are in sha2.h */
#define SHA256_SHORT_BLOCK_LENGTH (SHA256_BLOCK_LENGTH - 8)
/*** THE SIX LOGICAL FUNCTIONS ****************************************/
/*
* Bit shifting and rotation (used by the six SHA-XYZ logical functions:
*
* NOTE: The naming of R and S appears backwards here (R is a SHIFT and
* S is a ROTATION) because the SHA-256/384/512 description document
* (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this
* same "backwards" definition.
*/
/* Shift-right (used in SHA-256, SHA-384, and SHA-512): */
#define R(b,x) ((x) >> (b))
/* 32-bit Rotate-right (used in SHA-256): */
#define S32(b,x) (((x) >> (b)) | ((x) << (32 - (b))))
/* Two of six logical functions used in SHA-256, SHA-384, and SHA-512: */
#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z)))
#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
/* Four of six logical functions used in SHA-256: */
#define Sigma0_256(x) (S32(2, (x)) ^ S32(13, (x)) ^ S32(22, (x)))
#define Sigma1_256(x) (S32(6, (x)) ^ S32(11, (x)) ^ S32(25, (x)))
#define sigma0_256(x) (S32(7, (x)) ^ S32(18, (x)) ^ R(3 , (x)))
#define sigma1_256(x) (S32(17, (x)) ^ S32(19, (x)) ^ R(10, (x)))
/*** INTERNAL FUNCTION PROTOTYPES *************************************/
/* NOTE: These should not be accessed directly from outside this
* library -- they are intended for private internal visibility/use
* only.
*/
static void SHA256_Transform(SHA256_CTX *, const uint32_t*);
static int SHA256_Final(uint8_t *, SHA256_CTX *);
/*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/
/* Hash constant words K for SHA-256: */
static const uint32_t K256[64] = {
0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL,
0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL,
0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL,
0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL,
0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL,
0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL,
0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL,
0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL,
0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL,
0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL,
0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL,
0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL,
0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
};
/* Initial hash value H for SHA-256: */
static const uint32_t sha256_initial_hash_value[8] = {
0x6a09e667UL,
0xbb67ae85UL,
0x3c6ef372UL,
0xa54ff53aUL,
0x510e527fUL,
0x9b05688cUL,
0x1f83d9abUL,
0x5be0cd19UL
};
/*** SHA-256: *********************************************************/
int
SHA256_Init(SHA256_CTX *context)
{
if (context == NULL)
return 1;
memcpy(context->state, sha256_initial_hash_value,
(size_t)(SHA256_DIGEST_LENGTH));
memset(context->buffer, 0, (size_t)(SHA256_BLOCK_LENGTH));
context->bitcount = 0;
return 1;
}
#ifdef SHA2_UNROLL_TRANSFORM
/* Unrolled SHA-256 round macros: */
#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \
W256[j] = be32toh(*data); \
++data; \
T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \
K256[j] + W256[j]; \
(d) += T1; \
(h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \
j++
#define ROUND256(a,b,c,d,e,f,g,h) \
s0 = W256[(j+1)&0x0f]; \
s0 = sigma0_256(s0); \
s1 = W256[(j+14)&0x0f]; \
s1 = sigma1_256(s1); \
T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + \
(W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \
(d) += T1; \
(h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \
j++
static void
SHA256_Transform(SHA256_CTX *context, const uint32_t *data)
{
uint32_t a, b, c, d, e, f, g, h, s0, s1;
uint32_t T1, *W256;
int j;
W256 = (uint32_t *)context->buffer;
/* Initialize registers with the prev. intermediate value */
a = context->state[0];
b = context->state[1];
c = context->state[2];
d = context->state[3];
e = context->state[4];
f = context->state[5];
g = context->state[6];
h = context->state[7];
j = 0;
do {
/* Rounds 0 to 15 (unrolled): */
ROUND256_0_TO_15(a,b,c,d,e,f,g,h);
ROUND256_0_TO_15(h,a,b,c,d,e,f,g);
ROUND256_0_TO_15(g,h,a,b,c,d,e,f);
ROUND256_0_TO_15(f,g,h,a,b,c,d,e);
ROUND256_0_TO_15(e,f,g,h,a,b,c,d);
ROUND256_0_TO_15(d,e,f,g,h,a,b,c);
ROUND256_0_TO_15(c,d,e,f,g,h,a,b);
ROUND256_0_TO_15(b,c,d,e,f,g,h,a);
} while (j < 16);
/* Now for the remaining rounds to 64: */
do {
ROUND256(a,b,c,d,e,f,g,h);
ROUND256(h,a,b,c,d,e,f,g);
ROUND256(g,h,a,b,c,d,e,f);
ROUND256(f,g,h,a,b,c,d,e);
ROUND256(e,f,g,h,a,b,c,d);
ROUND256(d,e,f,g,h,a,b,c);
ROUND256(c,d,e,f,g,h,a,b);
ROUND256(b,c,d,e,f,g,h,a);
} while (j < 64);
/* Compute the current intermediate hash value */
context->state[0] += a;
context->state[1] += b;
context->state[2] += c;
context->state[3] += d;
context->state[4] += e;
context->state[5] += f;
context->state[6] += g;
context->state[7] += h;
/* Clean up */
a = b = c = d = e = f = g = h = T1 = 0;
}
#else /* SHA2_UNROLL_TRANSFORM */
void
SHA256_Transform(SHA256_CTX *context, const uint32_t *data)
{
uint32_t a, b, c, d, e, f, g, h, s0, s1;
uint32_t T1, T2, *W256;
int j;
W256 = (uint32_t *)(void *)context->buffer;
/* Initialize registers with the prev. intermediate value */
a = context->state[0];
b = context->state[1];
c = context->state[2];
d = context->state[3];
e = context->state[4];
f = context->state[5];
g = context->state[6];
h = context->state[7];
j = 0;
do {
W256[j] = be32toh(*data);
++data;
/* Apply the SHA-256 compression function to update a..h */
T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j];
T2 = Sigma0_256(a) + Maj(a, b, c);
h = g;
g = f;
f = e;
e = d + T1;
d = c;
c = b;
b = a;
a = T1 + T2;
j++;
} while (j < 16);
do {
/* Part of the message block expansion: */
s0 = W256[(j+1)&0x0f];
s0 = sigma0_256(s0);
s1 = W256[(j+14)&0x0f];
s1 = sigma1_256(s1);
/* Apply the SHA-256 compression function to update a..h */
T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] +
(W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0);
T2 = Sigma0_256(a) + Maj(a, b, c);
h = g;
g = f;
f = e;
e = d + T1;
d = c;
c = b;
b = a;
a = T1 + T2;
j++;
} while (j < 64);
/* Compute the current intermediate hash value */
context->state[0] += a;
context->state[1] += b;
context->state[2] += c;
context->state[3] += d;
context->state[4] += e;
context->state[5] += f;
context->state[6] += g;
context->state[7] += h;
/* Clean up */
a = b = c = d = e = f = g = h = T1 = T2 = 0;
}
#endif /* SHA2_UNROLL_TRANSFORM */
int
SHA256_Update(SHA256_CTX *context, const uint8_t *data, size_t len)
{
unsigned int freespace, usedspace;
if (len == 0) {
/* Calling with no data is valid - we do nothing */
return 1;
}
usedspace = (unsigned int)((context->bitcount >> 3) %
SHA256_BLOCK_LENGTH);
if (usedspace > 0) {
/* Calculate how much free space is available in the buffer */
freespace = SHA256_BLOCK_LENGTH - usedspace;
if (len >= freespace) {
/* Fill the buffer completely and process it */
memcpy(&context->buffer[usedspace], data,
(size_t)(freespace));
context->bitcount += freespace << 3;
len -= freespace;
data += freespace;
SHA256_Transform(context,
(uint32_t *)(void *)context->buffer);
} else {
/* The buffer is not yet full */
memcpy(&context->buffer[usedspace], data, len);
context->bitcount += len << 3;
/* Clean up: */
usedspace = freespace = 0;
return 1;
}
}
/*
* Process as many complete blocks as possible.
*
* Check alignment of the data pointer. If it is 32bit aligned,
* SHA256_Transform can be called directly on the data stream,
* otherwise enforce the alignment by copy into the buffer.
*/
if ((uintptr_t)data % 4 == 0) {
while (len >= SHA256_BLOCK_LENGTH) {
SHA256_Transform(context,
(const uint32_t *)(const void *)data);
context->bitcount += SHA256_BLOCK_LENGTH << 3;
len -= SHA256_BLOCK_LENGTH;
data += SHA256_BLOCK_LENGTH;
}
} else {
while (len >= SHA256_BLOCK_LENGTH) {
memcpy(context->buffer, data, SHA256_BLOCK_LENGTH);
SHA256_Transform(context,
(const uint32_t *)(const void *)context->buffer);
context->bitcount += SHA256_BLOCK_LENGTH << 3;
len -= SHA256_BLOCK_LENGTH;
data += SHA256_BLOCK_LENGTH;
}
}
if (len > 0) {
/* There's left-overs, so save 'em */
memcpy(context->buffer, data, len);
context->bitcount += len << 3;
}
/* Clean up: */
usedspace = freespace = 0;
return 1;
}
static int
SHA224_256_Final(uint8_t digest[], SHA256_CTX *context, size_t len)
{
uint32_t *d = (void *)digest;
unsigned int usedspace;
size_t i;
/* If no digest buffer is passed, we don't bother doing this: */
if (digest != NULL) {
usedspace = (unsigned int)((context->bitcount >> 3) %
SHA256_BLOCK_LENGTH);
context->bitcount = htobe64(context->bitcount);
if (usedspace > 0) {
/* Begin padding with a 1 bit: */
context->buffer[usedspace++] = 0x80;
if (usedspace <= SHA256_SHORT_BLOCK_LENGTH) {
/* Set-up for the last transform: */
memset(&context->buffer[usedspace], 0,
(size_t)(SHA256_SHORT_BLOCK_LENGTH -
usedspace));
} else {
if (usedspace < SHA256_BLOCK_LENGTH) {
memset(&context->buffer[usedspace], 0,
(size_t)(SHA256_BLOCK_LENGTH -
usedspace));
}
/* Do second-to-last transform: */
SHA256_Transform(context,
(uint32_t *)(void *)context->buffer);
/* And set-up for the last transform: */
memset(context->buffer, 0,
(size_t)(SHA256_SHORT_BLOCK_LENGTH));
}
} else {
/* Set-up for the last transform: */
memset(context->buffer, 0,
(size_t)(SHA256_SHORT_BLOCK_LENGTH));
/* Begin padding with a 1 bit: */
*context->buffer = 0x80;
}
/* Set the bit count: */
memcpy(&context->buffer[SHA256_SHORT_BLOCK_LENGTH],
&context->bitcount, sizeof(context->bitcount));
/* Final transform: */
SHA256_Transform(context, (uint32_t *)(void *)context->buffer);
for (i = 0; i < len / 4; i++)
d[i] = htobe32(context->state[i]);
}
/* Clean up state data: */
memset(context, 0, sizeof(*context));
usedspace = 0;
return 1;
}
static int
SHA256_Final(uint8_t digest[], SHA256_CTX *context)
{
return SHA224_256_Final(digest, context, SHA256_DIGEST_LENGTH);
}
/*
* Constant used by SHA256/384/512_End() functions for converting the
* digest to a readable hexadecimal character string:
*/
static const char sha2_hex_digits[] = "0123456789abcdef";
char *
SHA256_End(SHA256_CTX *ctx, uint8_t *buffer)
{
uint8_t digest[SHA256_DIGEST_LENGTH], *d = digest;
uint8_t *ret;
int i;
/* Sanity check: */
assert(ctx != NULL);
if ((ret = buffer) != NULL) {
SHA256_Final(digest, ctx);
for (i = 0; i < SHA256_DIGEST_LENGTH; i++) {
*buffer++ = (uint8_t)sha2_hex_digits[(*d & 0xf0) >> 4];
*buffer++ = (uint8_t)sha2_hex_digits[*d & 0x0f];
d++;
}
*buffer = (char) 0;
} else {
(void)memset(ctx, 0, sizeof(SHA256_CTX));
}
(void)memset(digest, 0, SHA256_DIGEST_LENGTH);
return (char *)ret;
}

198
lib/sortdeps.c Normal file
View File

@ -0,0 +1,198 @@
/*-
* 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 <stdlib.h>
#include <string.h>
#include <errno.h>
#include <xbps_api.h>
struct sorted_dependency {
SIMPLEQ_ENTRY(sorted_dependency) chain;
prop_dictionary_t dict;
};
static SIMPLEQ_HEAD(sdep_head, sorted_dependency) sdep_list =
SIMPLEQ_HEAD_INITIALIZER(sdep_list);
static struct sorted_dependency *
find_sorteddep_by_name(const char *pkgname)
{
struct sorted_dependency *sdep = NULL;
const char *curname;
SIMPLEQ_FOREACH(sdep, &sdep_list, chain) {
prop_dictionary_get_cstring_nocopy(sdep->dict,
"pkgname", &curname);
if (strcmp(pkgname, curname) == 0)
break;
}
return sdep;
}
int
xbps_sort_pkg_deps(prop_dictionary_t chaindeps)
{
prop_array_t sorted, unsorted, rundeps;
prop_object_t obj, obj2;
prop_object_iterator_t iter, iter2;
struct sorted_dependency *sdep;
size_t ndeps = 0, rundepscnt = 0, cnt = 0;
const char *pkgname;
char *curpkgnamedep;
int rv = 0;
assert(chaindeps != NULL);
sorted = prop_array_create();
if (sorted == NULL)
return ENOMEM;
/*
* All required deps are satisfied (already installed).
*/
unsorted = prop_dictionary_get(chaindeps, "unsorted_deps");
if (prop_array_count(unsorted) == 0) {
prop_dictionary_set(chaindeps, "packages", sorted);
return 0;
}
ndeps = prop_array_count(unsorted);
unsorted = prop_dictionary_get(chaindeps, "unsorted_deps");
iter = prop_array_iterator(unsorted);
if (iter == NULL) {
prop_object_release(sorted);
return ENOMEM;
}
again:
/*
* Order all deps by looking at its run_depends array.
*/
while ((obj = prop_object_iterator_next(iter)) != NULL) {
prop_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname);
if (find_sorteddep_by_name(pkgname) != NULL)
continue;
sdep = malloc(sizeof(*sdep));
if (sdep == NULL) {
rv = ENOMEM;
goto out;
}
/*
* Packages that don't have deps go unsorted, because
* it doesn't matter.
*/
rundeps = prop_dictionary_get(obj, "run_depends");
if (rundeps == NULL || prop_array_count(rundeps) == 0) {
sdep->dict = prop_dictionary_copy(obj);
SIMPLEQ_INSERT_TAIL(&sdep_list, sdep, chain);
cnt++;
continue;
}
iter2 = prop_array_iterator(rundeps);
if (iter2 == NULL) {
free(sdep);
rv = ENOMEM;
goto out;
}
/*
* Iterate over the run_depends array, and find out if they
* were already added in the sorted list.
*/
while ((obj2 = prop_object_iterator_next(iter2)) != NULL) {
curpkgnamedep =
xbps_get_pkg_name(prop_string_cstring_nocopy(obj2));
/*
* If dependency is already installed or queued,
* pass to the next one.
*/
if (xbps_check_is_installed_pkgname(curpkgnamedep))
rundepscnt++;
else if (find_sorteddep_by_name(curpkgnamedep) != NULL)
rundepscnt++;
free(curpkgnamedep);
}
prop_object_iterator_release(iter2);
/* Add dependency if all its required deps are already added */
if (prop_array_count(rundeps) == rundepscnt) {
sdep->dict = prop_dictionary_copy(obj);
SIMPLEQ_INSERT_TAIL(&sdep_list, sdep, chain);
rundepscnt = 0;
cnt++;
continue;
}
free(sdep);
rundepscnt = 0;
}
/* Iterate until all deps are processed. */
if (cnt < ndeps) {
prop_object_iterator_reset(iter);
goto again;
}
prop_object_iterator_release(iter);
/*
* Add all sorted dependencies into the sorted deps array.
*/
while ((sdep = SIMPLEQ_FIRST(&sdep_list)) != NULL) {
prop_array_add(sorted, sdep->dict);
SIMPLEQ_REMOVE(&sdep_list, sdep, sorted_dependency, chain);
prop_object_release(sdep->dict);
free(sdep);
}
/*
* Sanity check that the array contains the same number of
* objects than the total number of required dependencies.
*/
if (ndeps != prop_array_count(sorted)) {
rv = EINVAL;
goto out;
}
if (!prop_dictionary_set(chaindeps, "packages", sorted))
rv = EINVAL;
prop_dictionary_remove(chaindeps, "unsorted_deps");
out:
/*
* Release resources used by temporary sorting.
*/
prop_object_release(sorted);
while ((sdep = SIMPLEQ_FIRST(&sdep_list)) != NULL) {
SIMPLEQ_REMOVE(&sdep_list, sdep, sorted_dependency, chain);
prop_object_release(sdep->dict);
free(sdep);
}
return rv;
}

232
lib/state.c Normal file
View File

@ -0,0 +1,232 @@
/*-
* 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 <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;
}

454
lib/unpack.c Normal file
View File

@ -0,0 +1,454 @@
/*-
* Copyright (c) 2008-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 <fcntl.h>
#include <xbps_api.h>
static int unpack_archive_fini(struct archive *, prop_dictionary_t, bool);
static void set_extract_flags(int);
int
xbps_unpack_binary_pkg(prop_dictionary_t pkg, bool essential)
{
prop_string_t filename, repoloc, arch;
struct archive *ar;
const char *pkgname;
char *binfile;
int pkg_fd, rv = 0;
assert(pkg != NULL);
/*
* Append filename to the full path for binary pkg.
*/
prop_dictionary_get_cstring_nocopy(pkg, "pkgname", &pkgname);
filename = prop_dictionary_get(pkg, "filename");
arch = prop_dictionary_get(pkg, "architecture");
repoloc = prop_dictionary_get(pkg, "repository");
if (filename == NULL || arch == NULL || repoloc == NULL)
return ENOTSUP;
binfile = xbps_xasprintf("%s/%s/%s",
prop_string_cstring_nocopy(repoloc),
prop_string_cstring_nocopy(arch),
prop_string_cstring_nocopy(filename));
if (binfile == NULL)
return EINVAL;
if ((pkg_fd = open(binfile, O_RDONLY)) == -1) {
rv = errno;
goto out;
}
ar = archive_read_new();
if (ar == NULL) {
rv = ENOMEM;
goto out2;
}
/*
* Enable support for tar format and all compression methods.
*/
archive_read_support_compression_all(ar);
archive_read_support_format_tar(ar);
if ((rv = archive_read_open_fd(ar, pkg_fd,
ARCHIVE_READ_BLOCKSIZE)) != 0)
goto out3;
rv = unpack_archive_fini(ar, pkg, essential);
/*
* If installation of package was successful, make sure the package
* is really on storage (if possible).
*/
if (rv == 0)
if (fdatasync(pkg_fd) == -1)
rv = errno;
out3:
archive_read_finish(ar);
out2:
(void)close(pkg_fd);
out:
free(binfile);
if (rv == 0) {
/*
* Set package state to unpacked.
*/
rv = xbps_set_pkg_state_installed(pkgname,
XBPS_PKG_STATE_UNPACKED);
}
return rv;
}
/*
* 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 | \
ARCHIVE_EXTRACT_SECURE_SYMLINKS
#define FEXTRACT_FLAGS ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_PERM | \
ARCHIVE_EXTRACT_TIME | EXTRACT_FLAGS
static void
set_extract_flags(int flags)
{
if (getuid() == 0)
flags = FEXTRACT_FLAGS;
else
flags = EXTRACT_FLAGS;
}
static int
install_config_file(prop_dictionary_t d, struct archive_entry *entry,
const char *pkgname, int flags, bool skip)
{
prop_dictionary_t forigd;
prop_object_t obj, obj2;
prop_object_iterator_t iter, iter2;
const char *cffile, *sha256_new;
char *buf, *sha256_cur = NULL, *sha256_orig = NULL;
int rv = 0;
bool install_new = false;
if (d == NULL)
return 0;
iter = xbps_get_array_iter_from_dict(d, "conf_files");
if (iter == NULL)
return 0;
/*
* Get original hash for the file from current
* installed package.
*/
buf = xbps_xasprintf(".%s/metadata/%s/%s", XBPS_META_PATH,
pkgname, XBPS_PKGFILES);
if (buf == NULL)
return errno;
forigd = prop_dictionary_internalize_from_file(buf);
free(buf);
if (forigd != NULL) {
iter2 = xbps_get_array_iter_from_dict(forigd, "conf_files");
if (iter2 != NULL) {
while ((obj2 = prop_object_iterator_next(iter2))) {
prop_dictionary_get_cstring_nocopy(obj2,
"file", &cffile);
if (strstr(archive_entry_pathname(entry),
cffile)) {
prop_dictionary_get_cstring(obj2,
"sha256", &sha256_orig);
break;
}
}
prop_object_iterator_release(iter2);
}
prop_object_release(forigd);
}
/*
* Compare original, installed and new hash for current file.
*/
while ((obj = prop_object_iterator_next(iter))) {
prop_dictionary_get_cstring_nocopy(obj, "file", &cffile);
if (strstr(archive_entry_pathname(entry), cffile) == 0)
continue;
buf = xbps_xasprintf(".%s", cffile);
if (buf == NULL) {
prop_object_iterator_release(iter);
return errno;
}
prop_dictionary_get_cstring_nocopy(obj, "sha256", &sha256_new);
sha256_cur = xbps_get_file_hash(buf);
free(buf);
if (sha256_cur == NULL) {
if (errno == ENOENT) {
/*
* File not installed, install new one.
*/
install_new = true;
break;
} else {
rv = errno;
break;
}
}
/*
* Orig = X, Curr = X, New = X
*
* Install new file.
*/
if ((strcmp(sha256_orig, sha256_cur) == 0) &&
(strcmp(sha256_cur, sha256_new) == 0) &&
(strcmp(sha256_orig, sha256_new) == 0)) {
install_new = true;
break;
/*
* Orig = X, Curr = X, New = Y
*
* Install new file.
*/
} else if ((strcmp(sha256_orig, sha256_cur) == 0) &&
(strcmp(sha256_cur, sha256_new)) &&
(strcmp(sha256_orig, sha256_new))) {
install_new = true;
break;
/*
* Orig = X, Curr = Y, New = X
*
* Keep current file as is.
*/
} else if ((strcmp(sha256_orig, sha256_cur)) &&
(strcmp(sha256_orig, sha256_new) == 0) &&
(strcmp(sha256_cur, sha256_new))) {
skip = true;
break;
/*
* Orig = X, Curr = Y, New = Y
*
* Install new file.
*/
} else if ((strcmp(sha256_orig, sha256_cur)) &&
(strcmp(sha256_cur, sha256_new) == 0) &&
(strcmp(sha256_orig, sha256_new))) {
install_new = true;
break;
/*
* Orig = X, Curr = Y, New = Z
*
* Install new file as file.new.
*/
} else if ((strcmp(sha256_orig, sha256_cur)) &&
(strcmp(sha256_cur, sha256_new)) &&
(strcmp(sha256_orig, sha256_new))) {
buf = xbps_xasprintf(".%s.new", cffile);
if (buf == NULL) {
rv = errno;
break;
}
printf("Installing new configuration "
"file %s.new\n", cffile);
install_new = true;
archive_entry_set_pathname(entry, buf);
free(buf);
break;
}
}
if (install_new)
set_extract_flags(flags);
if (sha256_orig)
free(sha256_orig);
if (sha256_cur)
free(sha256_cur);
prop_object_iterator_release(iter);
return rv;
}
/*
* TODO: remove printfs and return appropiate errors to be interpreted by
* the consumer.
*/
static int
unpack_archive_fini(struct archive *ar, prop_dictionary_t pkg,
bool essential)
{
prop_dictionary_t filesd;
struct archive_entry *entry;
const char *pkgname, *version, *rootdir;
char *buf, *buf2;
int rv = 0, flags, lflags, eflags;
bool actgt = false, skip_entry = false;
assert(ar != NULL);
assert(pkg != NULL);
rootdir = xbps_get_rootdir();
flags = xbps_get_flags();
if (strcmp(rootdir, "") == 0)
rootdir = "/";
if (chdir(rootdir) == -1)
return errno;
prop_dictionary_get_cstring_nocopy(pkg, "pkgname", &pkgname);
prop_dictionary_get_cstring_nocopy(pkg, "version", &version);
set_extract_flags(lflags);
while (archive_read_next_header(ar, &entry) == ARCHIVE_OK) {
/*
* Always overwrite pkg metadata files. Other files
* in the archive aren't overwritten unless a package
* defines the "essential" boolean obj, or the
* XBPS_FLAG_FORCE is specified.
*/
eflags = 0;
eflags = lflags;
if (strcmp("./INSTALL", archive_entry_pathname(entry)) &&
strcmp("./REMOVE", archive_entry_pathname(entry)) &&
strcmp("./files.plist", archive_entry_pathname(entry)) &&
strcmp("./props.plist", archive_entry_pathname(entry))) {
if (((flags & XBPS_FLAG_FORCE) == 0) ||
essential == false) {
eflags |= ARCHIVE_EXTRACT_NO_OVERWRITE;
eflags |= ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER;
}
}
/*
* 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",
XBPS_META_PATH, pkgname);
if (buf == NULL)
return errno;
actgt = true;
archive_entry_set_pathname(entry, buf);
if (archive_read_extract(ar, entry, eflags) != 0) {
if ((rv = archive_errno(ar)) != EEXIST) {
free(buf);
return rv;
}
}
if ((rv = xbps_file_chdir_exec(rootdir, buf, "pre",
pkgname, version, NULL)) != 0) {
free(buf);
printf("%s: preinst action target error %s\n",
pkgname, strerror(errno));
return rv;
}
/* pass to the next entry if successful */
free(buf);
continue;
/*
* Unpack metadata files in final directory.
*/
} 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) {
/*
* Now we have a dictionary from the entry
* in memory. Will be written to disk later, when
* all files are extracted.
*/
filesd = xbps_read_dict_from_archive_entry(ar, entry);
if (filesd == NULL)
return errno;
/* Pass to next entry */
continue;
} 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);
}
/*
* Handle configuration files.
*/
if ((rv = install_config_file(filesd, entry, pkgname,
eflags, skip_entry)) != 0) {
prop_object_release(filesd);
return rv;
}
if (skip_entry) {
archive_read_data_skip(ar);
skip_entry = false;
continue;
}
/*
* Extract entry from archive.
*/
if (archive_read_extract(ar, entry, eflags) != 0) {
rv = archive_errno(ar);
if (rv != EEXIST) {
printf("ERROR: %s...exiting!\n",
archive_error_string(ar));
return rv;;
} else if (rv == EEXIST) {
if (flags & XBPS_FLAG_VERBOSE) {
printf("WARNING: ignoring existent "
"path: %s\n",
archive_entry_pathname(entry));
}
rv = 0;
continue;
}
}
if (flags & XBPS_FLAG_VERBOSE)
printf(" %s\n", archive_entry_pathname(entry));
}
if ((rv = archive_errno(ar)) == 0) {
/*
* Now that all files were successfully unpacked, we
* can safely externalize files.plist because the path
* is reachable.
*/
buf2 = xbps_xasprintf(".%s/metadata/%s/files.plist",
XBPS_META_PATH, pkgname);
if (!prop_dictionary_externalize_to_file(filesd, buf2)) {
prop_object_release(filesd);
free(buf2);
return errno;
}
free(buf2);
}
prop_object_release(filesd);
return rv;
}

372
lib/util.c Normal file
View File

@ -0,0 +1,372 @@
/*-
* Copyright (c) 2008-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 <stdarg.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <ctype.h>
#include <sys/utsname.h>
#include <xbps_api.h>
static bool question(bool, const char *, va_list);
static const char *rootdir;
static int flags;
char *
xbps_get_file_hash(const char *file)
{
SHA256_CTX ctx;
char *hash;
uint8_t buf[BUFSIZ * 20], digest[SHA256_DIGEST_STRING_LENGTH];
ssize_t bytes;
int fd;
if ((fd = open(file, O_RDONLY)) == -1)
return NULL;
SHA256_Init(&ctx);
while ((bytes = read(fd, buf, sizeof(buf))) > 0)
SHA256_Update(&ctx, buf, (size_t)bytes);
hash = strdup(SHA256_End(&ctx, digest));
(void)close(fd);
return hash;
}
int
xbps_check_file_hash(const char *path, const char *sha256)
{
char *res;
res = xbps_get_file_hash(path);
if (res == NULL)
return errno;
if (strcmp(sha256, res)) {
free(res);
return ERANGE;
}
free(res);
return 0;
}
int
xbps_check_pkg_file_hash(prop_dictionary_t pkgd, const char *repoloc)
{
const char *sha256, *arch, *filename;
char *binfile;
int rv = 0;
assert(repoloc != NULL);
if (!prop_dictionary_get_cstring_nocopy(pkgd, "filename", &filename))
return EINVAL;
if (!prop_dictionary_get_cstring_nocopy(pkgd, "filename-sha256",
&sha256))
return EINVAL;
if (!prop_dictionary_get_cstring_nocopy(pkgd, "architecture", &arch))
return EINVAL;
binfile = xbps_xasprintf("%s/%s/%s", repoloc, arch, filename);
if (binfile == NULL)
return EINVAL;
rv = xbps_check_file_hash(binfile, sha256);
free(binfile);
return rv;
}
int
xbps_check_is_installed_pkg(const char *pkg)
{
prop_dictionary_t dict;
const char *reqver, *instver;
char *pkgname;
int rv = 0;
pkg_state_t state = 0;
assert(pkg != NULL);
pkgname = xbps_get_pkg_name(pkg);
reqver = xbps_get_pkg_version(pkg);
dict = xbps_find_pkg_installed_from_plist(pkgname);
if (dict == NULL) {
free(pkgname);
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 */
prop_dictionary_get_cstring_nocopy(dict, "version", &instver);
/* Compare installed and required version. */
rv = xbps_cmpver(instver, reqver);
prop_object_release(dict);
return rv;
}
bool
xbps_check_is_installed_pkgname(const char *pkgname)
{
prop_dictionary_t pkgd;
assert(pkgname != NULL);
pkgd = xbps_find_pkg_installed_from_plist(pkgname);
if (pkgd) {
prop_object_release(pkgd);
return true;
}
return false;
}
const char *
xbps_get_pkg_version(const char *pkg)
{
const char *tmp;
assert(pkg != NULL);
/* Get the required version */
tmp = strrchr(pkg, '-');
if (tmp == NULL)
return NULL;
return tmp + 1; /* skip first '-' */
}
const char *
xbps_get_pkg_revision(const char *pkg)
{
const char *tmp;
assert(pkg != NULL);
/* Get the required revision */
tmp = strrchr(pkg, '_');
if (tmp == NULL)
return NULL;
return tmp + 1; /* skip first '_' */
}
char *
xbps_get_pkg_name(const char *pkg)
{
const char *tmp;
char *pkgname;
size_t len = 0;
assert(pkg != NULL);
/* Get package name */
tmp = strrchr(pkg, '-');
if (tmp == NULL)
return NULL;
len = strlen(pkg) - strlen(tmp) + 1;
pkgname = malloc(len);
memcpy(pkgname, pkg, len - 1);
pkgname[len - 1] = '\0';
return pkgname;
}
char *
xbps_get_pkg_index_plist(const char *path)
{
struct utsname un;
assert(path != NULL);
if (uname(&un) == -1)
return NULL;
return xbps_xasprintf("%s/%s/%s", path, un.machine, XBPS_PKGINDEX);
}
bool
xbps_pkg_has_rundeps(prop_dictionary_t pkg)
{
prop_array_t array;
assert(pkg != NULL);
array = prop_dictionary_get(pkg, "run_depends");
if (array && prop_array_count(array) > 0)
return true;
return false;
}
void
xbps_set_rootdir(const char *dir)
{
assert(dir != NULL);
rootdir = dir;
}
const char *
xbps_get_rootdir(void)
{
if (rootdir == NULL)
rootdir = "";
return rootdir;
}
void
xbps_set_flags(int lflags)
{
flags = lflags;
}
int
xbps_get_flags(void)
{
return flags;
}
char *
xbps_xasprintf(const char *fmt, ...)
{
va_list ap;
char *buf;
va_start(ap, fmt);
if (vasprintf(&buf, fmt, ap) == -1)
return NULL;
va_end(ap);
return buf;
}
/*
* The following functions were taken from pacman (src/pacman/util.c)
* Copyright (c) 2002-2007 by Judd Vinet <jvinet@zeroflux.org>
*/
bool
xbps_yesno(const char *fmt, ...)
{
va_list ap;
bool res;
va_start(ap, fmt);
res = question(1, fmt, ap);
va_end(ap);
return res;
}
bool
xbps_noyes(const char *fmt, ...)
{
va_list ap;
bool res;
va_start(ap, fmt);
res = question(0, fmt, ap);
va_end(ap);
return res;
}
static char *
strtrim(char *str)
{
char *pch = str;
if (str == NULL || *str == '\0')
return str;
while (isspace((unsigned char)*pch))
pch++;
if (pch != str)
memmove(str, pch, (strlen(pch) + 1));
if (*str == '\0')
return str;
pch = (str + (strlen(str) - 1));
while (isspace((unsigned char)*pch))
pch--;
*++pch = '\0';
return str;
}
static bool
question(bool preset, const char *fmt, va_list ap)
{
char response[32];
vfprintf(stderr, fmt, ap);
if (preset)
fprintf(stderr, " %s ", "[Y/n]");
else
fprintf(stderr, " %s ", "[y/N]");
if (fgets(response, 32, stdin)) {
(void)strtrim(response);
if (strlen(response) == 0)
return preset;
if ((strcasecmp(response, "y") == 0) ||
(strcasecmp(response, "yes") == 0))
return true;
else if ((strcasecmp(response, "n") == 0) ||
(strcasecmp(response, "no") == 0))
return false;
}
return false;
}

22
prog.mk Normal file
View File

@ -0,0 +1,22 @@
include $(TOPDIR)/vars.mk
OBJS ?= main.o
all: $(BIN)
.PHONY: all
$(BIN): $(OBJS)
$(CC) $(LDFLAGS) $^ -o $@
.PHONY: clean
clean: clean-bins clean-objs
clean-bins:
-rm -f $(BIN)
clean-objs:
-rm -f $(OBJS)
install: $(BIN)
install -d $(SBINDIR)
install $(INSTALL_STRIPPED) -m 755 $(BIN) $(SBINDIR)

16
vars.mk Normal file
View File

@ -0,0 +1,16 @@
# Common variables.
PREFIX ?= /usr/local
SBINDIR ?= $(PREFIX)/sbin
LIBDIR ?= $(PREFIX)/lib
ETCDIR ?= $(PREFIX)/etc
TOPDIR ?= ..
INSTALL_STRIPPED ?= -s
LDFLAGS += -L$(TOPDIR)/lib -L$(PREFIX)/lib -lxbps
CPPFLAGS += -I$(TOPDIR)/include -D_BSD_SOURCE -D_XOPEN_SOURCE=600
CPPFLAGS += -D_GNU_SOURCE
WARNFLAGS ?= -pedantic -std=c99 -Wall -Wextra -Werror -Wshadow -Wformat=2
WARNFLAGS += -Wmissing-declarations -Wcomment -Wunused-macros -Wendif-labels
WARNFLAGS += -Wcast-qual -Wcast-align -Wconversion
CFLAGS += $(WARNFLAGS) -O2 -fPIC -DPIC