xbps-rindex: remove -c --clean mode and adapt to the new libxbps API.

- Removed -c --clean mode. It's not too useful and adds a considerable
  amount of gratuitous code. It takes almost the same time than
  adding all pkgs from scratch.

- When creating the repository data always add the meta plist at the
  2nd position in the archive, to optimize its access.

- Misc improvements.
This commit is contained in:
Juan RP 2013-10-07 10:23:14 +02:00
parent 1f270e3a1a
commit f3b0b19258
9 changed files with 124 additions and 312 deletions

View File

@ -2,7 +2,7 @@ TOPDIR = ../..
-include $(TOPDIR)/config.mk
BIN = xbps-rindex
OBJS = main.o index-add.o index-clean.o remove-obsoletes.o repoflush.o
OBJS = main.o index-add.o remove-obsoletes.o repoflush.o
OBJS += readpassphrase.o sign.o
EXTRA_CFLAGS = -Wno-unused-result

View File

@ -64,24 +64,9 @@
#define __UNCONST(a) ((void *)(unsigned long)(const void *)(a))
#endif
struct repodata {
struct archive *ar;
char *repofile;
char *tname;
int repofd;
};
/* From index-add.c */
int index_add(struct xbps_handle *, int, char **, bool);
/* From index-clean.c */
int index_clean(struct xbps_handle *, const char *);
/* From index-files.c */
int index_files_add(struct xbps_handle *, int, char **);
int index_files_clean(struct xbps_handle *, const char *);
/* From remove-obsoletes.c */
int remove_obsoletes(struct xbps_handle *, const char *);
@ -93,8 +78,7 @@ int sign_repo(struct xbps_handle *, const char *, const char *,
char *readpassphrase(const char *, char *, size_t, int);
/* From repoflush.c */
struct repodata *repodata_init(struct xbps_handle *xhp, const char *);
int repodata_add_buf(struct repodata *, const char *, const char *);
void repodata_flush(struct repodata *);
bool repodata_flush(struct xbps_handle *, const char *,
xbps_dictionary_t, xbps_dictionary_t, xbps_dictionary_t);
#endif /* !_XBPS_RINDEX_DEFS_H_ */

View File

@ -66,16 +66,14 @@ index_add(struct xbps_handle *xhp, int argc, char **argv, bool force)
repodir = dirname(tmprepodir);
repo = xbps_repo_open(xhp, repodir);
if (repo != NULL) {
idx = xbps_repo_get_plist(repo, XBPS_REPOIDX);
idxfiles = xbps_repo_get_plist(repo, XBPS_REPOIDX_FILES);
}
if (idx == NULL)
if (repo == NULL) {
idx = xbps_dictionary_create();
if (idxfiles == NULL)
idxfiles = xbps_dictionary_create();
if (repo != NULL)
} else {
idx = xbps_dictionary_copy(repo->idx);
idxfiles = xbps_dictionary_copy(repo->idxfiles);
xbps_repo_close(repo);
}
/*
* Process all packages specified in argv.
@ -183,6 +181,7 @@ index_add(struct xbps_handle *xhp, int argc, char **argv, bool force)
free(pkgname);
return EINVAL;
}
free(pkgname);
flush = true;
printf("index: added `%s' (%s).\n", pkgver, arch);
/*
@ -193,7 +192,6 @@ index_add(struct xbps_handle *xhp, int argc, char **argv, bool force)
"./files.plist");
if (newpkgfilesd == NULL) {
free(pkgver);
free(pkgname);
return EINVAL;
}
@ -221,7 +219,6 @@ index_add(struct xbps_handle *xhp, int argc, char **argv, bool force)
xbps_object_release(newpkgfilesd);
xbps_object_release(newpkgd);
free(pkgver);
free(pkgname);
continue;
}
/* create pkg files array */
@ -255,39 +252,25 @@ index_add(struct xbps_handle *xhp, int argc, char **argv, bool force)
xbps_object_release(newpkgfilesd);
/* add pkg files array into index-files */
xbps_dictionary_set(idxfiles, pkgname, filespkgar);
xbps_dictionary_set(idxfiles, pkgver, filespkgar);
xbps_object_release(filespkgar);
printf("index-files: added `%s' (%s)\n", pkgver, arch);
xbps_object_release(newpkgd);
free(pkgver);
free(pkgname);
}
/*
* Generate repository data file.
* Generate repository data files.
*/
if (flush) {
struct repodata *rd;
char *xml;
rd = repodata_init(xhp, repodir);
xml = xbps_dictionary_externalize(idx);
assert(idx);
rv = repodata_add_buf(rd, xml, XBPS_REPOIDX);
free(xml);
xml = xbps_dictionary_externalize(idxfiles);
assert(idx);
rv = repodata_add_buf(rd, xml, XBPS_REPOIDX_FILES);
free(xml);
repodata_flush(rd);
if (!repodata_flush(xhp, repodir, idx, idxfiles, NULL)) {
fprintf(stderr, "failed to write repodata: %s\n",
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));
xbps_object_release(idx);
xbps_object_release(idxfiles);
return rv;
}

View File

@ -1,161 +0,0 @@
/*-
* Copyright (c) 2012-2013 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 <sys/stat.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <dirent.h>
#include <libgen.h>
#include <assert.h>
#include <pthread.h>
#include <fcntl.h>
#include <xbps.h>
#include "defs.h"
struct cbdata {
pthread_mutex_t mtx;
xbps_array_t array;
};
static int
idx_cleaner_cb(struct xbps_handle *xhp,
xbps_object_t obj,
const char *key _unused,
void *arg,
bool *done _unused)
{
struct cbdata *cbd = arg;
const char *arch, *pkgver, *sha256;
char *filen;
xbps_dictionary_get_cstring_nocopy(obj, "architecture", &arch);
xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver);
xbps_dbg_printf(xhp, "%s: checking %s [%s] ...", pkgver, arch);
filen = xbps_xasprintf("%s.%s.xbps", pkgver, arch);
if (access(filen, R_OK) == -1) {
/*
* File cannot be read, might be permissions,
* broken or simply unexistent; either way, remove it.
*/
xbps_array_add_cstring_nocopy(cbd->array, pkgver);
} else {
/*
* File can be read; check its hash.
*/
xbps_dictionary_get_cstring_nocopy(obj,
"filename-sha256", &sha256);
if (xbps_file_hash_check(filen, sha256) != 0)
xbps_array_add_cstring_nocopy(cbd->array, pkgver);
}
free(filen);
return 0;
}
/*
* Removes stalled pkg entries in repository's XBPS_REPOIDX file, if any
* binary package cannot be read (unavailable, not enough perms, etc).
*/
int
index_clean(struct xbps_handle *xhp, const char *repodir)
{
struct xbps_repo *repo;
struct cbdata cbd;
xbps_array_t allkeys;
xbps_dictionary_t idx, idxfiles;
const char *keyname;
char *pkgname;
int rv = 0;
bool flush = false;
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;
}
idx = xbps_repo_get_plist(repo, XBPS_REPOIDX);
idxfiles = xbps_repo_get_plist(repo, XBPS_REPOIDX_FILES);
xbps_repo_close(repo);
if (idx == NULL || idxfiles == NULL) {
fprintf(stderr, "incomplete repository data file!");
return -1;
}
if (chdir(repodir) == -1) {
fprintf(stderr, "index: cannot chdir to %s: %s\n",
repodir, strerror(errno));
return -1;
}
printf("Cleaning `%s' index, please wait...\n", repodir);
cbd.array = xbps_array_create();
allkeys = xbps_dictionary_all_keys(idx);
rv = xbps_array_foreach_cb_multi(xhp, allkeys, idx, idx_cleaner_cb, &cbd);
xbps_object_release(allkeys);
for (unsigned int x = 0; x < xbps_array_count(cbd.array); x++) {
xbps_array_get_cstring_nocopy(cbd.array, x, &keyname);
printf("index: removed entry %s\n", keyname);
pkgname = xbps_pkg_name(keyname);
xbps_dictionary_remove(idx, pkgname);
xbps_dictionary_remove(idxfiles, pkgname);
free(pkgname);
flush = true;
}
xbps_object_release(cbd.array);
if (flush) {
struct repodata *rd;
char *xml;
rd = repodata_init(xhp, repodir);
xml = xbps_dictionary_externalize(idx);
assert(idx);
rv = repodata_add_buf(rd, xml, XBPS_REPOIDX);
free(xml);
xml = xbps_dictionary_externalize(idxfiles);
assert(idx);
rv = repodata_add_buf(rd, xml, XBPS_REPOIDX_FILES);
free(xml);
repodata_flush(rd);
}
printf("index: %u packages registered.\n",
xbps_dictionary_count(idx));
printf("index-files: %u packages registered.\n",
xbps_dictionary_count(idxfiles));
xbps_object_release(idx);
xbps_object_release(idxfiles);
return rv;
}

View File

@ -44,7 +44,6 @@ usage(bool fail)
" --signedby <string> Signature details, i.e \"name <email>\"\n\n"
"MODE\n"
" -a --add <repodir/pkg> ... Add package(s) to repository index\n"
" -c --clean <repodir> Cleans obsolete entries in repository index\n"
" -r --remove-obsoletes <repodir> Removes obsolete packages from repository\n"
" -s --sign <repodir> Sign repository index\n\n");
exit(fail ? EXIT_FAILURE : EXIT_SUCCESS);
@ -53,10 +52,9 @@ usage(bool fail)
int
main(int argc, char **argv)
{
const char *shortopts = "acfhrV";
const char *shortopts = "afhrV";
struct option longopts[] = {
{ "add", no_argument, NULL, 'a' },
{ "clean", no_argument, NULL, 'c' },
{ "force", no_argument, NULL, 'f' },
{ "help", no_argument, NULL, 'h' },
{ "remove-obsoletes", no_argument, NULL, 'r' },
@ -69,9 +67,9 @@ main(int argc, char **argv)
struct xbps_handle xh;
const char *privkey = NULL, *signedby = NULL;
int rv, c;
bool clean_mode, add_mode, rm_mode, sign_mode, force;
bool add_mode, rm_mode, sign_mode, force;
clean_mode = add_mode = rm_mode = sign_mode = force = false;
add_mode = rm_mode = sign_mode = force = false;
while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) {
switch (c) {
@ -84,9 +82,6 @@ main(int argc, char **argv)
case 'a':
add_mode = true;
break;
case 'c':
clean_mode = true;
break;
case 'f':
force = true;
break;
@ -104,13 +99,12 @@ main(int argc, char **argv)
exit(EXIT_SUCCESS);
}
}
if ((argc == optind) || (!add_mode && !clean_mode && !rm_mode && !sign_mode)) {
if ((argc == optind) || (!add_mode && !rm_mode && !sign_mode)) {
usage(true);
} else if ((add_mode && (clean_mode || rm_mode)) ||
(clean_mode && (add_mode || rm_mode)) ||
(rm_mode && (add_mode || clean_mode)) ||
(sign_mode && (add_mode || clean_mode || rm_mode))) {
fprintf(stderr, "Only one mode can be specified: add, clean, "
} else if ((add_mode && (rm_mode || sign_mode)) ||
(rm_mode && (add_mode || sign_mode)) ||
(sign_mode && (add_mode || rm_mode))) {
fprintf(stderr, "Only one mode can be specified: add, "
"remove-obsoletes or sign.\n");
exit(EXIT_FAILURE);
}
@ -125,8 +119,6 @@ main(int argc, char **argv)
if (add_mode)
rv = index_add(&xh, argc - optind, argv + optind, force);
else if (clean_mode)
rv = index_clean(&xh, argv[optind]);
else if (rm_mode)
rv = remove_obsoletes(&xh, argv[optind]);
else if (sign_mode)

View File

@ -119,10 +119,6 @@ remove_obsoletes(struct xbps_handle *xhp, const char *repodir)
}
return 0;
}
if ((repo->idx = xbps_repo_get_plist(repo, XBPS_REPOIDX)) == NULL) {
xbps_repo_close(repo);
return -1;
}
if (chdir(repodir) == -1) {
fprintf(stderr, "xbps-rindex: cannot chdir to %s: %s\n",
repodir, strerror(errno));

View File

@ -37,54 +37,71 @@
#include <xbps.h>
#include "defs.h"
struct repodata *
repodata_init(struct xbps_handle *xhp, const char *repodir)
{
struct repodata *rd;
rd = malloc(sizeof(struct repodata));
assert(rd);
/* Create a tempfile for our repository archive */
rd->repofile = xbps_repo_path(xhp, repodir);
rd->tname = xbps_xasprintf("%s.XXXXXXXXXX", rd->repofile);
if ((rd->repofd = mkstemp(rd->tname)) == -1) {
free(rd);
return NULL;
}
/* Create and write our repository archive */
rd->ar = archive_write_new();
assert(rd->ar);
archive_write_set_compression_gzip(rd->ar);
archive_write_set_format_pax_restricted(rd->ar);
archive_write_set_options(rd->ar, "compression-level=9");
archive_write_open_fd(rd->ar, rd->repofd);
return rd;
}
int
repodata_add_buf(struct repodata *rd, const char *buf, const char *filename)
{
return xbps_archive_append_buf(rd->ar, buf, strlen(buf),
filename, 0644, "root", "root");
}
void
repodata_flush(struct repodata *rd)
bool
repodata_flush(struct xbps_handle *xhp, const char *repodir,
xbps_dictionary_t idx, xbps_dictionary_t idxfiles,
xbps_dictionary_t meta)
{
struct archive *ar;
char *repofile, *tname, *buf;
int rv, repofd = -1;
mode_t myumask;
/* Create a tempfile for our repository archive */
repofile = xbps_repo_path(xhp, repodir);
tname = xbps_xasprintf("%s.XXXXXXXXXX", repofile);
if ((repofd = mkstemp(tname)) == -1)
return false;
/* Create and write our repository archive */
ar = archive_write_new();
assert(ar);
archive_write_set_compression_gzip(ar);
archive_write_set_format_pax_restricted(ar);
archive_write_set_options(ar, "compression-level=9");
archive_write_open_fd(ar, repofd);
/* XBPS_REPOIDX */
buf = xbps_dictionary_externalize(idx);
assert(buf);
rv = xbps_archive_append_buf(ar, buf, strlen(buf),
XBPS_REPOIDX, 0644, "root", "root");
free(buf);
if (rv != 0)
return false;
/* XBPS_REPOIDX_META */
if (meta == NULL) {
/* fake entry */
buf = strdup("DEADBEEF");
} else {
buf = xbps_dictionary_externalize(meta);
}
rv = xbps_archive_append_buf(ar, buf, strlen(buf),
XBPS_REPOIDX_META, 0644, "root", "root");
free(buf);
if (rv != 0)
return false;
/* XBPS_REPOIDX_FILES */
buf = xbps_dictionary_externalize(idxfiles);
assert(buf);
rv = xbps_archive_append_buf(ar, buf, strlen(buf),
XBPS_REPOIDX_FILES, 0644, "root", "root");
free(buf);
if (rv != 0)
return false;
/* Write data to tempfile and rename */
archive_write_finish(rd->ar);
fdatasync(rd->repofd);
archive_write_finish(ar);
fdatasync(repofd);
myumask = umask(0);
(void)umask(myumask);
assert(fchmod(rd->repofd, 0666 & ~myumask) != -1);
close(rd->repofd);
rename(rd->tname, rd->repofile);
free(rd->repofile);
free(rd->tname);
free(rd);
assert(fchmod(repofd, 0666 & ~myumask) != -1);
close(repofd);
rename(tname, repofile);
free(repofile);
free(tname);
return true;
}

View File

@ -146,14 +146,13 @@ sign_repo(struct xbps_handle *xhp, const char *repodir,
const char *privkey, const char *signedby)
{
RSA *rsa = NULL;
struct repodata *rd;
struct xbps_repo *repo;
xbps_dictionary_t idx, meta;
xbps_dictionary_t idx, idxfiles, meta = NULL;
xbps_data_t data;
unsigned int siglen;
unsigned char *sig;
char *buf, *xml, *defprivkey = NULL;
int rv = 0;
char *buf = NULL, *xml = NULL, *defprivkey = NULL;
int rv = -1;
if (signedby == NULL) {
fprintf(stderr, "--signedby unset! cannot sign repository\n");
@ -165,22 +164,25 @@ sign_repo(struct xbps_handle *xhp, const char *repodir,
repo = xbps_repo_open(xhp, repodir);
if (repo == NULL) {
fprintf(stderr, "cannot read repository data: %s\n", strerror(errno));
return -1;
goto out;
}
idx = xbps_repo_get_plist(repo, XBPS_REPOIDX);
xbps_repo_close(repo);
if (xbps_dictionary_count(idx) == 0) {
if (xbps_dictionary_count(repo->idx) == 0) {
fprintf(stderr, "invalid number of objects in repository index!\n");
xbps_repo_close(repo);
return -1;
}
xbps_repo_open_idxfiles(repo);
idx = xbps_dictionary_copy(repo->idx);
idxfiles = xbps_dictionary_copy(repo->idxfiles);
xbps_repo_close(repo);
/*
* Externalize the index and then sign it.
*/
xml = xbps_dictionary_externalize(idx);
if (xml == NULL) {
fprintf(stderr, "failed to externalize repository index: %s\n", strerror(errno));
xbps_object_release(idx);
return -1;
goto out;
}
/*
* If privkey not set, default to ~/.ssh/id_rsa.
@ -193,10 +195,10 @@ sign_repo(struct xbps_handle *xhp, const char *repodir,
rsa = rsa_sign_buf(defprivkey, xml, &sig, &siglen);
if (rsa == NULL) {
free(xml);
return -1;
goto out;
}
/*
* Prepare the XBPS_REPOMETA for our repository data.
* Prepare the XBPS_REPOIDX_META for our repository data.
*/
meta = xbps_dictionary_create();
xbps_dictionary_set_cstring_nocopy(meta, "signature-by", signedby);
@ -213,19 +215,20 @@ sign_repo(struct xbps_handle *xhp, const char *repodir,
/*
* and finally write our repodata file!
*/
rd = repodata_init(xhp, repodir);
assert(rd);
xml = xbps_dictionary_externalize(idx);
assert(xml);
rv = repodata_add_buf(rd, xml, XBPS_REPOIDX);
free(xml);
xml = xbps_dictionary_externalize(meta);
assert(xml);
rv = repodata_add_buf(rd, xml, XBPS_REPOMETA);
free(xml);
repodata_flush(rd);
free(buf);
RSA_free(rsa);
if (!repodata_flush(xhp, repodir, idx, idxfiles, meta)) {
fprintf(stderr, "failed to write repodata: %s\n", strerror(errno));
goto out;
}
rv = 0;
out:
if (xml != NULL)
free(xml);
if (buf != NULL)
free(buf);
if (rsa != NULL)
RSA_free(rsa);
return rv;
}

View File

@ -3,7 +3,7 @@
.Dt xbps-rindex 8
.Sh NAME
.Nm xbps-rindex
.Nd XBPS utility to handle local binary package repositories
.Nd XBPS utility to manage local binary package repositories
.Sh SYNOPSYS
.Nm xbps-rindex
.Op OPTIONS
@ -25,30 +25,28 @@ mode.
Show the help usage.
.It Fl V -version
Show the XBPS version.
.It Sy --signedby Ar string
This is required to sign a repository, a description of the person signing the repository, i.e name and email.
.It Sy --privkey Ar key
Path to the private RSA key to sign the repository. If unset, defaults to
.Sy ~/.ssh/id_rsa .
.Sh MODE
.Pp
.Bl -tag -width x
.It Sy -a, --add Ar /path/to/repo/binpkg.xbps ...
Registers the binary package into the local repository, replacing
existing version. Multiple binary packages can be specified as arguments.
.It Sy -c, --clean Ar repository
Removes obsolete entries found in the local repository's index.
.It Sy -a, --add Ar repository/binpkg.xbps ...
Registers the binary package into the local repository. The specified binary
package is only added to the index if its version is greater than the one
currently stored. Multiple binary packages can be specified as arguments.
.It Sy -r, --remove-obsoletes Ar repository
Removes obsolete packages from
.Ar repository .
Packages that are not currently registered in repository's index will
be removed (out of date, invalid archives, etc).
.It Sy -s, --sign
.It Sy -s, --sign Ar repository
Signs a repository with your specified RSA key. If
.Fl --privkey
argument not set, it defaults to
.Sy ~/.ssh/id_rsa .
.It Sy --signedby Ar string
This is required to sign a repository, use something like
.Ar name <email> .
.It Sy --privkey Ar key
Path to the private RSA key to sign the repository. If unset, defaults to
.Sy ~/.ssh/id_rsa .
.Sh ENVIRONMENT
.Bl -tag -width XBPS_TARGET_ARCH
.It Sy XBPS_TARGET_ARCH