From: "Fabian Groffen" <grobian@gentoo.org>
To: gentoo-commits@lists.gentoo.org
Subject: [gentoo-commits] repo/proj/prefix:master commit in: scripts/rsync-generation/
Date: Sat, 17 Mar 2018 20:59:03 +0000 (UTC) [thread overview]
Message-ID: <1521320291.9e0ef57926049281e6075a8040c6c99871878ca5.grobian@gentoo> (raw)
commit: 9e0ef57926049281e6075a8040c6c99871878ca5
Author: Fabian Groffen <grobian <AT> gentoo <DOT> org>
AuthorDate: Sat Mar 17 20:58:11 2018 +0000
Commit: Fabian Groffen <grobian <AT> gentoo <DOT> org>
CommitDate: Sat Mar 17 20:58:11 2018 +0000
URL: https://gitweb.gentoo.org/repo/proj/prefix.git/commit/?id=9e0ef579
scripts/rsync-generation/hashgen: moved to its own repository
hashgen will live on in github.com/grobian/hashgen
scripts/rsync-generation/hashgen.c | 1510 ------------------------------------
1 file changed, 1510 deletions(-)
diff --git a/scripts/rsync-generation/hashgen.c b/scripts/rsync-generation/hashgen.c
deleted file mode 100644
index 60121978da..0000000000
--- a/scripts/rsync-generation/hashgen.c
+++ /dev/null
@@ -1,1510 +0,0 @@
-/* Copyright 2006-2018 Gentoo Foundation; Distributed under the GPL v2 */
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-#include <ctype.h>
-#include <dirent.h>
-#include <time.h>
-#include <errno.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <openssl/sha.h>
-#include <openssl/whrlpool.h>
-#include <blake2.h>
-#include <zlib.h>
-#include <gpgme.h>
-
-/* Generate thick Manifests based on thin Manifests */
-
-/* In order to build this program, the following packages are required:
- * - app-crypt/libb2 (for BLAKE2, for as long as openssl doesn't include it)
- * - dev-libs/openssl (for SHA, WHIRLPOOL)
- * - sys-libs/zlib (for compressing Manifest files)
- * - app-crypt/gpgme (for signing/verifying the top level manifest)
- * compile like this:
- * ${CC} -o hashgen -fopenmp ${CFLAGS} \
- * -lssl -lcrypto -lb2 -lz `gpgme-config --libs` hashgen.c
- */
-
-enum hash_impls {
- HASH_SHA256 = 1<<0,
- HASH_SHA512 = 1<<1,
- HASH_WHIRLPOOL = 1<<2,
- HASH_BLAKE2B = 1<<3
-};
-/* default changed from sha256, sha512, whirlpool
- * to blake2b, sha512 on 2017-11-21 */
-#define HASH_DEFAULT (HASH_BLAKE2B | HASH_SHA512);
-static int hashes = HASH_DEFAULT;
-
-static inline void
-hex_hash(char *out, const unsigned char *buf, const int length)
-{
- switch (length) {
- /* SHA256_DIGEST_LENGTH */
- case 32:
- snprintf(out, 64 + 1,
- "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
- "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
- "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
- "%02x%02x",
- buf[ 0], buf[ 1], buf[ 2], buf[ 3], buf[ 4],
- buf[ 5], buf[ 6], buf[ 7], buf[ 8], buf[ 9],
- buf[10], buf[11], buf[12], buf[13], buf[14],
- buf[15], buf[16], buf[17], buf[18], buf[19],
- buf[20], buf[21], buf[22], buf[23], buf[24],
- buf[25], buf[26], buf[27], buf[28], buf[29],
- buf[30], buf[31]
- );
- break;
- /* SHA512_DIGEST_LENGTH, WHIRLPOOL_DIGEST_LENGTH, BLAKE2B_OUTBYTES */
- case 64:
- snprintf(out, 128 + 1,
- "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
- "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
- "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
- "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
- "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
- "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
- "%02x%02x%02x%02x",
- buf[ 0], buf[ 1], buf[ 2], buf[ 3], buf[ 4],
- buf[ 5], buf[ 6], buf[ 7], buf[ 8], buf[ 9],
- buf[10], buf[11], buf[12], buf[13], buf[14],
- buf[15], buf[16], buf[17], buf[18], buf[19],
- buf[20], buf[21], buf[22], buf[23], buf[24],
- buf[25], buf[26], buf[27], buf[28], buf[29],
- buf[30], buf[31], buf[32], buf[33], buf[34],
- buf[35], buf[36], buf[37], buf[38], buf[39],
- buf[40], buf[41], buf[42], buf[43], buf[44],
- buf[45], buf[46], buf[47], buf[48], buf[49],
- buf[50], buf[51], buf[52], buf[53], buf[54],
- buf[55], buf[56], buf[57], buf[58], buf[59],
- buf[60], buf[61], buf[62], buf[63]
- );
- break;
- /* fallback case, should never be necessary */
- default:
- {
- int i;
- for (i = 0; i < length; i++) {
- snprintf(&out[i * 2], 3, "%02x", buf[i]);
- }
- }
- break;
- }
-}
-
-static inline void
-update_times(struct timeval *tv, struct stat *s)
-{
-#ifdef __MACH__
-# define st_mtim st_mtimespec
-# define st_atim st_atimespec
-#endif
- if (tv[1].tv_sec < s->st_mtim.tv_sec ||
- (tv[1].tv_sec == s->st_mtim.tv_sec &&
- tv[1].tv_usec < s->st_mtim.tv_nsec / 1000))
- {
- tv[0].tv_sec = s->st_atim.tv_sec;
- tv[0].tv_usec = s->st_atim.tv_nsec / 1000;
- tv[1].tv_sec = s->st_mtim.tv_sec;
- tv[1].tv_usec = s->st_mtim.tv_nsec / 1000;
- }
-}
-
-static void
-get_hashes(
- const char *fname,
- char *sha256,
- char *sha512,
- char *whrlpl,
- char *blak2b,
- size_t *flen)
-{
- FILE *f;
- char data[8192];
- size_t len;
- SHA256_CTX s256;
- SHA512_CTX s512;
- WHIRLPOOL_CTX whrl;
- blake2b_state bl2b;
-
- if ((f = fopen(fname, "r")) == NULL)
- return;
-
- SHA256_Init(&s256);
- SHA512_Init(&s512);
- WHIRLPOOL_Init(&whrl);
- blake2b_init(&bl2b, BLAKE2B_OUTBYTES);
-
- while ((len = fread(data, 1, sizeof(data), f)) > 0) {
- *flen += len;
-#pragma omp parallel sections
- {
-#pragma omp section
- {
- if (hashes & HASH_SHA256)
- SHA256_Update(&s256, data, len);
- }
-#pragma omp section
- {
- if (hashes & HASH_SHA512)
- SHA512_Update(&s512, data, len);
- }
-#pragma omp section
- {
- if (hashes & HASH_WHIRLPOOL)
- WHIRLPOOL_Update(&whrl, data, len);
- }
-#pragma omp section
- {
- if (hashes & HASH_BLAKE2B)
- blake2b_update(&bl2b, (unsigned char *)data, len);
- }
- }
- }
- fclose(f);
-
-#pragma omp parallel sections
- {
- {
- if (hashes & HASH_SHA256) {
- unsigned char sha256buf[SHA256_DIGEST_LENGTH];
- SHA256_Final(sha256buf, &s256);
- hex_hash(sha256, sha256buf, SHA256_DIGEST_LENGTH);
- }
- }
-#pragma omp section
- {
- if (hashes & HASH_SHA512) {
- unsigned char sha512buf[SHA512_DIGEST_LENGTH];
- SHA512_Final(sha512buf, &s512);
- hex_hash(sha512, sha512buf, SHA512_DIGEST_LENGTH);
- }
- }
-#pragma omp section
- {
- if (hashes & HASH_WHIRLPOOL) {
- unsigned char whrlplbuf[WHIRLPOOL_DIGEST_LENGTH];
- WHIRLPOOL_Final(whrlplbuf, &whrl);
- hex_hash(whrlpl, whrlplbuf, WHIRLPOOL_DIGEST_LENGTH);
- }
- }
-#pragma omp section
- {
- if (hashes & HASH_BLAKE2B) {
- unsigned char blak2bbuf[BLAKE2B_OUTBYTES];
- blake2b_final(&bl2b, blak2bbuf, BLAKE2B_OUTBYTES);
- hex_hash(blak2b, blak2bbuf, BLAKE2B_OUTBYTES);
- }
- }
- }
-}
-
-#define LISTSZ 64
-
-static int
-compare_strings(const void *l, const void *r)
-{
- const char **strl = (const char **)l;
- const char **strr = (const char **)r;
- return strcmp(*strl, *strr);
-}
-
-/**
- * Return a sorted list of entries in the given directory. All entries
- * starting with a dot are ignored, and not present in the returned
- * list. The list and all entries are allocated using malloc() and need
- * to be freed.
- * This function returns 0 when everything is fine, non-zero otherwise.
- */
-static char
-list_dir(char ***retlist, size_t *retcnt, const char *path)
-{
- DIR *d;
- struct dirent *e;
- size_t rlen = 0;
- size_t rsize = 0;
- char **rlist = NULL;
-
- if ((d = opendir(path)) != NULL) {
- while ((e = readdir(d)) != NULL) {
- /* skip all dotfiles */
- if (e->d_name[0] == '.')
- continue;
-
- if (rlen == rsize) {
- rsize += LISTSZ;
- rlist = realloc(rlist,
- rsize * sizeof(rlist[0]));
- if (rlist == NULL) {
- fprintf(stderr, "out of memory\n");
- return 1;
- }
- }
- rlist[rlen] = strdup(e->d_name);
- if (rlist[rlen] == NULL) {
- fprintf(stderr, "out of memory\n");
- return 1;
- }
- rlen++;
- }
- closedir(d);
-
- qsort(rlist, rlen, sizeof(rlist[0]), compare_strings);
-
- *retlist = rlist;
- *retcnt = rlen;
- return 0;
- } else {
- return 1;
- }
-}
-
-static void
-write_hashes(
- struct timeval *tv,
- const char *root,
- const char *name,
- const char *type,
- FILE *m,
- gzFile gm)
-{
- size_t flen = 0;
- char sha256[(SHA256_DIGEST_LENGTH * 2) + 1];
- char sha512[(SHA512_DIGEST_LENGTH * 2) + 1];
- char whrlpl[(WHIRLPOOL_DIGEST_LENGTH * 2) + 1];
- char blak2b[(BLAKE2B_OUTBYTES * 2) + 1];
- char data[8192];
- char fname[8192];
- size_t len;
- struct stat s;
-
- snprintf(fname, sizeof(fname), "%s/%s", root, name);
-
- if (stat(fname, &s) != 0)
- return;
-
- update_times(tv, &s);
-
- get_hashes(fname, sha256, sha512, whrlpl, blak2b, &flen);
-
- len = snprintf(data, sizeof(data), "%s %s %zd", type, name, flen);
- if (hashes & HASH_BLAKE2B)
- len += snprintf(data + len, sizeof(data) - len,
- " BLAKE2B %s", blak2b);
- if (hashes & HASH_SHA256)
- len += snprintf(data + len, sizeof(data) - len,
- " SHA256 %s", sha256);
- if (hashes & HASH_SHA512)
- len += snprintf(data + len, sizeof(data) - len,
- " SHA512 %s", sha512);
- if (hashes & HASH_WHIRLPOOL)
- len += snprintf(data + len, sizeof(data) - len,
- " WHIRLPOOL %s", whrlpl);
- len += snprintf(data + len, sizeof(data) - len, "\n");
-
- if (m != NULL)
- fwrite(data, len, 1, m);
- if (gm != NULL)
- gzwrite(gm, data, len);
-}
-
-static char
-write_hashes_dir(
- struct timeval *tv,
- const char *root,
- const char *name,
- gzFile zm)
-{
- char path[8192];
- char **dentries;
- size_t dentrieslen;
- size_t i;
-
- snprintf(path, sizeof(path), "%s/%s", root, name);
- if (list_dir(&dentries, &dentrieslen, path) == 0) {
- for (i = 0; i < dentrieslen; i++) {
- snprintf(path, sizeof(path), "%s/%s", name, dentries[i]);
- free(dentries[i]);
- if (write_hashes_dir(tv, root, path, zm) == 0)
- continue;
- /* regular file */
- write_hashes(tv, root, path, "DATA", NULL, zm);
- }
- free(dentries);
- return 0;
- } else {
- return 1;
- }
-}
-
-static char
-process_files(struct timeval *tv, const char *dir, const char *off, FILE *m)
-{
- char path[8192];
- char **dentries;
- size_t dentrieslen;
- size_t i;
-
- snprintf(path, sizeof(path), "%s/%s", dir, off);
- if (list_dir(&dentries, &dentrieslen, path) == 0) {
- for (i = 0; i < dentrieslen; i++) {
- snprintf(path, sizeof(path), "%s%s%s",
- off, *off == '\0' ? "" : "/", dentries[i]);
- free(dentries[i]);
- if (process_files(tv, dir, path, m) == 0)
- continue;
- /* regular file */
- write_hashes(tv, dir, path, "AUX", m, NULL);
- }
- free(dentries);
- return 0;
- } else {
- return 1;
- }
-}
-
-static int
-parse_layout_conf(const char *path)
-{
- FILE *f;
- char buf[8192];
- size_t len = 0;
- size_t sz;
- char *p;
- char *q;
- char *tok;
- char *last_nl;
- char *start;
- int ret = 0;
-
- if ((f = fopen(path, "r")) == NULL)
- return 0;
-
- /* read file, examine lines after encountering a newline, that is,
- * if the file doesn't end with a newline, the final bit is ignored */
- while ((sz = fread(buf + len, 1, sizeof(buf) - len, f)) > 0) {
- len += sz;
- start = buf;
- last_nl = NULL;
- for (p = buf; p - buf < len; p++) {
- if (*p == '\n') {
- if (last_nl != NULL)
- start = last_nl + 1;
- last_nl = p;
- do {
- sz = strlen("manifest-hashes");
- if (strncmp(start, "manifest-hashes", sz))
- break;
- if ((q = strchr(start + sz, '=')) == NULL)
- break;
- q++;
- while (isspace((int)*q))
- q++;
- /* parse the tokens, whitespace separated */
- tok = q;
- do {
- while (!isspace((int)*q))
- q++;
- sz = q - tok;
- if (strncmp(tok, "SHA256", sz) == 0) {
- ret |= HASH_SHA256;
- } else if (strncmp(tok, "SHA512", sz) == 0) {
- ret |= HASH_SHA512;
- } else if (strncmp(tok, "WHIRLPOOL", sz) == 0) {
- ret |= HASH_WHIRLPOOL;
- } else if (strncmp(tok, "BLAKE2B", sz) == 0) {
- ret |= HASH_BLAKE2B;
- } else {
- fprintf(stderr, "warning: unsupported hash from "
- "layout.conf: %.*s\n", (int)sz, tok);
- }
- while (isspace((int)*q) && *q != '\n')
- q++;
- tok = q;
- } while (*q != '\n');
- /* got it, expect only once, so stop processing */
- fclose(f);
- return ret;
- } while (0);
- }
- }
- if (last_nl != NULL) {
- last_nl++; /* skip \n */
- len = last_nl - buf;
- memmove(buf, last_nl, len);
- last_nl = buf;
- } else {
- /* skip too long line */
- len = 0;
- }
- }
-
- fclose(f);
- /* if we didn't find anything, return the default set */
- return HASH_DEFAULT;
-}
-
-static char *str_manifest = "Manifest";
-static char *str_manifest_gz = "Manifest.gz";
-static char *str_manifest_files_gz = "Manifest.files.gz";
-enum type_manifest {
- GLOBAL_MANIFEST, /* Manifest.files.gz + Manifest */
- SUBTREE_MANIFEST, /* Manifest.gz for recursive list of files */
- EBUILD_MANIFEST, /* Manifest thick from thin */
- CATEGORY_MANIFEST /* Manifest.gz with Manifest entries */
-};
-static char *
-generate_dir(const char *dir, enum type_manifest mtype)
-{
- FILE *f;
- char path[8192];
- struct stat s;
- struct timeval tv[2];
- char **dentries;
- size_t dentrieslen;
- size_t i;
-
- /* our timestamp strategy is as follows:
- * - when a Manifest exists, use its timestamp
- * - when a meta-Manifest is written (non-ebuilds) use the timestamp
- * of the latest Manifest referenced
- * - when a Manifest is written for something like eclasses, use the
- * timestamp of the latest file in the dir
- * this way we should keep updates limited to where changes are, and
- * also get reproducible mtimes. */
- tv[0].tv_sec = 0;
- tv[0].tv_usec = 0;
- tv[1].tv_sec = 0;
- tv[1].tv_usec = 0;
-
- if (mtype == GLOBAL_MANIFEST) {
- char *mfest;
- size_t len;
- gzFile mf;
- time_t rtime;
-
- snprintf(path, sizeof(path), "%s/%s", dir, str_manifest_files_gz);
- if ((mf = gzopen(path, "wb9")) == NULL) {
- fprintf(stderr, "failed to open file '%s' for writing: %s\n",
- path, strerror(errno));
- return NULL;
- }
-
- /* These "IGNORE" entries are taken from gx86, there is no
- * standardisation on this, on purpose, apparently. */
- len = snprintf(path, sizeof(path),
- "IGNORE distfiles\n"
- "IGNORE local\n"
- "IGNORE lost+found\n"
- "IGNORE packages\n");
- gzwrite(mf, path, len);
-
- if (list_dir(&dentries, &dentrieslen, dir) != 0)
- return NULL;
-
- for (i = 0; i < dentrieslen; i++) {
- /* ignore existing Manifests */
- if (strcmp(dentries[i], str_manifest_files_gz) == 0 ||
- strcmp(dentries[i], str_manifest) == 0)
- {
- free(dentries[i]);
- continue;
- }
-
- snprintf(path, sizeof(path), "%s/%s", dir, dentries[i]);
-
- mfest = NULL;
- if (!stat(path, &s)) {
- if (s.st_mode & S_IFDIR) {
- if (
- strcmp(dentries[i], "eclass") == 0 ||
- strcmp(dentries[i], "licenses") == 0 ||
- strcmp(dentries[i], "metadata") == 0 ||
- strcmp(dentries[i], "profiles") == 0 ||
- strcmp(dentries[i], "scripts") == 0
- )
- {
- mfest = generate_dir(path, SUBTREE_MANIFEST);
- } else {
- mfest = generate_dir(path, CATEGORY_MANIFEST);
- }
-
- if (mfest == NULL) {
- fprintf(stderr, "generating Manifest for %s failed!\n",
- path);
- gzclose(mf);
- return NULL;
- }
-
- snprintf(path, sizeof(path), "%s/%s",
- dentries[i], mfest);
- write_hashes(tv, dir, path, "MANIFEST", NULL, mf);
- } else if (s.st_mode & S_IFREG) {
- write_hashes(tv, dir, dentries[i], "DATA", NULL, mf);
- } /* ignore other "things" (like symlinks) as they
- don't belong in a tree */
- } else {
- fprintf(stderr, "stat(%s) failed: %s\n",
- path, strerror(errno));
- }
- free(dentries[i]);
- }
- free(dentries);
- gzclose(mf);
-
- if (tv[0].tv_sec != 0) {
- snprintf(path, sizeof(path), "%s/%s", dir, str_manifest_files_gz);
- utimes(path, tv);
- }
-
- /* create global Manifest */
- snprintf(path, sizeof(path), "%s/%s", dir, str_manifest);
- if ((f = fopen(path, "w")) == NULL) {
- fprintf(stderr, "failed to open file '%s' for writing: %s\n",
- path, strerror(errno));
- return NULL;
- }
-
- write_hashes(tv, dir, str_manifest_files_gz, "MANIFEST", f, NULL);
- time(&rtime);
- len = strftime(path, sizeof(path),
- "TIMESTAMP %Y-%m-%dT%H:%M:%SZ\n", gmtime(&rtime));
- fwrite(path, len, 1, f);
- fflush(f);
- fclose(f);
-
- /* because we write a timestamp in Manifest, we don't mess with
- * its mtime, else it would obviously lie */
- return str_manifest_files_gz;
- } else if (mtype == SUBTREE_MANIFEST) {
- const char *ldir;
- gzFile mf;
-
- snprintf(path, sizeof(path), "%s/%s", dir, str_manifest_gz);
- if ((mf = gzopen(path, "wb9")) == NULL) {
- fprintf(stderr, "failed to open file '%s' for writing: %s\n",
- path, strerror(errno));
- return NULL;
- }
-
- ldir = strrchr(dir, '/');
- if (ldir == NULL)
- ldir = dir;
- if (strcmp(ldir, "metadata") == 0) {
- size_t len;
- len = snprintf(path, sizeof(path),
- "IGNORE timestamp\n"
- "IGNORE timestamp.chk\n"
- "IGNORE timestamp.commit\n"
- "IGNORE timestamp.x\n");
- gzwrite(mf, path, len);
- }
-
- if (list_dir(&dentries, &dentrieslen, dir) != 0)
- return NULL;
-
- for (i = 0; i < dentrieslen; i++) {
- /* ignore existing Manifests */
- if (strcmp(dentries[i], str_manifest_gz) == 0) {
- free(dentries[i]);
- continue;
- }
-
- if (write_hashes_dir(tv, dir, dentries[i], mf) != 0)
- write_hashes(tv, dir, dentries[i], "DATA", NULL, mf);
- free(dentries[i]);
- }
-
- free(dentries);
- gzclose(mf);
-
- if (tv[0].tv_sec != 0) {
- /* set Manifest and dir mtime to most recent file found */
- snprintf(path, sizeof(path), "%s/%s", dir, str_manifest_gz);
- utimes(path, tv);
- utimes(dir, tv);
- }
-
- return str_manifest_gz;
- } else if (mtype == CATEGORY_MANIFEST) {
- char *mfest;
- gzFile mf;
-
- snprintf(path, sizeof(path), "%s/%s", dir, str_manifest_gz);
- if ((mf = gzopen(path, "wb9")) == NULL) {
- fprintf(stderr, "failed to open file '%s' for writing: %s\n",
- path, strerror(errno));
- return NULL;
- }
-
- if (list_dir(&dentries, &dentrieslen, dir) != 0)
- return NULL;
-
- for (i = 0; i < dentrieslen; i++) {
- /* ignore existing Manifests */
- if (strcmp(dentries[i], str_manifest_gz) == 0) {
- free(dentries[i]);
- continue;
- }
-
- snprintf(path, sizeof(path), "%s/%s", dir, dentries[i]);
- if (!stat(path, &s)) {
- if (s.st_mode & S_IFDIR) {
- mfest = generate_dir(path, EBUILD_MANIFEST);
-
- if (mfest == NULL) {
- fprintf(stderr, "generating Manifest for %s failed!\n",
- path);
- gzclose(mf);
- return NULL;
- }
-
- snprintf(path, sizeof(path), "%s/%s",
- dentries[i], mfest);
- write_hashes(tv, dir, path, "MANIFEST", NULL, mf);
- } else if (s.st_mode & S_IFREG) {
- write_hashes(tv, dir, dentries[i], "DATA", NULL, mf);
- } /* ignore other "things" (like symlinks) as they
- don't belong in a tree */
- } else {
- fprintf(stderr, "stat(%s) failed: %s\n",
- path, strerror(errno));
- }
- free(dentries[i]);
- }
-
- free(dentries);
- gzclose(mf);
-
- if (tv[0].tv_sec != 0) {
- /* set Manifest and dir mtime to most ebuild dir found */
- snprintf(path, sizeof(path), "%s/%s", dir, str_manifest_gz);
- utimes(path, tv);
- utimes(dir, tv);
- }
-
- return str_manifest_gz;
- } else if (mtype == EBUILD_MANIFEST) {
- char newmanifest[8192];
- FILE *m;
-
- snprintf(newmanifest, sizeof(newmanifest), "%s/.Manifest.new", dir);
- if ((m = fopen(newmanifest, "w")) == NULL) {
- fprintf(stderr, "failed to open file '%s' for writing: %s\n",
- newmanifest, strerror(errno));
- return NULL;
- }
-
- /* we know the Manifest is sorted, and stuff in files/ is
- * prefixed with AUX, hence, if it exists, we need to do it
- * first */
- snprintf(path, sizeof(path), "%s/files", dir);
- process_files(tv, path, "", m);
-
- /* the Manifest file may be missing in case there are no DIST
- * entries to be stored */
- snprintf(path, sizeof(path), "%s/%s", dir, str_manifest);
- if (!stat(path, &s))
- update_times(tv, &s);
- f = fopen(path, "r");
- if (f != NULL) {
- /* copy the DIST entries, we could do it unconditional, but this
- * way we can re-run without producing invalid Manifests */
- while (fgets(path, sizeof(path), f) != NULL) {
- if (strncmp(path, "DIST ", 5) == 0)
- if (fwrite(path, strlen(path), 1, m) != 1) {
- fprintf(stderr, "failed to write to "
- "%s/.Manifest.new: %s\n",
- dir, strerror(errno));
- fclose(f);
- fclose(m);
- return NULL;
- }
- }
- fclose(f);
- }
-
- if (list_dir(&dentries, &dentrieslen, dir) == 0) {
- for (i = 0; i < dentrieslen; i++) {
- if (strcmp(dentries[i] + strlen(dentries[i]) - 7,
- ".ebuild") != 0)
- {
- free(dentries[i]);
- continue;
- }
- write_hashes(tv, dir, dentries[i], "EBUILD", m, NULL);
- free(dentries[i]);
- }
- free(dentries);
- }
-
- write_hashes(tv, dir, "ChangeLog", "MISC", m, NULL);
- write_hashes(tv, dir, "metadata.xml", "MISC", m, NULL);
-
- fflush(m);
- fclose(m);
-
- snprintf(path, sizeof(path), "%s/%s", dir, str_manifest);
- rename(newmanifest, path);
-
- if (tv[0].tv_sec != 0) {
- /* set Manifest and dir mtime to most recent file we found */
- utimes(path, tv);
- utimes(dir, tv);
- }
-
- return str_manifest;
- } else {
- return NULL;
- }
-}
-
-static char *
-process_dir_gen(const char *dir)
-{
- char path[8192];
- int newhashes;
-
- snprintf(path, sizeof(path), "%s/metadata/layout.conf", dir);
- if ((newhashes = parse_layout_conf(path)) != 0) {
- hashes = newhashes;
- } else {
- return "generation must be done on a full tree";
- }
-
- if (chdir(dir) != 0) {
- fprintf(stderr, "cannot chdir() to %s: %s\n", dir, strerror(errno));
- return "not a directory";
- }
-
- if (generate_dir(".\0", GLOBAL_MANIFEST) == NULL)
- return "generation failed";
-
- return NULL;
-}
-
-static char
-verify_gpg_sig(const char *path)
-{
- gpgme_ctx_t g_ctx;
- gpgme_data_t manifest;
- gpgme_data_t out;
- gpgme_verify_result_t vres;
- gpgme_signature_t sig;
- gpgme_key_t key;
- char buf[32];
- FILE *f;
- struct tm *ctime;
- char ret = 1; /* fail */
-
- if ((f = fopen(path, "r")) == NULL) {
- fprintf(stderr, "failed to open %s: %s\n", path, strerror(errno));
- return ret;
- }
-
- if (gpgme_new(&g_ctx) != GPG_ERR_NO_ERROR) {
- fprintf(stderr, "failed to create gpgme context\n");
- return ret;
- }
-
- if (gpgme_data_new(&out) != GPG_ERR_NO_ERROR) {
- fprintf(stderr, "failed to create new gpgme data\n");
- return ret;
- }
-
- if (gpgme_data_new_from_stream(&manifest, f) != GPG_ERR_NO_ERROR) {
- fprintf(stderr, "failed to create new gpgme data from stream\n");
- return ret;
- }
-
- if (gpgme_op_verify(g_ctx, manifest, NULL, out) != GPG_ERR_NO_ERROR) {
- fprintf(stderr, "failed to verify signature\n");
- return ret;
- }
-
- vres = gpgme_op_verify_result(g_ctx);
- fclose(f);
-
- if (vres == NULL || vres->signatures == NULL) {
- fprintf(stderr, "verification failed due to a missing gpg keyring\n");
- return ret;
- }
-
- for (sig = vres->signatures; sig != NULL; sig = sig->next) {
- if (sig->status != GPG_ERR_NO_PUBKEY) {
- ctime = gmtime((time_t *)&sig->timestamp);
- strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S UTC", ctime);
- printf("%s key fingerprint "
- "%.4s %.4s %.4s %.4s %.4s %.4s %.4s %.4s %.4s %.4s\n"
- "%s signature made %s by\n",
- gpgme_pubkey_algo_name(sig->pubkey_algo),
- sig->fpr + 0, sig->fpr + 4, sig->fpr + 8, sig->fpr + 12,
- sig->fpr + 16, sig->fpr + 20, sig->fpr + 24, sig->fpr + 28,
- sig->fpr + 32, sig->fpr + 36,
- sig->status == GPG_ERR_NO_ERROR ? "good" : "BAD",
- buf);
-
- if (gpgme_get_key(g_ctx, sig->fpr, &key, 0) == GPG_ERR_NO_ERROR) {
- ret = 0; /* valid */
- if (key->uids != NULL)
- printf("%s\n", key->uids->uid);
- gpgme_key_release(key);
- }
- }
-
- switch (sig->status) {
- case GPG_ERR_NO_ERROR:
- /* nothing, handled above */
- break;
- case GPG_ERR_SIG_EXPIRED:
- printf("the signature is valid but expired\n");
- break;
- case GPG_ERR_KEY_EXPIRED:
- printf("the signature is valid but the key used to verify "
- "the signature has expired\n");
- break;
- case GPG_ERR_CERT_REVOKED:
- printf("the signature is valid but the key used to verify "
- "the signature has been revoked\n");
- break;
- case GPG_ERR_BAD_SIGNATURE:
- printf("the signature is invalid\n");
- break;
- case GPG_ERR_NO_PUBKEY:
- printf("the signature could not be verified due to a "
- "missing key\n");
- break;
- default:
- printf("there was some other error which prevented the "
- "signature verification\n");
- break;
- }
- }
-
- gpgme_release(g_ctx);
-
- return ret;
-}
-
-static size_t checked_manifests = 0;
-static size_t checked_files = 0;
-static size_t failed_files = 0;
-
-static char
-verify_file(const char *dir, char *mfline, const char *mfest)
-{
- char *path;
- char *size;
- long long int fsize;
- char *hashtype;
- char *hash;
- char *p;
- char buf[8192];
- size_t flen = 0;
- char sha256[(SHA256_DIGEST_LENGTH * 2) + 1];
- char sha512[(SHA512_DIGEST_LENGTH * 2) + 1];
- char whrlpl[(WHIRLPOOL_DIGEST_LENGTH * 2) + 1];
- char blak2b[(BLAKE2B_OUTBYTES * 2) + 1];
- char ret = 0;
-
- /* mfline is a Manifest file line with type and leading path
- * stripped, something like:
- * file <SIZE> <HASHTYPE HASH ...>
- * we parse this, and verify the size and hashes */
-
- path = mfline;
- p = strchr(path, ' ');
- if (p == NULL) {
- fprintf(stderr, "%s: corrupt manifest line: %s\n", mfest, path);
- return 1;
- }
- *p++ = '\0';
-
- size = p;
- p = strchr(size, ' ');
- if (p == NULL) {
- fprintf(stderr, "%s: corrupt manifest line, need size for %s\n",
- mfest, path);
- return 1;
- }
- *p++ = '\0';
- fsize = strtoll(size, NULL, 10);
- if (fsize == 0 && errno == EINVAL) {
- fprintf(stderr, "%s: corrupt manifest line, size is not a number: %s\n",
- dir + 2, size);
- return 1;
- }
-
- sha256[0] = sha512[0] = whrlpl[0] = blak2b[0] = '\0';
- snprintf(buf, sizeof(buf), "%s/%s", dir, path);
- get_hashes(buf, sha256, sha512, whrlpl, blak2b, &flen);
-
- if (flen == 0) {
- fprintf(stderr, "cannot locate %s/%s\n", dir + 2, path);
- return 1;
- }
-
- checked_files++;
-
- if (flen != fsize) {
- printf("%s:%s:\n- file size mismatch\n"
- " got: %zd\n"
- " expected: %lld\n",
- mfest, path, flen, fsize);
- failed_files++;
- return 1;
- }
-
- /* now we are in free territory, we read TYPE HASH pairs until we
- * drained the string, and match them against what we computed */
- while (p != NULL && *p != '\0') {
- hashtype = p;
- p = strchr(hashtype, ' ');
- if (p == NULL) {
- fprintf(stderr, "%s: corrupt manifest line, missing hash type\n",
- mfest);
- return 1;
- }
- *p++ = '\0';
-
- hash = p;
- p = strchr(hash, ' ');
- if (p != NULL)
- *p++ = '\0';
-
-#define idif(X) if (X == 0) printf("%s:%s:\n", mfest, path);
- if (strcmp(hashtype, "SHA256") == 0) {
- if (!(hashes & HASH_SHA256)) {
- idif(ret);
- printf("- warning: hash SHA256 ignored as "
- "it is not enabled for this repository\n");
- } else if (strcmp(hash, sha256) != 0) {
- idif(ret);
- printf("- SHA256 hash mismatch\n"
- " computed: '%s'\n"
- " recorded in manifest: '%s'\n",
- sha256, hash);
- ret = 1;
- }
- sha256[0] = '\0';
- } else if (strcmp(hashtype, "SHA512") == 0) {
- if (!(hashes & HASH_SHA512)) {
- idif(ret);
- printf("- warning: hash SHA512 ignored as "
- "it is not enabled for this repository\n");
- } else if (strcmp(hash, sha512) != 0) {
- idif(ret);
- printf("- SHA512 hash mismatch\n"
- " computed: '%s'\n"
- " recorded in manifest: '%s'\n",
- sha512, hash);
- ret = 1;
- }
- sha512[0] = '\0';
- } else if (strcmp(hashtype, "WHIRLPOOL") == 0) {
- if (!(hashes & HASH_WHIRLPOOL)) {
- idif(ret);
- printf("- warning: hash WHIRLPOOL ignored as "
- "it is not enabled for this repository\n");
- } else if (strcmp(hash, whrlpl) != 0) {
- idif(ret);
- printf("- WHIRLPOOL hash mismatch\n"
- " computed: '%s'\n"
- " recorded in manifest: '%s'\n",
- whrlpl, hash);
- ret = 1;
- }
- whrlpl[0] = '\0';
- } else if (strcmp(hashtype, "BLAKE2B") == 0) {
- if (!(hashes & HASH_BLAKE2B)) {
- idif(ret);
- printf("- warning: hash BLAKE2B ignored as "
- "it is not enabled for this repository\n");
- } else if (strcmp(hash, blak2b) != 0) {
- idif(ret);
- printf("- BLAKE2B hash mismatch\n"
- " computed: '%s'\n"
- " recorded in manifest: '%s'\n",
- blak2b, hash);
- ret = 1;
- }
- blak2b[0] = '\0';
- } else {
- idif(ret);
- printf("- unsupported hash: %s\n", hashtype);
- ret = 1;
- }
- }
-
- if (sha256[0] != '\0') {
- idif(ret);
- printf("- missing hash: SHA256\n");
- ret = 1;
- }
- if (sha512[0] != '\0') {
- idif(ret);
- printf("- missing hash: SHA512\n");
- ret = 1;
- }
- if (whrlpl[0] != '\0') {
- idif(ret);
- printf("- missing hash: WHIRLPOOL\n");
- ret = 1;
- }
- if (blak2b[0] != '\0') {
- idif(ret);
- printf("- missing hash: BLAKE2B\n");
- ret = 1;
- }
-
- failed_files += ret;
- return ret;
-}
-
-static int
-compare_elems(const void *l, const void *r)
-{
- const char *strl = *((const char **)l) + 2;
- const char *strr = *((const char **)r) + 2;
- unsigned char cl;
- unsigned char cr;
- /* compare treating / as end of string */
- while ((cl = *strl++) == (cr = *strr++))
- if (cl == '\0')
- return 0;
- if (cl == '/')
- cl = '\0';
- if (cr == '/')
- cr = '\0';
- return cl - cr;
-}
-
-struct subdir_workload {
- size_t subdirlen;
- size_t elemslen;
- char **elems;
-};
-
-static char verify_manifest(const char *dir, const char *manifest);
-
-static char
-verify_dir(
- const char *dir,
- char **elems,
- size_t elemslen,
- size_t skippath,
- const char *mfest)
-{
- char **dentries = NULL;
- size_t dentrieslen = 0;
- size_t curelem = 0;
- size_t curdentry = 0;
- char *entry;
- char *slash;
- char etpe;
- char ret = 0;
- int cmp;
- struct subdir_workload **subdir = NULL;
- size_t subdirsize = 0;
- size_t subdirlen = 0;
-
- /* shortcut a single Manifest entry pointing to the same dir
- * (happens at top-level) */
- if (elemslen == 1 && skippath == 0 &&
- **elems == 'M' && strchr(*elems + 2, '/') == NULL)
- {
- if ((ret = verify_file(dir, *elems + 2, mfest)) == 0) {
- slash = strchr(*elems + 2, ' ');
- if (slash != NULL)
- *slash = '\0';
- /* else, verify_manifest will fail, so ret will be handled */
- ret = verify_manifest(dir, *elems + 2);
- }
- return ret;
- }
-
- /*
- * We have a list of entries from the manifest just read, now we
- * need to match these onto the directory layout. From what we got
- * - we can ignore TIMESTAMP and DIST entries
- * - IGNOREs need to be handled separate (shortcut)
- * - MANIFESTs need to be handled on their own, for memory
- * consumption reasons, we defer them to until we've verified
- * what's left, we treat the path the Manifest refers to as IGNORE
- * - DATAs, EBUILDs and MISCs needs verifying
- * - AUXs need verifying, but in files/ subdir
- * If we sort both lists, we should be able to do a merge-join, to
- * easily flag missing entries in either list without hashing or
- * anything.
- */
- if (list_dir(&dentries, &dentrieslen, dir) == 0) {
- while (curdentry < dentrieslen) {
- if (strcmp(dentries[curdentry], str_manifest) == 0 ||
- strcmp(dentries[curdentry], str_manifest_gz) == 0 ||
- strcmp(dentries[curdentry], str_manifest_files_gz) == 0)
- {
- curdentry++;
- continue;
- }
-
- if (curelem < elemslen) {
- entry = elems[curelem] + 2 + skippath;
- etpe = *elems[curelem];
- } else {
- entry = "";
- etpe = 'I';
- }
-
- /* handle subdirs first */
- if ((slash = strchr(entry, '/')) != NULL) {
- size_t sublen = slash - entry;
- int elemstart = curelem;
- char **subelems = &elems[curelem];
-
- /* collect all entries like this one (same subdir) into
- * a sub-list that we can verify */
- curelem++;
- while (curelem < elemslen &&
- strncmp(entry, elems[curelem] + 2 + skippath,
- sublen + 1) == 0)
- curelem++;
-
- if (subdirlen == subdirsize) {
- subdirsize += LISTSZ;
- subdir = realloc(subdir,
- subdirsize * sizeof(subdir[0]));
- if (subdir == NULL) {
- fprintf(stderr, "out of memory\n");
- return 1;
- }
- }
- subdir[subdirlen] = malloc(sizeof(struct subdir_workload));
- if (subdir[subdirlen] == NULL) {
- fprintf(stderr, "out of memory\n");
- return 1;
- }
- subdir[subdirlen]->subdirlen = sublen;
- subdir[subdirlen]->elemslen = curelem - elemstart;
- subdir[subdirlen]->elems = subelems;
- subdirlen++;
-
- curelem--; /* move back, see below */
-
- /* modify the last entry to be the subdir, such that we
- * can let the code below synchronise with dentries */
- elems[curelem][2 + skippath + sublen] = ' ';
- entry = elems[curelem] + 2 + skippath;
- etpe = 'S'; /* flag this was a subdir */
- }
-
- /* does this entry exist in list? */
- if (*entry == '\0') {
- /* end of list reached, force dir to catch up */
- cmp = 1;
- } else {
- slash = strchr(entry, ' ');
- if (slash != NULL)
- *slash = '\0';
- cmp = strcmp(entry, dentries[curdentry]);
- if (slash != NULL)
- *slash = ' ';
- }
- if (cmp == 0) {
- /* equal, so yay */
- if (etpe == 'D') {
- ret |= verify_file(dir, entry, mfest);
- }
- /* else this is I(GNORE) or S(ubdir), which means it is
- * ok in any way (M shouldn't happen) */
- curelem++;
- curdentry++;
- } else if (cmp < 0) {
- /* entry is missing from dir */
- if (etpe == 'I') {
- /* right, we can ignore this */
- } else {
- ret |= 1;
- slash = strchr(entry, ' ');
- if (slash != NULL)
- *slash = '\0';
- printf("%s:%s:\n- %s file not found\n",
- mfest, entry, etpe == 'M' ? "MANIFEST" : "DATA");
- if (slash != NULL)
- *slash = ' ';
- failed_files++;
- }
- curelem++;
- } else if (cmp > 0) {
- /* dir has extra element */
- ret |= 1;
- printf("%s:\n- found excess file: %s\n",
- mfest, dentries[curdentry]);
- curdentry++;
- failed_files++;
- }
- }
-
- while (dentrieslen-- > 0)
- free(dentries[dentrieslen]);
- free(dentries);
-
-#pragma omp parallel for shared(ret) private(entry, etpe, slash)
- for (cmp = 0; cmp < subdirlen; cmp++) {
- char ndir[8192];
-
- entry = subdir[cmp]->elems[0] + 2 + skippath;
- etpe = subdir[cmp]->elems[0][0];
-
- /* restore original entry format */
- subdir[cmp]->elems[subdir[cmp]->elemslen - 1]
- [2 + skippath + subdir[cmp]->subdirlen] = '/';
-
- if (etpe == 'M') {
- size_t skiplen = strlen(dir) + 1 + subdir[cmp]->subdirlen;
- /* sub-Manifest, we need to do a proper recurse */
- slash = strrchr(entry, '/'); /* cannot be NULL */
- snprintf(ndir, sizeof(ndir), "%s/%s", dir, entry);
- ndir[skiplen] = '\0';
- slash = strchr(ndir + skiplen + 1, ' ');
- if (slash != NULL) /* path should fit in ndir ... */
- *slash = '\0';
- if (verify_file(dir, entry, mfest) != 0 ||
- verify_manifest(ndir, ndir + skiplen + 1) != 0)
- ret |= 1;
- } else {
- snprintf(ndir, sizeof(ndir), "%s/%.*s", dir,
- (int)subdir[cmp]->subdirlen, entry);
- ret |= verify_dir(ndir, subdir[cmp]->elems,
- subdir[cmp]->elemslen,
- skippath + subdir[cmp]->subdirlen + 1, mfest);
- }
-
- free(subdir[cmp]);
- }
-
- if (subdir)
- free(subdir);
-
- return ret;
- } else {
- return 1;
- }
-}
-
-static char
-verify_manifest(const char *dir, const char *manifest)
-{
- char buf[8192];
- FILE *f;
- gzFile mf;
- char ret = 0;
-
- size_t elemssize = 0;
- size_t elemslen = 0;
- char **elems = NULL;
-#define append_list(STR) \
- if (strncmp(STR, "TIMESTAMP ", 10) != 0 || strncmp(STR, "DIST ", 5) != 0) {\
- char *endp = STR + strlen(STR) - 1;\
- while (isspace(*endp))\
- *endp-- = '\0';\
- if (elemslen == elemssize) {\
- elemssize += LISTSZ;\
- elems = realloc(elems, elemssize * sizeof(elems[0]));\
- if (elems == NULL) {\
- fprintf(stderr, "out of memory\n");\
- return 1;\
- }\
- }\
- if (strncmp(STR, "IGNORE ", 7) == 0) {\
- STR[5] = 'I';\
- elems[elemslen] = strdup(STR + 5);\
- if (elems[elemslen] == NULL) {\
- fprintf(stderr, "out of memory\n");\
- return 1;\
- }\
- elemslen++;\
- } else if (strncmp(STR, "MANIFEST ", 9) == 0) {\
- STR[7] = 'M';\
- elems[elemslen] = strdup(STR + 7);\
- if (elems[elemslen] == NULL) {\
- fprintf(stderr, "out of memory\n");\
- return 1;\
- }\
- elemslen++;\
- } else if (strncmp(STR, "DATA ", 5) == 0 ||\
- strncmp(STR, "MISC ", 5) == 0 ||\
- strncmp(STR, "EBUILD ", 7) == 0)\
- {\
- if (*STR == 'E') {\
- STR[5] = 'D';\
- elems[elemslen] = strdup(STR + 5);\
- } else {\
- STR[3] = 'D';\
- elems[elemslen] = strdup(STR + 3);\
- }\
- if (elems[elemslen] == NULL) {\
- fprintf(stderr, "out of memory\n");\
- return 1;\
- }\
- elemslen++;\
- } else if (strncmp(STR, "AUX ", 4) == 0) {\
- /* translate directly into what it is: DATA in files/ */\
- size_t slen = strlen(STR + 2) + sizeof("files/");\
- elems[elemslen] = malloc(slen);\
- if (elems[elemslen] == NULL) {\
- fprintf(stderr, "out of memory\n");\
- return 1;\
- }\
- snprintf(elems[elemslen], slen, "D files/%s", STR + 4);\
- elemslen++;\
- }\
- }
-
- snprintf(buf, sizeof(buf), "%s/%s", dir, manifest);
- if (strcmp(manifest, str_manifest) == 0) {
- if ((f = fopen(buf, "r")) == NULL) {
- fprintf(stderr, "failed to open %s: %s\n",
- buf, strerror(errno));
- return 1;
- }
- while (fgets(buf, sizeof(buf), f) != NULL) {
- append_list(buf);
- }
- fclose(f);
- } else if (strcmp(manifest, str_manifest_files_gz) == 0 ||
- strcmp(manifest, str_manifest_gz) == 0)
- {
- if ((mf = gzopen(buf, "rb9")) == NULL) {
- fprintf(stderr, "failed to open file '%s' for reading: %s\n",
- buf, strerror(errno));
- return 1;
- }
- while (gzgets(mf, buf, sizeof(buf)) != NULL) {
- append_list(buf);
- }
- gzclose(mf);
- }
-
- /* The idea:
- * - Manifest without MANIFEST entries, we need to scan the entire
- * subtree
- * - Manifest with MANIFEST entries, assume they are just one level
- * deeper, thus ignore that subdir, further like above
- * - Manifest at top-level, needs to be igored as it only points to
- * the larger Manifest.files.gz
- */
- qsort(elems, elemslen, sizeof(elems[0]), compare_elems);
- snprintf(buf, sizeof(buf), "%s/%s", dir, manifest);
- ret = verify_dir(dir, elems, elemslen, 0, buf + 2);
- checked_manifests++;
-
- while (elemslen-- > 0)
- free(elems[elemslen]);
- free(elems);
-
- return ret;
-}
-
-static char *
-process_dir_vrfy(const char *dir)
-{
- char buf[8192];
- int newhashes;
- char *ret = NULL;
- struct timeval startt;
- struct timeval finisht;
- double etime;
-
- gettimeofday(&startt, NULL);
-
- fprintf(stdout, "verifying %s...\n", dir);
- snprintf(buf, sizeof(buf), "%s/metadata/layout.conf", dir);
- if ((newhashes = parse_layout_conf(buf)) != 0) {
- hashes = newhashes;
- } else {
- return "verification must be done on a full tree";
- }
-
- if (chdir(dir) != 0) {
- fprintf(stderr, "cannot chdir() to %s: %s\n", dir, strerror(errno));
- return "not a directory";
- }
-
- if (verify_gpg_sig(str_manifest) != 0)
- ret = "gpg signature invalid";
-
- /* verification goes like this:
- * - verify the signature of the top-level Manifest file (done
- * above)
- * - read the contents of the Manifest file, and process the
- * entries - verify them, check there are no files which shouldn't
- * be there
- * - recurse into directories for which Manifest files are defined
- */
- if (verify_manifest(".\0", str_manifest) != 0)
- ret = "manifest verification failed";
-
- gettimeofday(&finisht, NULL);
-
- etime = ((double)((finisht.tv_sec - startt.tv_sec) * 1000000 +
- finisht.tv_usec) - (double)startt.tv_usec) / 1000000.0;
- printf("checked %zd Manifests, %zd files, %zd failures in %.02fs\n",
- checked_manifests, checked_files, failed_files, etime);
- return ret;
-}
-
-int
-main(int argc, char *argv[])
-{
- char *prog;
- char *(*runfunc)(const char *);
- int arg = 1;
- int ret = 0;
- char *rsn;
-
- if ((prog = strrchr(argv[0], '/')) == NULL) {
- prog = argv[0];
- } else {
- prog++;
- }
-
- if (argc > 1) {
- if (strcmp(argv[1], "hashverify") == 0 ||
- strcmp(argv[1], "hashgen") == 0)
- {
- prog = argv[1];
- arg = 2;
- }
- }
-
- if (strcmp(prog, "hashverify") == 0) {
- runfunc = &process_dir_vrfy;
- } else {
- /* default mode: hashgen */
- runfunc = &process_dir_gen;
- }
-
- gpgme_check_version(NULL);
-
- if (argc > 1) {
- for (; arg < argc; arg++) {
- rsn = runfunc(argv[arg]);
- if (rsn != NULL) {
- printf("%s\n", rsn);
- ret |= 1;
- }
- }
- } else {
- rsn = runfunc(".");
- if (rsn != NULL) {
- printf("%s\n", rsn);
- ret |= 1;
- }
- }
-
- return ret;
-}
next reply other threads:[~2018-03-17 20:59 UTC|newest]
Thread overview: 78+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-03-17 20:59 Fabian Groffen [this message]
-- strict thread matches above, loose matches on Subject: below --
2024-07-10 18:24 [gentoo-commits] repo/proj/prefix:master commit in: scripts/rsync-generation/ Fabian Groffen
2024-06-14 20:13 Fabian Groffen
2024-03-31 10:26 Fabian Groffen
2024-03-31 10:09 Fabian Groffen
2024-03-31 8:53 Fabian Groffen
2024-03-31 8:46 Fabian Groffen
2024-03-31 8:27 Fabian Groffen
2024-03-30 18:44 Fabian Groffen
2024-03-30 11:46 Fabian Groffen
2024-03-29 10:31 Fabian Groffen
2024-03-29 10:31 Fabian Groffen
2024-03-28 16:12 Fabian Groffen
2024-03-28 16:12 Fabian Groffen
2024-03-28 16:12 Fabian Groffen
2024-03-28 16:12 Fabian Groffen
2023-09-11 10:39 Fabian Groffen
2023-08-01 2:40 Benda XU
2023-04-09 16:06 Fabian Groffen
2022-08-17 19:27 Fabian Groffen
2022-07-24 20:11 Fabian Groffen
2019-06-07 5:44 Fabian Groffen
2019-06-07 5:44 Fabian Groffen
2018-05-14 15:54 Fabian Groffen
2018-03-29 5:55 Fabian Groffen
2018-03-27 14:03 Fabian Groffen
2018-03-17 20:59 Fabian Groffen
2018-03-12 10:06 Fabian Groffen
2018-03-10 15:04 Fabian Groffen
2018-03-07 18:04 Fabian Groffen
2018-03-03 21:42 Fabian Groffen
2018-03-01 16:36 Fabian Groffen
2018-03-01 14:03 Fabian Groffen
2018-03-01 13:00 Fabian Groffen
2018-03-01 10:55 Fabian Groffen
2018-03-01 6:42 Fabian Groffen
2018-02-28 19:09 Fabian Groffen
2018-02-28 18:44 Fabian Groffen
2018-02-28 18:44 Fabian Groffen
2018-02-28 18:44 Fabian Groffen
2018-02-28 14:44 Fabian Groffen
2018-02-28 14:44 Fabian Groffen
2018-02-22 19:45 Fabian Groffen
2018-02-22 7:29 Fabian Groffen
2018-02-21 8:53 Fabian Groffen
2018-02-17 17:19 Fabian Groffen
2018-02-17 8:13 Fabian Groffen
2017-12-01 13:45 Fabian Groffen
2017-11-29 21:36 Fabian Groffen
2017-11-29 21:36 Fabian Groffen
2017-11-29 19:30 Fabian Groffen
2017-11-29 19:30 Fabian Groffen
2017-11-29 19:30 Fabian Groffen
2017-11-29 16:46 Fabian Groffen
2017-11-29 16:46 Fabian Groffen
2017-11-29 14:38 Fabian Groffen
2017-11-27 14:10 Fabian Groffen
2017-11-27 13:07 Fabian Groffen
2017-11-27 13:07 Fabian Groffen
2017-09-09 18:39 Fabian Groffen
2016-10-12 7:24 Fabian Groffen
2016-09-09 13:38 Fabian Groffen
2016-09-07 11:02 Fabian Groffen
2016-08-17 4:26 Fabian Groffen
2016-08-16 7:57 Fabian Groffen
2016-07-29 9:01 Fabian Groffen
2016-07-29 8:08 Fabian Groffen
2016-05-03 18:35 Fabian Groffen
2016-05-03 16:08 Fabian Groffen
2016-04-14 15:38 Fabian Groffen
2016-04-14 13:39 Fabian Groffen
2016-04-06 12:32 Fabian Groffen
2016-04-06 11:28 Fabian Groffen
2016-04-06 11:28 Fabian Groffen
2016-04-06 10:50 Fabian Groffen
2016-04-06 10:49 Fabian Groffen
2016-01-05 19:08 Fabian Groffen
2015-08-31 18:53 Fabian Groffen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1521320291.9e0ef57926049281e6075a8040c6c99871878ca5.grobian@gentoo \
--to=grobian@gentoo.org \
--cc=gentoo-commits@lists.gentoo.org \
--cc=gentoo-dev@lists.gentoo.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox