diff --git a/bin/xbps-rindex/Makefile b/bin/xbps-rindex/Makefile index 29ebf790..d99fad29 100644 --- a/bin/xbps-rindex/Makefile +++ b/bin/xbps-rindex/Makefile @@ -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 diff --git a/bin/xbps-rindex/defs.h b/bin/xbps-rindex/defs.h index b6377a4e..c8429520 100644 --- a/bin/xbps-rindex/defs.h +++ b/bin/xbps-rindex/defs.h @@ -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_ */ diff --git a/bin/xbps-rindex/index-add.c b/bin/xbps-rindex/index-add.c index 9b8799fa..7f39f418 100644 --- a/bin/xbps-rindex/index-add.c +++ b/bin/xbps-rindex/index-add.c @@ -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; } diff --git a/bin/xbps-rindex/index-clean.c b/bin/xbps-rindex/index-clean.c deleted file mode 100644 index 52efd9d8..00000000 --- a/bin/xbps-rindex/index-clean.c +++ /dev/null @@ -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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#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; -} diff --git a/bin/xbps-rindex/main.c b/bin/xbps-rindex/main.c index 727c0b67..02819ecf 100644 --- a/bin/xbps-rindex/main.c +++ b/bin/xbps-rindex/main.c @@ -44,7 +44,6 @@ usage(bool fail) " --signedby Signature details, i.e \"name \"\n\n" "MODE\n" " -a --add ... Add package(s) to repository index\n" - " -c --clean Cleans obsolete entries in repository index\n" " -r --remove-obsoletes Removes obsolete packages from repository\n" " -s --sign 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) diff --git a/bin/xbps-rindex/remove-obsoletes.c b/bin/xbps-rindex/remove-obsoletes.c index 9017c22d..29b69bbb 100644 --- a/bin/xbps-rindex/remove-obsoletes.c +++ b/bin/xbps-rindex/remove-obsoletes.c @@ -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)); diff --git a/bin/xbps-rindex/repoflush.c b/bin/xbps-rindex/repoflush.c index 77d1abfa..f75c483f 100644 --- a/bin/xbps-rindex/repoflush.c +++ b/bin/xbps-rindex/repoflush.c @@ -37,54 +37,71 @@ #include #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; } diff --git a/bin/xbps-rindex/sign.c b/bin/xbps-rindex/sign.c index 0292f201..7d39b8a6 100644 --- a/bin/xbps-rindex/sign.c +++ b/bin/xbps-rindex/sign.c @@ -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; } diff --git a/bin/xbps-rindex/xbps-rindex.8 b/bin/xbps-rindex/xbps-rindex.8 index 380fc954..2676959d 100644 --- a/bin/xbps-rindex/xbps-rindex.8 +++ b/bin/xbps-rindex/xbps-rindex.8 @@ -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 . -.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