Initial import of xbps with code as August '09.
--HG-- extra : convert_revision : juan%40xbps-20090817170720-amxxac4a2e8bza1j
This commit is contained in:
44
lib/Makefile
Normal file
44
lib/Makefile
Normal 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
282
lib/cmpver.c
Normal 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
102
lib/configure.c
Normal 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
349
lib/depends.c
Normal 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
168
lib/fexec.c
Normal 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
458
lib/findpkg.c
Normal 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
143
lib/humanize_number.c
Normal 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
152
lib/orphans.c
Normal 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
458
lib/plist.c
Normal 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
203
lib/purge.c
Normal 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
114
lib/register.c
Normal 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
288
lib/remove.c
Normal 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
151
lib/repository.c
Normal 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
215
lib/requiredby.c
Normal 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
466
lib/sha256.c
Normal 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
198
lib/sortdeps.c
Normal 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
232
lib/state.c
Normal 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
454
lib/unpack.c
Normal 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
372
lib/util.c
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user