xbps-rindex: use a POSIX named semaphore to avoid concurrency issues.

This commit is contained in:
Juan RP 2014-01-31 11:35:31 +01:00
parent 915b8b2557
commit f5e1fff93a
8 changed files with 179 additions and 32 deletions

3
NEWS
View File

@ -1,5 +1,8 @@
xbps-0.31 (??):
* xbps-rindex(8): use a POSIX named semaphore in modes that can modify
repository data archive, to avoid concurrency issues.
* Removed 0.27 compat from repodata.
* If a repository has been signed previously respect its settings

View File

@ -2,6 +2,6 @@ TOPDIR = ../..
-include $(TOPDIR)/config.mk
BIN = xbps-rindex
OBJS = main.o index-add.o index-clean.o remove-obsoletes.o repoflush.o sign.o
OBJS = main.o sem.o index-add.o index-clean.o remove-obsoletes.o repoflush.o sign.o
include $(TOPDIR)/mk/prog.mk

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2012-2013 Juan Romero Pardines.
* Copyright (c) 2012-2014 Juan Romero Pardines.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -27,6 +27,7 @@
#define _XBPS_RINDEX_DEFS_H_
#include <xbps.h>
#include <semaphore.h>
/* libarchive compat */
#if ARCHIVE_VERSION_NUMBER >= 3000000
@ -64,6 +65,9 @@
#define __UNCONST(a) ((void *)(unsigned long)(const void *)(a))
#endif
#define _XBPS_RINDEX "xbps-rindex"
#define _XBPS_RINDEX_SEMNAME "/xbps-rindex-write"
/* From index-add.c */
int index_add(struct xbps_handle *, int, char **, bool);
@ -81,4 +85,8 @@ int sign_repo(struct xbps_handle *, const char *, const char *,
bool repodata_flush(struct xbps_handle *, const char *,
xbps_dictionary_t, xbps_dictionary_t, xbps_dictionary_t);
/* From sem.c */
sem_t *index_lock(void);
void index_unlock(sem_t *);
#endif /* !_XBPS_RINDEX_DEFS_H_ */

View File

@ -43,6 +43,7 @@ index_add(struct xbps_handle *xhp, int argc, char **argv, bool force)
xbps_array_t array, pkg_files, pkg_links, pkg_cffiles;
xbps_dictionary_t idx, idxmeta, idxfiles, binpkgd, pkg_filesd, curpkgd;
xbps_object_t obj, fileobj;
sem_t *sem;
struct xbps_repo *repo;
struct stat st;
const char *arch;
@ -50,14 +51,16 @@ index_add(struct xbps_handle *xhp, int argc, char **argv, bool force)
int rv = 0, ret = 0;
bool flush = false, found = false;
if ((tmprepodir = strdup(argv[0])) == NULL)
return ENOMEM;
if ((sem = index_lock()) == NULL)
return EINVAL;
/*
* Read the repository data or create index dictionaries otherwise.
*/
if ((tmprepodir = strdup(argv[0])) == NULL) {
rv = ENOMEM;
goto out;
}
repodir = dirname(tmprepodir);
repo = xbps_repo_open(xhp, repodir);
if (repo && repo->idx) {
xbps_repo_open_idxfiles(repo);
@ -70,7 +73,6 @@ index_add(struct xbps_handle *xhp, int argc, char **argv, bool force)
idxmeta = NULL;
idxfiles = xbps_dictionary_create();
}
/*
* Process all packages specified in argv.
*/
@ -81,7 +83,8 @@ index_add(struct xbps_handle *xhp, int argc, char **argv, bool force)
binpkgd = xbps_get_pkg_plist_from_binpkg(argv[i],
"./props.plist");
if (binpkgd == NULL) {
fprintf(stderr, "failed to read %s metadata for `%s', skipping!\n", XBPS_PKGPROPS, argv[i]);
fprintf(stderr, "index: failed to read %s metadata for "
"`%s', skipping!\n", XBPS_PKGPROPS, argv[i]);
continue;
}
xbps_dictionary_get_cstring_nocopy(binpkgd, "architecture", &arch);
@ -102,9 +105,10 @@ index_add(struct xbps_handle *xhp, int argc, char **argv, bool force)
curpkgd = xbps_dictionary_get(idx, pkgname);
if (curpkgd == NULL) {
if (errno && errno != ENOENT) {
rv = errno;
free(pkgver);
free(pkgname);
return errno;
goto out;
}
} else if (!force) {
/* Only check version if !force */
@ -139,22 +143,26 @@ index_add(struct xbps_handle *xhp, int argc, char **argv, bool force)
if ((sha256 = xbps_file_hash(argv[i])) == NULL) {
free(pkgver);
free(pkgname);
return errno;
rv = EINVAL;
goto out;
}
if (!xbps_dictionary_set_cstring(binpkgd, "filename-sha256", sha256)) {
free(pkgver);
free(pkgname);
return errno;
rv = EINVAL;
goto out;
}
if (stat(argv[i], &st) == -1) {
free(pkgver);
free(pkgname);
return errno;
rv = EINVAL;
goto out;
}
if (!xbps_dictionary_set_uint64(binpkgd, "filename-size", (uint64_t)st.st_size)) {
free(pkgver);
free(pkgname);
return errno;
rv = EINVAL;
goto out;
}
/* Remove unneeded objects */
xbps_dictionary_remove(binpkgd, "pkgname");
@ -165,7 +173,8 @@ index_add(struct xbps_handle *xhp, int argc, char **argv, bool force)
*/
if (!xbps_dictionary_set(idx, pkgname, binpkgd)) {
free(pkgname);
return EINVAL;
rv = EINVAL;
goto out;
}
flush = true;
printf("index: added `%s' (%s).\n", pkgver, arch);
@ -178,7 +187,8 @@ index_add(struct xbps_handle *xhp, int argc, char **argv, bool force)
pkg_filesd = xbps_get_pkg_plist_from_binpkg(argv[i], "./files.plist");
if (pkg_filesd == NULL) {
free(pkgver);
return EINVAL;
rv = EINVAL;
goto out;
}
pkg_cffiles = xbps_dictionary_get(pkg_filesd, "conf_files");
@ -244,12 +254,16 @@ index_add(struct xbps_handle *xhp, int argc, char **argv, bool force)
*/
if (flush) {
if (!repodata_flush(xhp, repodir, idx, idxfiles, idxmeta)) {
fprintf(stderr, "failed to write repodata: %s\n", strerror(errno));
fprintf(stderr, "%s: failed to write repodata: %s\n",
_XBPS_RINDEX, strerror(errno));
return -1;
}
}
printf("index: %u packages registered.\n", xbps_dictionary_count(idx));
printf("index-files: %u packages registered.\n", xbps_dictionary_count(idxfiles));
out:
index_unlock(sem);
return rv;
}

View File

@ -118,20 +118,27 @@ idxfiles_cleaner_cb(struct xbps_handle *xhp _unused, xbps_object_t obj _unused,
int
index_clean(struct xbps_handle *xhp, const char *repodir)
{
xbps_array_t allkeys;
xbps_dictionary_t idx = NULL, idxmeta = NULL, idxfiles = NULL;
struct xbps_repo *repo;
struct cbdata cbd;
xbps_array_t allkeys;
xbps_dictionary_t idx, idxmeta, idxfiles;
sem_t *sem;
char *keyname, *pkgname;
int rv = 0;
bool flush = false;
if ((sem = index_lock()) == NULL)
return EINVAL;
repo = xbps_repo_open(xhp, repodir);
if (repo == NULL) {
if (errno == ENOENT)
return 0;
fprintf(stderr, "index: cannot read repository data: %s\n", strerror(errno));
return -1;
goto out;
fprintf(stderr, "%s: cannot read repository data: %s\n",
_XBPS_RINDEX, strerror(errno));
rv = errno;
goto out;
}
xbps_repo_open_idxfiles(repo);
idx = xbps_dictionary_copy(repo->idx);
@ -139,8 +146,9 @@ index_clean(struct xbps_handle *xhp, const char *repodir)
idxfiles = xbps_dictionary_copy(repo->idxfiles);
xbps_repo_close(repo);
if (idx == NULL || idxfiles == NULL) {
fprintf(stderr, "incomplete repository data file!\n");
return -1;
fprintf(stderr, "%s: incomplete repository data file!\n", _XBPS_RINDEX);
rv = EINVAL;
goto out;
}
printf("Cleaning `%s' index, please wait...\n", repodir);
@ -187,9 +195,10 @@ index_clean(struct xbps_handle *xhp, const char *repodir)
if (flush) {
if (!repodata_flush(xhp, repodir, idx, idxfiles, idxmeta)) {
rv = errno;
fprintf(stderr, "failed to write repodata: %s\n",
strerror(errno));
return -1;
goto out;
}
}
printf("index: %u packages registered.\n",
@ -197,7 +206,14 @@ index_clean(struct xbps_handle *xhp, const char *repodir)
printf("index-files: %u packages registered.\n",
xbps_dictionary_count(idxfiles));
out:
index_unlock(sem);
if (idx)
xbps_object_release(idx);
if (idxmeta)
xbps_object_release(idxmeta);
if (idxfiles)
xbps_object_release(idxfiles);
return rv;

64
bin/xbps-rindex/sem.c Normal file
View File

@ -0,0 +1,64 @@
/*-
* Copyright (c) 2014 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 <sys/stat.h>
#include <fcntl.h>
#include "defs.h"
sem_t *
index_lock(void)
{
sem_t *sem;
/*
* Create/open the POSIX named semaphore.
*/
sem = sem_open(_XBPS_RINDEX_SEMNAME, O_CREAT, 0660, 1);
if (sem == SEM_FAILED) {
fprintf(stderr, "%s: failed to create/open named "
"semaphore: %s\n", _XBPS_RINDEX, strerror(errno));
return NULL;
}
if (sem_wait(sem) == -1) {
fprintf(stderr, "%s: failed to lock named semaphore: %s\n",
_XBPS_RINDEX, strerror(errno));
return NULL;
}
return sem;
}
void
index_unlock(sem_t *sem)
{
/* Unblock semaphore, close and destroy it (if possible) */
sem_post(sem);
sem_close(sem);
sem_unlink(_XBPS_RINDEX_SEMNAME);
}

View File

@ -116,6 +116,7 @@ int
sign_repo(struct xbps_handle *xhp, const char *repodir,
const char *privkey, const char *signedby)
{
sem_t *sem;
struct stat st;
struct xbps_repo *repo;
xbps_dictionary_t pkgd, meta = NULL;
@ -135,18 +136,24 @@ sign_repo(struct xbps_handle *xhp, const char *repodir,
fprintf(stderr, "--signedby unset! cannot sign repository\n");
return -1;
}
if ((sem = index_lock()) == NULL)
return EINVAL;
/*
* Check that repository index exists and not empty, otherwise bail out.
*/
repo = xbps_repo_open(xhp, repodir);
if (repo == NULL) {
fprintf(stderr, "cannot read repository data: %s\n", strerror(errno));
return -1;
rv = errno;
fprintf(stderr, "%s: cannot read repository data: %s\n",
_XBPS_RINDEX, strerror(errno));
goto out;
}
if (xbps_dictionary_count(repo->idx) == 0) {
fprintf(stderr, "Invalid repository, existing!\n");
xbps_repo_close(repo);
return -1;
fprintf(stderr, "%s: invalid repository, existing!\n", _XBPS_RINDEX);
rv = EINVAL;
goto out;
}
xbps_repo_open_idxfiles(repo);
/*
@ -163,7 +170,7 @@ sign_repo(struct xbps_handle *xhp, const char *repodir,
OpenSSL_add_all_digests();
if ((rsa = load_rsa_privkey(defprivkey)) == NULL) {
fprintf(stderr, "failed to read the RSA privkey\n");
fprintf(stderr, "%s: failed to read the RSA privkey\n", _XBPS_RINDEX);
rv = EINVAL;
goto out;
}
@ -289,6 +296,8 @@ sign_repo(struct xbps_handle *xhp, const char *repodir,
xbps_dictionary_count(repo->idx) == 1 ? "" : "s");
out:
index_unlock(sem);
if (rsa) {
RSA_free(rsa);
rsa = NULL;

33
configure vendored
View File

@ -338,6 +338,39 @@ echo "CPPFLAGS += -I\$(TOPDIR)/lib/portableproplib/prop" >>$CONFIG_MK
echo "LDFLAGS += -lpthread" >>$CONFIG_MK
echo "STATIC_LIBS += -lpthread" >>$CONFIG_MK
#
# Check for POSIX semaphores.
#
printf "Checking for POSIX semaphores ... "
cat <<EOF > _$func.c
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
int main(void) {
sem_t *sem;
sem = sem_open("/xbps0000test", 0644, O_CREAT, 1);
sem_wait(sem);
sem_post(sem);
sem_close(sem);
sem_unlink("/xbps0000test");
return 0;
}
EOF
if $XCC -pthread -lrt _$func.c -o _$func 2>/dev/null; then
POSIXSEM=yes
echo yes.
fi
rm -f _$func.c _$func
if [ -z "$POSIXSEM" ]; then
echo "no! POSIX semaphores are required, exiting..."
exit 1
fi
echo "LDFLAGS += -lrt" >>$CONFIG_MK
echo "STATIC_LIBS += -lrt" >>$CONFIG_MK
#
# Check for vasprintf().
#