summaryrefslogtreecommitdiff
path: root/rpmio
diff options
context:
space:
mode:
Diffstat (limited to 'rpmio')
-rw-r--r--rpmio/Makefile.am13
-rw-r--r--rpmio/argv.c28
-rw-r--r--rpmio/argv.h8
-rw-r--r--rpmio/base64.c2
-rw-r--r--rpmio/digest.c82
-rw-r--r--rpmio/digest.h5
-rw-r--r--rpmio/digest_beecrypt.c253
-rw-r--r--rpmio/digest_nss.c62
-rw-r--r--rpmio/digest_openssl.c839
-rw-r--r--rpmio/macro.c1324
-rw-r--r--rpmio/rpmbase64.h6
-rw-r--r--rpmio/rpmfileutil.c70
-rw-r--r--rpmio/rpmfileutil.h4
-rw-r--r--rpmio/rpmglob.c66
-rw-r--r--rpmio/rpmio.c1253
-rw-r--r--rpmio/rpmio.h1
-rw-r--r--rpmio/rpmio_internal.h8
-rw-r--r--rpmio/rpmkeyring.c159
-rw-r--r--rpmio/rpmkeyring.h17
-rw-r--r--rpmio/rpmlog.c372
-rw-r--r--rpmio/rpmlog.h56
-rw-r--r--rpmio/rpmlua.c56
-rw-r--r--rpmio/rpmlua.h2
-rw-r--r--rpmio/rpmmacro.h34
-rw-r--r--rpmio/rpmpgp.c370
-rw-r--r--rpmio/rpmpgp.h80
-rw-r--r--rpmio/rpmsq.c246
-rw-r--r--rpmio/rpmsq.h50
-rw-r--r--rpmio/rpmstrpool.c42
-rw-r--r--rpmio/rpmstrpool.h13
-rw-r--r--rpmio/rpmsw.h2
-rw-r--r--rpmio/rpmurl.h2
-rw-r--r--rpmio/rpmutil.h5
-rw-r--r--rpmio/stubs.c18
34 files changed, 3686 insertions, 1862 deletions
diff --git a/rpmio/Makefile.am b/rpmio/Makefile.am
index 7b27d6153..6024ae4e2 100644
--- a/rpmio/Makefile.am
+++ b/rpmio/Makefile.am
@@ -1,9 +1,14 @@
# Makefile for rpm library.
+include $(top_srcdir)/rpm.am
+AM_CFLAGS = @RPMCFLAGS@
+
AM_CPPFLAGS = -I$(top_builddir) -I$(top_srcdir) -I$(top_builddir)/include/
AM_CPPFLAGS += @WITH_NSS_INCLUDE@
AM_CPPFLAGS += @WITH_BEECRYPT_INCLUDE@
+AM_CPPFLAGS += @WITH_OPENSSL_INCLUDE@
AM_CPPFLAGS += @WITH_POPT_INCLUDE@
+AM_CPPFLAGS += $(ZSTD_CFLAGS)
AM_CPPFLAGS += -I$(top_srcdir)/misc
AM_CPPFLAGS += -DRPMCONFIGDIR="\"@RPMCONFIGDIR@\""
AM_CPPFLAGS += -DLOCALSTATEDIR="\"$(localstatedir)\""
@@ -21,20 +26,26 @@ librpmio_la_SOURCES = \
if WITH_BEECRYPT
librpmio_la_SOURCES += digest_beecrypt.c
else
+if WITH_OPENSSL
+librpmio_la_SOURCES += digest_openssl.c
+else
librpmio_la_SOURCES += digest_nss.c
endif
+endif
-librpmio_la_LDFLAGS = -version-info 4:0:1
+librpmio_la_LDFLAGS = -version-info $(rpm_version_info)
librpmio_la_LIBADD = \
../misc/libmisc.la \
@WITH_NSS_LIB@ \
@WITH_BEECRYPT_LIB@ \
+ @WITH_OPENSSL_LIB@ \
@WITH_BZ2_LIB@ \
@WITH_ZLIB_LIB@ \
@WITH_LIBELF_LIB@ \
@WITH_POPT_LIB@ \
@WITH_LZMA_LIB@ \
+ $(ZSTD_LIBS) \
-lpthread
if WITH_INTERNAL_BEECRYPT
diff --git a/rpmio/argv.c b/rpmio/argv.c
index f061f03de..3508a9fc1 100644
--- a/rpmio/argv.c
+++ b/rpmio/argv.c
@@ -213,12 +213,32 @@ int argvSplit(ARGV_t * argvp, const char * str, const char * seps)
char *argvJoin(ARGV_const_t argv, const char *sep)
{
+ int argc = 0;
+ size_t argvlen = 0;
char *dest = NULL;
- char * const *arg;
- for (arg = argv; arg && *arg; arg++) {
- rstrscat(&dest, *arg, *(arg+1) ? sep : "", NULL);
- }
+ if (argv) {
+ ARGV_const_t arg;
+ for (arg = argv; *arg; arg++)
+ argvlen += strlen(*arg);
+ argc = arg - argv;
+ }
+
+ if (argc > 0) {
+ size_t seplen = (sep != NULL) ? strlen(sep) : 0;
+ char *p;
+
+ dest = xmalloc(argvlen + (seplen * (argc - 1)) + 1);
+
+ p = stpcpy(dest, argv[0]);
+ for (int i = 1; i < argc; i++) {
+ if (seplen)
+ p = stpcpy(p, sep);
+ p = stpcpy(p, argv[i]);
+ }
+ *p = '\0';
+ }
+
return dest;
}
diff --git a/rpmio/argv.h b/rpmio/argv.h
index d73a3c35f..602b1dc20 100644
--- a/rpmio/argv.h
+++ b/rpmio/argv.h
@@ -3,6 +3,8 @@
/** \ingroup rpmargv
* \file rpmio/argv.h
+ *
+ * Argument Manipulation API.
*/
#include <stdio.h>
@@ -149,7 +151,7 @@ typedef rpmFlags argvFlags;
/** \ingroup rpmargv
* Split a string into an argv array.
* @param str string arg to split
- * @param seps seperator characters
+ * @param seps separator characters
* @param flags flags to control behavior
* @return argv array
*/
@@ -159,7 +161,7 @@ ARGV_t argvSplitString(const char * str, const char * seps, argvFlags flags);
* Split a string into an argv array.
* @retval *argvp argv array
* @param str string arg to split
- * @param seps seperator characters
+ * @param seps separator characters
* @return 0 always
*/
int argvSplit(ARGV_t * argvp, const char * str, const char * seps);
@@ -167,7 +169,7 @@ int argvSplit(ARGV_t * argvp, const char * str, const char * seps);
/** \ingroup rpmargv
* Join an argv array into a string.
* @param *argv argv array to join
- * @param sep seperator string to use
+ * @param sep separator string to use
* @return malloc'ed string
*/
char *argvJoin(ARGV_const_t argv, const char *sep);
diff --git a/rpmio/base64.c b/rpmio/base64.c
index 60e67d442..4424aabbd 100644
--- a/rpmio/base64.c
+++ b/rpmio/base64.c
@@ -104,7 +104,7 @@ static int base64_decode_value(unsigned char value_in)
{
static const int decoding[] = {62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-2,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51};
value_in -= 43;
- if (value_in > sizeof(decoding)/sizeof(int))
+ if (value_in >= sizeof(decoding)/sizeof(int))
return -1;
return decoding[value_in];
}
diff --git a/rpmio/digest.c b/rpmio/digest.c
index c1f73b331..1f5e1667b 100644
--- a/rpmio/digest.c
+++ b/rpmio/digest.c
@@ -8,14 +8,28 @@
#include "debug.h"
-#define DIGESTS_MAX 11
+#define DIGESTS_MAX 12
struct rpmDigestBundle_s {
- int index_min; /*!< Smallest index of active digest */
int index_max; /*!< Largest index of active digest */
off_t nbytes; /*!< Length of total input data */
- DIGEST_CTX digests[DIGESTS_MAX]; /*!< Digest contexts indexed by algo */
+ DIGEST_CTX digests[DIGESTS_MAX]; /*!< Digest contexts identified by id */
+ int ids[DIGESTS_MAX]; /*!< Digest ID (arbitrary non-zero) */
};
+static int findID(rpmDigestBundle bundle, int id)
+{
+ int ix = -1;
+ if (bundle) {
+ for (int i = 0; i < DIGESTS_MAX; i++) {
+ if (bundle->ids[i] == id) {
+ ix = i;
+ break;
+ }
+ }
+ }
+ return ix;
+}
+
rpmDigestBundle rpmDigestBundleNew(void)
{
rpmDigestBundle bundle = xcalloc(1, sizeof(*bundle));
@@ -25,7 +39,7 @@ rpmDigestBundle rpmDigestBundleNew(void)
rpmDigestBundle rpmDigestBundleFree(rpmDigestBundle bundle)
{
if (bundle) {
- for (int i = bundle->index_min; i <= bundle->index_max ; i++) {
+ for (int i = 0; i <= bundle->index_max ; i++) {
if (bundle->digests[i] == NULL)
continue;
rpmDigestFinal(bundle->digests[i], NULL, NULL, 0);
@@ -40,56 +54,58 @@ rpmDigestBundle rpmDigestBundleFree(rpmDigestBundle bundle)
int rpmDigestBundleAdd(rpmDigestBundle bundle, int algo,
rpmDigestFlags flags)
{
- DIGEST_CTX ctx = NULL;
- if (bundle && algo > 0 && algo < DIGESTS_MAX) {
- if (bundle->digests[algo] == NULL) {
- ctx = rpmDigestInit(algo, flags);
- if (ctx) {
- bundle->digests[algo] = ctx;
- if (algo < bundle->index_min) {
- bundle->index_min = algo;
- }
- if (algo > bundle->index_max) {
- bundle->index_max = algo;
- }
+ return rpmDigestBundleAddID(bundle, algo, algo, flags);
+}
+
+int rpmDigestBundleAddID(rpmDigestBundle bundle, int algo, int id,
+ rpmDigestFlags flags)
+{
+ int rc = -1;
+ if (id > 0 && findID(bundle, id) < 0) {
+ int ix = findID(bundle, 0); /* Find first free slot */
+ if (ix >= 0) {
+ bundle->digests[ix] = rpmDigestInit(algo, flags);
+ if (bundle->digests[ix]) {
+ bundle->ids[ix]= id;
+ if (ix > bundle->index_max)
+ bundle->index_max = ix;
+ rc = 0;
}
}
}
- return (ctx != NULL);
+ return rc;
}
-
int rpmDigestBundleUpdate(rpmDigestBundle bundle, const void *data, size_t len)
{
int rc = 0;
if (bundle && data && len > 0) {
- for (int i = bundle->index_min; i <= bundle->index_max; i++) {
- DIGEST_CTX ctx = bundle->digests[i];
- if (ctx == NULL)
- continue;
- rc += rpmDigestUpdate(ctx, data, len);
+ for (int i = 0; i <= bundle->index_max; i++) {
+ if (bundle->ids[i] > 0)
+ rc += rpmDigestUpdate(bundle->digests[i], data, len);
}
bundle->nbytes += len;
}
return rc;
}
-int rpmDigestBundleFinal(rpmDigestBundle bundle,
- int algo, void ** datap, size_t * lenp, int asAscii)
+int rpmDigestBundleFinal(rpmDigestBundle bundle, int id,
+ void ** datap, size_t * lenp, int asAscii)
{
int rc = 0;
- if (bundle && algo >= bundle->index_min && algo <= bundle->index_max) {
- rc = rpmDigestFinal(bundle->digests[algo], datap, lenp, asAscii);
- bundle->digests[algo] = NULL;
+ int ix = findID(bundle, id);
+
+ if (ix >= 0) {
+ rc = rpmDigestFinal(bundle->digests[ix], datap, lenp, asAscii);
+ bundle->digests[ix] = NULL;
+ bundle->ids[ix] = 0;
}
return rc;
}
-DIGEST_CTX rpmDigestBundleDupCtx(rpmDigestBundle bundle, int algo)
+DIGEST_CTX rpmDigestBundleDupCtx(rpmDigestBundle bundle, int id)
{
- DIGEST_CTX dup = NULL;
- if (bundle && algo >= bundle->index_min && algo <= bundle->index_max) {
- dup = rpmDigestDup(bundle->digests[algo]);
- }
+ int ix = findID(bundle, id);
+ DIGEST_CTX dup = (ix >= 0) ? rpmDigestDup(bundle->digests[ix]) : NULL;
return dup;
}
diff --git a/rpmio/digest.h b/rpmio/digest.h
index f10f1c871..9e0cde3b9 100644
--- a/rpmio/digest.h
+++ b/rpmio/digest.h
@@ -5,8 +5,7 @@
typedef struct pgpDigAlg_s * pgpDigAlg;
-typedef int (*setmpifunc)(pgpDigAlg digp,
- int num, const uint8_t *p, const uint8_t *pend);
+typedef int (*setmpifunc)(pgpDigAlg digp, int num, const uint8_t *p);
typedef int (*verifyfunc)(pgpDigAlg pgpkey, pgpDigAlg pgpsig,
uint8_t *hash, size_t hashlen, int hash_algo);
typedef void (*freefunc)(pgpDigAlg digp);
@@ -28,7 +27,7 @@ struct pgpDigParams_s {
uint8_t tag;
uint8_t version; /*!< version number. */
- pgpTime_t time; /*!< time that the key was created. */
+ uint32_t time; /*!< key/signature creation time. */
uint8_t pubkey_algo; /*!< public key algorithm. */
uint8_t hash_algo;
diff --git a/rpmio/digest_beecrypt.c b/rpmio/digest_beecrypt.c
index 7ff706034..597027e25 100644
--- a/rpmio/digest_beecrypt.c
+++ b/rpmio/digest_beecrypt.c
@@ -1,17 +1,17 @@
#include "system.h"
-#include <beecrypt.h>
-#include <dsa.h>
-#include <endianness.h>
-#include <md5.h>
-#include <mp.h>
-#include <rsa.h>
-#include <rsapk.h>
-#include <sha1.h>
+#include <beecrypt/beecrypt.h>
+#include <beecrypt/dsa.h>
+#include <beecrypt/endianness.h>
+#include <beecrypt/md5.h>
+#include <beecrypt/mp.h>
+#include <beecrypt/rsa.h>
+#include <beecrypt/rsapk.h>
+#include <beecrypt/sha1.h>
#if HAVE_BEECRYPT_API_H
-#include <sha256.h>
-#include <sha384.h>
-#include <sha512.h>
+#include <beecrypt/sha256.h>
+#include <beecrypt/sha384.h>
+#include <beecrypt/sha512.h>
#endif
#include <rpm/rpmpgp.h>
@@ -198,66 +198,6 @@ int rpmDigestFinal(DIGEST_CTX ctx, void ** datap, size_t *lenp, int asAscii)
return 0;
}
-/**************************** helpers ************************************/
-
-static inline char * pgpHexCvt(char *t, const byte *s, int nbytes)
-{
- static char hex[] = "0123456789abcdef";
- while (nbytes-- > 0) {
- unsigned int i;
- i = *s++;
- *t++ = hex[ (i >> 4) & 0xf ];
- *t++ = hex[ (i ) & 0xf ];
- }
- *t = '\0';
- return t;
-}
-
-static const char * pgpMpiHex(const byte *p, const byte *pend)
-{
- static char prbuf[2048];
- char *t = prbuf;
- int nbytes = pgpMpiLen(p) - 2;
- if (nbytes > 1024 || nbytes > pend - (p + 2))
- return NULL;
- t = pgpHexCvt(t, p+2, nbytes);
- return prbuf;
-}
-
-static int pgpHexSet(int lbits, mpnumber * mpn, const byte * p, const byte * pend)
-{
- unsigned int mbits = pgpMpiBits(p);
- unsigned int nbits;
- unsigned int nbytes;
- char *t;
- unsigned int ix;
-
- nbits = (lbits > mbits ? lbits : mbits);
- nbytes = ((nbits + 7) >> 3);
- t = xmalloc(2*nbytes+1);
- ix = 2 * ((nbits - mbits) >> 3);
-
- if (ix > 0) memset(t, (int)'0', ix);
- strcpy(t+ix, pgpMpiHex(p, pend));
- (void) mpnsethex(mpn, t);
- t = _free(t);
- return 0;
-}
-
-static void pgpFreeSigRSADSA(pgpDigAlg sa)
-{
- if (sa->data)
- free(sa->data);
- sa->data = 0;
-}
-
-static void pgpFreeKeyRSADSA(pgpDigAlg sa)
-{
- if (sa->data)
- free(sa->data);
- sa->data = 0;
-}
-
/****************************** RSA **************************************/
@@ -267,45 +207,73 @@ struct pgpDigSigRSA_s {
struct pgpDigKeyRSA_s {
rsapk rsa_pk;
+ int nbytes;
};
-static int pgpSetSigMpiRSA(pgpDigAlg pgpsig, int num,
- const uint8_t *p, const uint8_t *pend)
+static int pgpSetSigMpiRSA(pgpDigAlg pgpsig, int num, const uint8_t *p)
{
struct pgpDigSigRSA_s *sig = pgpsig->data;
+ int mlen = pgpMpiLen(p) - 2;
int rc = 1;
+ if (!sig)
+ sig = pgpsig->data = xcalloc(1, sizeof(*sig));
+
switch (num) {
case 0:
- sig = pgpsig->data = xcalloc(1, sizeof(*sig));
- (void) mpnsethex(&sig->c, pgpMpiHex(p, pend));
- rc = 0;
+ if (!mpnsetbin(&sig->c, p + 2, mlen))
+ rc = 0;
break;
}
return rc;
}
-static int pgpSetKeyMpiRSA(pgpDigAlg pgpkey, int num,
- const uint8_t *p, const uint8_t *pend)
+static int pgpSetKeyMpiRSA(pgpDigAlg pgpkey, int num, const uint8_t *p)
{
struct pgpDigKeyRSA_s *key = pgpkey->data;
+ int mlen = pgpMpiLen(p) - 2;
int rc = 1;
if (!key)
key = pgpkey->data = xcalloc(1, sizeof(*key));
+
switch (num) {
case 0:
- (void) mpbsethex(&key->rsa_pk.n, pgpMpiHex(p, pend));
- rc = 0;
+ key->nbytes = mlen;
+ if (!mpbsetbin(&key->rsa_pk.n, p + 2, mlen))
+ rc = 0;
break;
case 1:
- (void) mpnsethex(&key->rsa_pk.e, pgpMpiHex(p, pend));
- rc = 0;
+ if (!mpnsetbin(&key->rsa_pk.e, p + 2, mlen))
+ rc = 0;
break;
}
return rc;
}
+static int pkcs1pad(mpnumber *rsahm, int nbytes, const char *prefix, uint8_t *hash, size_t hashlen)
+{
+ int datalen = strlen(prefix) / 2 + hashlen;
+ byte *buf, *bp;
+ int rc = 1;
+
+ if (nbytes < 4 + datalen)
+ return 1;
+ buf = xmalloc(nbytes);
+ memset(buf, 0xff, nbytes);
+ buf[0] = 0x00;
+ buf[1] = 0x01;
+ bp = buf + nbytes - datalen;
+ bp[-1] = 0;
+ for (; *prefix; prefix += 2)
+ *bp++ = (rnibble(prefix[0]) << 4) | rnibble(prefix[1]);
+ memcpy(bp, hash, hashlen);
+ if (!mpnsetbin(rsahm, buf, nbytes))
+ rc = 0;
+ buf = _free(buf);
+ return rc;
+}
+
static int pgpVerifySigRSA(pgpDigAlg pgpkey, pgpDigAlg pgpsig, uint8_t *hash, size_t hashlen, int hash_algo)
{
struct pgpDigKeyRSA_s *key = pgpkey->data;
@@ -340,28 +308,10 @@ static int pgpVerifySigRSA(pgpDigAlg pgpkey, pgpDigAlg pgpsig, uint8_t *hash, si
return 1;
}
- /* Generate RSA modulus parameter. */
- { unsigned int nbits = MP_WORDS_TO_BITS(sig->c.size);
- unsigned int nb = (nbits + 7) >> 3;
- byte *buf, *bp;
-
- if (nb < 3)
- return 1;
- buf = xmalloc(nb);
- memset(buf, 0xff, nb);
- buf[0] = 0x00;
- buf[1] = 0x01;
- bp = buf + nb - strlen(prefix)/2 - hashlen - 1;
- if (bp < buf)
- return 1;
- *bp++ = 0;
- for (; *prefix; prefix += 2)
- *bp++ = (rnibble(prefix[0]) << 4) | rnibble(prefix[1]);
- memcpy(bp, hash, hashlen);
- mpnzero(&rsahm);
- (void) mpnsetbin(&rsahm, buf, nb);
- buf = _free(buf);
- }
+ memset(&rsahm, 0, sizeof(rsahm));
+ if (pkcs1pad(&rsahm, key->nbytes, prefix, hash, hashlen) != 0)
+ return 1;
+
#if HAVE_BEECRYPT_API_H
rc = rsavrfy(&key->rsa_pk.n, &key->rsa_pk.e, &sig->c, &rsahm) == 1 ? 0 : 1;
#else
@@ -371,6 +321,25 @@ static int pgpVerifySigRSA(pgpDigAlg pgpkey, pgpDigAlg pgpsig, uint8_t *hash, si
return rc;
}
+static void pgpFreeSigRSA(pgpDigAlg pgpsig)
+{
+ struct pgpDigSigRSA_s *sig = pgpsig->data;
+ if (sig) {
+ mpnfree(&sig->c);
+ pgpsig->data = _free(sig);
+ }
+}
+
+static void pgpFreeKeyRSA(pgpDigAlg pgpkey)
+{
+ struct pgpDigKeyRSA_s *key = pgpkey->data;
+ if (key) {
+ mpbfree(&key->rsa_pk.n);
+ mpnfree(&key->rsa_pk.e);
+ pgpkey->data = _free(key);
+ }
+}
+
/****************************** DSA **************************************/
@@ -384,30 +353,35 @@ struct pgpDigKeyDSA_s {
mpbarrett q;
mpnumber g;
mpnumber y;
+ int qbytes;
};
-static int pgpSetSigMpiDSA(pgpDigAlg pgpsig, int num,
- const uint8_t *p, const uint8_t *pend)
+static int pgpSetSigMpiDSA(pgpDigAlg pgpsig, int num, const uint8_t *p)
{
struct pgpDigSigDSA_s *sig = pgpsig->data;
+ int mlen = pgpMpiLen(p) - 2;
int rc = 1;
+ if (!sig)
+ sig = pgpsig->data = xcalloc(1, sizeof(*sig));
+
switch (num) {
case 0:
- sig = pgpsig->data = xcalloc(1, sizeof(*sig));
- rc = pgpHexSet(160, &sig->r, p, pend);
+ if (!mpnsetbin(&sig->r, p + 2, mlen))
+ rc = 0;
break;
case 1:
- rc = pgpHexSet(160, &sig->s, p, pend);
+ if (!mpnsetbin(&sig->s, p + 2, mlen))
+ rc = 0;
break;
}
return rc;
}
-static int pgpSetKeyMpiDSA(pgpDigAlg pgpkey, int num,
- const uint8_t *p, const uint8_t *pend)
+static int pgpSetKeyMpiDSA(pgpDigAlg pgpkey, int num, const uint8_t *p)
{
struct pgpDigKeyDSA_s *key = pgpkey->data;
+ int mlen = pgpMpiLen(p) - 2;
int rc = 1;
if (!key)
@@ -415,20 +389,21 @@ static int pgpSetKeyMpiDSA(pgpDigAlg pgpkey, int num,
switch (num) {
case 0:
- mpbsethex(&key->p, pgpMpiHex(p, pend));
- rc = 0;
+ if (!mpbsetbin(&key->p, p + 2, mlen))
+ rc = 0;
break;
case 1:
- mpbsethex(&key->q, pgpMpiHex(p, pend));
- rc = 0;
+ key->qbytes = mlen;
+ if (!mpbsetbin(&key->q, p + 2, mlen))
+ rc = 0;
break;
case 2:
- mpnsethex(&key->g, pgpMpiHex(p, pend));
- rc = 0;
+ if (!mpnsetbin(&key->g, p + 2, mlen))
+ rc = 0;
break;
case 3:
- mpnsethex(&key->y, pgpMpiHex(p, pend));
- rc = 0;
+ if (!mpnsetbin(&key->y, p + 2, mlen))
+ rc = 0;
break;
}
return rc;
@@ -441,17 +416,41 @@ static int pgpVerifySigDSA(pgpDigAlg pgpkey, pgpDigAlg pgpsig, uint8_t *hash, si
mpnumber hm;
int rc = 1;
- if (sig && key) {
+ if (sig && key && hashlen >= key->qbytes) {
mpnzero(&hm);
- mpnsetbin(&hm, hash, hashlen);
+ mpnsetbin(&hm, hash, key->qbytes);
rc = dsavrfy(&key->p, &key->q, &key->g, &hm, &key->y, &sig->r, &sig->s) == 1 ? 0 : 1;
mpnfree(&hm);
}
return rc;
}
-static int pgpSetMpiNULL(pgpDigAlg pgpkey, int num,
- const uint8_t *p, const uint8_t *pend)
+static void pgpFreeSigDSA(pgpDigAlg pgpsig)
+{
+ struct pgpDigSigDSA_s *sig = pgpsig->data;
+ if (sig) {
+ mpnfree(&sig->r);
+ mpnfree(&sig->s);
+ pgpsig->data = _free(sig);
+ }
+}
+
+static void pgpFreeKeyDSA(pgpDigAlg pgpkey)
+{
+ struct pgpDigKeyDSA_s *key = pgpkey->data;
+ if (key) {
+ mpbfree(&key->p);
+ mpbfree(&key->q);
+ mpnfree(&key->g);
+ mpnfree(&key->y);
+ pgpkey->data = _free(key);
+ }
+}
+
+
+/****************************** NULL **************************************/
+
+static int pgpSetMpiNULL(pgpDigAlg pgpkey, int num, const uint8_t *p)
{
return 1;
}
@@ -469,12 +468,12 @@ pgpDigAlg pgpPubkeyNew(int algo)
switch (algo) {
case PGPPUBKEYALGO_RSA:
ka->setmpi = pgpSetKeyMpiRSA;
- ka->free = pgpFreeKeyRSADSA;
+ ka->free = pgpFreeKeyRSA;
ka->mpis = 2;
break;
case PGPPUBKEYALGO_DSA:
ka->setmpi = pgpSetKeyMpiDSA;
- ka->free = pgpFreeKeyRSADSA;
+ ka->free = pgpFreeKeyDSA;
ka->mpis = 4;
break;
default:
@@ -495,13 +494,13 @@ pgpDigAlg pgpSignatureNew(int algo)
switch (algo) {
case PGPPUBKEYALGO_RSA:
sa->setmpi = pgpSetSigMpiRSA;
- sa->free = pgpFreeSigRSADSA;
+ sa->free = pgpFreeSigRSA;
sa->verify = pgpVerifySigRSA;
sa->mpis = 1;
break;
case PGPPUBKEYALGO_DSA:
sa->setmpi = pgpSetSigMpiDSA;
- sa->free = pgpFreeSigRSADSA;
+ sa->free = pgpFreeSigDSA;
sa->verify = pgpVerifySigDSA;
sa->mpis = 2;
break;
diff --git a/rpmio/digest_nss.c b/rpmio/digest_nss.c
index 8a948219d..992d9acf6 100644
--- a/rpmio/digest_nss.c
+++ b/rpmio/digest_nss.c
@@ -53,6 +53,9 @@ int rpmInitCrypto(void)
* a private context if possible.
*/
if (!_crypto_initialized) {
+ /* NSPR sets SIGPIPE to ignore behind our back, save and restore */
+ struct sigaction oact;
+ sigaction(SIGPIPE, NULL, &oact);
#if HAVE_NSS_INITCONTEXT
PRUint32 flags = (NSS_INIT_READONLY|NSS_INIT_NOCERTDB|
NSS_INIT_NOMODDB|NSS_INIT_FORCEOPEN|
@@ -62,10 +65,12 @@ int rpmInitCrypto(void)
#else
if (NSS_NoDB_Init(NULL) != SECSuccess) {
#endif
+ rpmlog(RPMLOG_ERR, _("Failed to initialize NSS library\n"));
rc = -1;
} else {
_crypto_initialized = 1;
}
+ sigaction(SIGPIPE, &oact, NULL);
}
/* Register one post-fork handler per process */
@@ -223,8 +228,7 @@ static SECOidTag getHashAlg(unsigned int hashalgo)
return SEC_OID_UNKNOWN;
}
-static int pgpMpiSet(unsigned int lbits, uint8_t *dest,
- const uint8_t * p, const uint8_t * pend)
+static int pgpMpiSet(unsigned int lbits, uint8_t *dest, const uint8_t * p)
{
unsigned int mbits = pgpMpiBits(p);
unsigned int nbits;
@@ -232,9 +236,6 @@ static int pgpMpiSet(unsigned int lbits, uint8_t *dest,
uint8_t *t = dest;
unsigned int ix;
- if ((p + ((mbits+7) >> 3)) > pend)
- return 1;
-
if (mbits > lbits)
return 1;
@@ -249,14 +250,10 @@ static int pgpMpiSet(unsigned int lbits, uint8_t *dest,
return 0;
}
-static SECItem *pgpMpiItem(PRArenaPool *arena, SECItem *item,
- const uint8_t *p, const uint8_t *pend)
+static SECItem *pgpMpiItem(PRArenaPool *arena, SECItem *item, const uint8_t *p)
{
size_t nbytes = pgpMpiLen(p)-2;
- if (p + nbytes + 2 > pend)
- return NULL;
-
if (item == NULL) {
if ((item=SECITEM_AllocItem(arena, item, nbytes)) == NULL)
return item;
@@ -312,25 +309,28 @@ static SECKEYPublicKey *pgpNewPublicKey(KeyType type)
#define DSA1_Q_BITS DSA_Q_BITS
#endif
-static int pgpSetSigMpiDSA(pgpDigAlg pgpsig, int num,
- const uint8_t *p, const uint8_t *pend)
+static int pgpSetSigMpiDSA(pgpDigAlg pgpsig, int num, const uint8_t *p)
{
SECItem *sig = pgpsig->data;
- int lbits = DSA1_Q_BITS;
+ unsigned int qbits = DSA1_Q_BITS;
+ unsigned int subprlen = DSA1_SUBPRIME_LEN;
+ unsigned int siglen = DSA1_SIGNATURE_LEN;
int rc = 1; /* assume failure */
switch (num) {
case 0:
- sig = pgpsig->data = SECITEM_AllocItem(NULL, NULL, DSA1_SIGNATURE_LEN);
+ sig = pgpsig->data = SECITEM_AllocItem(NULL, NULL, siglen);
if (sig) {
- memset(sig->data, 0, DSA1_SIGNATURE_LEN);
- rc = pgpMpiSet(lbits, sig->data, p, pend);
+ memset(sig->data, 0, siglen);
+ rc = pgpMpiSet(qbits, sig->data, p);
}
break;
case 1:
- if (sig && pgpMpiSet(lbits, sig->data+DSA1_SUBPRIME_LEN, p, pend) == 0) {
+ if (sig && pgpMpiSet(qbits, sig->data+subprlen, p) == 0) {
SECItem *signew = SECITEM_AllocItem(NULL, NULL, 0);
- if (signew && DSAU_EncodeDerSig(signew, sig) == SECSuccess) {
+ if (signew == NULL)
+ break;
+ if (DSAU_EncodeDerSigWithLen(signew, sig, siglen) == SECSuccess) {
SECITEM_FreeItem(sig, PR_TRUE);
pgpsig->data = signew;
rc = 0;
@@ -342,8 +342,7 @@ static int pgpSetSigMpiDSA(pgpDigAlg pgpsig, int num,
return rc;
}
-static int pgpSetKeyMpiDSA(pgpDigAlg pgpkey, int num,
- const uint8_t *p, const uint8_t *pend)
+static int pgpSetKeyMpiDSA(pgpDigAlg pgpkey, int num, const uint8_t *p)
{
SECItem *mpi = NULL;
SECKEYPublicKey *key = pgpkey->data;
@@ -354,16 +353,16 @@ static int pgpSetKeyMpiDSA(pgpDigAlg pgpkey, int num,
if (key) {
switch (num) {
case 0:
- mpi = pgpMpiItem(key->arena, &key->u.dsa.params.prime, p, pend);
+ mpi = pgpMpiItem(key->arena, &key->u.dsa.params.prime, p);
break;
case 1:
- mpi = pgpMpiItem(key->arena, &key->u.dsa.params.subPrime, p, pend);
+ mpi = pgpMpiItem(key->arena, &key->u.dsa.params.subPrime, p);
break;
case 2:
- mpi = pgpMpiItem(key->arena, &key->u.dsa.params.base, p, pend);
+ mpi = pgpMpiItem(key->arena, &key->u.dsa.params.base, p);
break;
case 3:
- mpi = pgpMpiItem(key->arena, &key->u.dsa.publicValue, p, pend);
+ mpi = pgpMpiItem(key->arena, &key->u.dsa.publicValue, p);
break;
}
}
@@ -388,21 +387,19 @@ static int pgpVerifySigDSA(pgpDigAlg pgpkey, pgpDigAlg pgpsig,
return (rc != SECSuccess);
}
-static int pgpSetSigMpiRSA(pgpDigAlg pgpsig, int num,
- const uint8_t *p, const uint8_t *pend)
+static int pgpSetSigMpiRSA(pgpDigAlg pgpsig, int num, const uint8_t *p)
{
SECItem *sigitem = NULL;
if (num == 0) {
- sigitem = pgpMpiItem(NULL, pgpsig->data, p, pend);
+ sigitem = pgpMpiItem(NULL, pgpsig->data, p);
if (sigitem)
pgpsig->data = sigitem;
}
return (sigitem == NULL);
}
-static int pgpSetKeyMpiRSA(pgpDigAlg pgpkey, int num,
- const uint8_t *p, const uint8_t *pend)
+static int pgpSetKeyMpiRSA(pgpDigAlg pgpkey, int num, const uint8_t *p)
{
SECItem *kitem = NULL;
SECKEYPublicKey *key = pgpkey->data;
@@ -413,10 +410,10 @@ static int pgpSetKeyMpiRSA(pgpDigAlg pgpkey, int num,
if (key) {
switch (num) {
case 0:
- kitem = pgpMpiItem(key->arena, &key->u.rsa.modulus, p, pend);
+ kitem = pgpMpiItem(key->arena, &key->u.rsa.modulus, p);
break;
case 1:
- kitem = pgpMpiItem(key->arena, &key->u.rsa.publicExponent, p, pend);
+ kitem = pgpMpiItem(key->arena, &key->u.rsa.publicExponent, p);
break;
}
}
@@ -471,8 +468,7 @@ static void pgpFreeKeyRSADSA(pgpDigAlg ka)
ka->data = NULL;
}
-static int pgpSetMpiNULL(pgpDigAlg pgpkey, int num,
- const uint8_t *p, const uint8_t *pend)
+static int pgpSetMpiNULL(pgpDigAlg pgpkey, int num, const uint8_t *p)
{
return 1;
}
diff --git a/rpmio/digest_openssl.c b/rpmio/digest_openssl.c
new file mode 100644
index 000000000..18e52a724
--- /dev/null
+++ b/rpmio/digest_openssl.c
@@ -0,0 +1,839 @@
+#include "system.h"
+
+#include <openssl/evp.h>
+#include <openssl/rsa.h>
+#include <openssl/dsa.h>
+#include <rpm/rpmpgp.h>
+
+#include "rpmio/digest.h"
+
+
+/* Compatibility functions for OpenSSL 1.0.2 */
+
+#ifndef HAVE_EVP_MD_CTX_NEW
+# define EVP_MD_CTX_new EVP_MD_CTX_create
+# define EVP_MD_CTX_free EVP_MD_CTX_destroy
+#endif
+
+#ifndef HAVE_RSA_SET0_KEY
+int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d);
+int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d)
+{
+ if (!r) return 0;
+
+ if (n) {
+ r->n = n;
+ }
+
+ if (e) {
+ r->e = e;
+ }
+
+ if (d) {
+ r->d = d;
+ }
+
+ return 1;
+}
+#endif /* HAVE_RSA_SET0_KEY */
+
+#ifndef HAVE_DSA_SET0_KEY
+int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key);
+
+int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key)
+{
+ if (!d) return 0;
+
+ if (pub_key) {
+ d->pub_key = pub_key;
+ }
+
+ if (priv_key) {
+ d->priv_key = priv_key;
+ }
+
+ return 1;
+}
+#endif /* HAVE_DSA_SET0_KEY */
+
+#ifndef HAVE_DSA_SET0_PQG
+int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g);
+
+int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g)
+{
+ if (!d) return 0;
+
+ if (p) {
+ d->p = p;
+ }
+
+ if (q) {
+ d->q = q;
+ }
+
+ if (g) {
+ d->g = g;
+ }
+
+ return 1;
+}
+#endif /* HAVE_DSA_SET0_PQG */
+
+#ifndef HAVE_DSA_SIG_SET0
+int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s);
+
+int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s)
+{
+ if (!sig) return 0;
+
+ if (r) {
+ sig->r = r;
+ }
+
+ if (s) {
+ sig->s = s;
+ }
+
+ return 1;
+}
+#endif /* HAVE_DSA_SIG_SET0 */
+
+#ifndef HAVE_BN2BINPAD
+static int BN_bn2binpad(const BIGNUM *a, unsigned char *to, int tolen)
+{
+ int i;
+
+ i = BN_num_bytes(a);
+ if (tolen < i)
+ return -1;
+
+ /* Add leading zeroes if necessary */
+ if (tolen > i) {
+ memset(to, 0, tolen - i);
+ to += tolen - i;
+ }
+
+ BN_bn2bin(a, to);
+
+ return tolen;
+}
+#endif /* HAVE_BN2BINPAD */
+
+struct DIGEST_CTX_s {
+ rpmDigestFlags flags; /*!< Bit(s) to control digest operation. */
+ int algo; /*!< Used hash algorithm */
+
+ EVP_MD_CTX *md_ctx; /* Digest context (opaque) */
+
+};
+
+/**************************** init ************************************/
+
+int rpmInitCrypto(void) {
+ return 0;
+}
+
+int rpmFreeCrypto(void) {
+ return 0;
+}
+
+/**************************** digest ************************************/
+
+DIGEST_CTX rpmDigestDup(DIGEST_CTX octx)
+{
+ if (!octx) return NULL;
+
+ DIGEST_CTX nctx = NULL;
+ nctx = xcalloc(1, sizeof(*nctx));
+
+ nctx->flags = octx->flags;
+ nctx->algo = octx->algo;
+ nctx->md_ctx = EVP_MD_CTX_new();
+ if (!nctx->md_ctx) {
+ free(nctx);
+ return NULL;
+ }
+
+ if (!EVP_MD_CTX_copy(nctx->md_ctx, octx->md_ctx)) {
+ free(nctx);
+ return NULL;
+ }
+
+ return nctx;
+}
+
+static const EVP_MD *getEVPMD(int hashalgo)
+{
+ switch (hashalgo) {
+
+ case PGPHASHALGO_MD5:
+ return EVP_md5();
+
+ case PGPHASHALGO_SHA1:
+ return EVP_sha1();
+
+ case PGPHASHALGO_RIPEMD160:
+ return EVP_ripemd160();
+
+ case PGPHASHALGO_MD2:
+ return EVP_md2();
+
+ case PGPHASHALGO_SHA256:
+ return EVP_sha256();
+
+ case PGPHASHALGO_SHA384:
+ return EVP_sha384();
+
+ case PGPHASHALGO_SHA512:
+ return EVP_sha512();
+
+ case PGPHASHALGO_SHA224:
+ return EVP_sha224();
+
+ default:
+ return EVP_md_null();
+ }
+}
+
+size_t rpmDigestLength(int hashalgo)
+{
+ return EVP_MD_size(getEVPMD(hashalgo));
+}
+
+DIGEST_CTX rpmDigestInit(int hashalgo, rpmDigestFlags flags)
+{
+ DIGEST_CTX ctx = xcalloc(1, sizeof(*ctx));
+
+ ctx->md_ctx = EVP_MD_CTX_new();
+ if (!ctx->md_ctx) {
+ free(ctx);
+ return NULL;
+ }
+
+ const EVP_MD *md = getEVPMD(hashalgo);
+ if (md == EVP_md_null()) {
+ free(ctx->md_ctx);
+ free(ctx);
+ return NULL;
+ }
+
+ ctx->algo = hashalgo;
+ ctx->flags = flags;
+ if (!EVP_DigestInit_ex(ctx->md_ctx, md, NULL)) {
+ free(ctx->md_ctx);
+ free(ctx);
+ return NULL;
+ }
+
+ return ctx;
+}
+
+int rpmDigestUpdate(DIGEST_CTX ctx, const void *data, size_t len)
+{
+ if (ctx == NULL) return -1;
+
+ EVP_DigestUpdate(ctx->md_ctx, data, len);
+
+ return 0;
+}
+
+int rpmDigestFinal(DIGEST_CTX ctx, void ** datap, size_t *lenp, int asAscii)
+{
+ int ret;
+ unsigned char *digest = NULL;
+ unsigned int digestlen;
+
+ if (ctx == NULL) return -1;
+
+ digestlen = EVP_MD_CTX_size(ctx->md_ctx);
+ digest = xcalloc(digestlen, sizeof(*digest));
+
+ ret = EVP_DigestFinal_ex(ctx->md_ctx, digest, &digestlen);
+ if (ret != 1) goto done;
+
+ if (!asAscii) {
+ /* Raw data requested */
+ if (lenp) *lenp = digestlen;
+ if (datap) {
+ *datap = digest;
+ digest = NULL;
+ }
+ }
+
+ else {
+ /* ASCII requested */
+ if (lenp) *lenp = (2*digestlen) + 1;
+ if (datap) {
+ const uint8_t * s = (const uint8_t *) digest;
+ *datap = pgpHexStr(s, digestlen);
+ }
+ }
+
+ ret = 1;
+
+done:
+ if (digest) {
+ /* Zero the digest, just in case it's sensitive */
+ memset(digest, 0, digestlen);
+ free(digest);
+ }
+
+ EVP_MD_CTX_free(ctx->md_ctx);
+ free(ctx);
+
+ if (ret != 1) {
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/****************************** RSA **************************************/
+
+/* Key */
+
+struct pgpDigKeyRSA_s {
+ size_t nbytes; /* Size of modulus */
+
+ BIGNUM *n; /* Common Modulus */
+ BIGNUM *e; /* Public Exponent */
+
+ EVP_PKEY *evp_pkey; /* Fully constructed key */
+};
+
+static int constructRSASigningKey(struct pgpDigKeyRSA_s *key)
+{
+ if (key->evp_pkey) {
+ /* We've already constructed it, so just reuse it */
+ return 1;
+ }
+
+ /* Create the RSA key */
+ RSA *rsa = RSA_new();
+ if (!rsa) return 0;
+
+ if (!RSA_set0_key(rsa, key->n, key->e, NULL)) {
+ RSA_free(rsa);
+ return 0;
+ }
+
+ /* Create an EVP_PKEY container to abstract the key-type. */
+ key->evp_pkey = EVP_PKEY_new();
+ if (!key->evp_pkey) {
+ RSA_free(rsa);
+ return 0;
+ }
+
+ /* Assign the RSA key to the EVP_PKEY structure.
+ This will take over memory management of the RSA key */
+ if (!EVP_PKEY_assign_RSA(key->evp_pkey, rsa)) {
+ EVP_PKEY_free(key->evp_pkey);
+ key->evp_pkey = NULL;
+ RSA_free(rsa);
+ }
+
+ return 1;
+}
+
+static int pgpSetKeyMpiRSA(pgpDigAlg pgpkey, int num, const uint8_t *p)
+{
+ size_t mlen = pgpMpiLen(p) - 2;
+ struct pgpDigKeyRSA_s *key = pgpkey->data;
+
+ if (!key) {
+ key = pgpkey->data = xcalloc(1, sizeof(*key));
+ }
+
+ switch (num) {
+ case 0:
+ /* Modulus */
+ if (key->n) {
+ /* This should only ever happen once per key */
+ return 1;
+ }
+
+ key->nbytes = mlen;
+ /* Create a BIGNUM from the pointer.
+ Note: this assumes big-endian data as required by PGP */
+ key->n = BN_bin2bn(p+2, mlen, NULL);
+ if (!key->n) return 1;
+ break;
+
+ case 1:
+ /* Exponent */
+ if (key->e) {
+ /* This should only ever happen once per key */
+ return 1;
+ }
+
+ /* Create a BIGNUM from the pointer.
+ Note: this assumes big-endian data as required by PGP */
+ key->e = BN_bin2bn(p+2, mlen, NULL);
+ if (!key->e) return 1;
+ break;
+ }
+
+ return 0;
+}
+
+static void pgpFreeKeyRSA(pgpDigAlg pgpkey)
+{
+ struct pgpDigKeyRSA_s *key = pgpkey->data;
+ if (key) {
+ if (key->evp_pkey) {
+ EVP_PKEY_free(key->evp_pkey);
+ } else {
+ /* If key->evp_pkey was constructed,
+ * the memory management of these BNs
+ * are freed with it. */
+ BN_clear_free(key->n);
+ BN_clear_free(key->e);
+ }
+
+ free(key);
+ }
+}
+
+/* Signature */
+
+struct pgpDigSigRSA_s {
+ BIGNUM *bn;
+ size_t len;
+};
+
+static int pgpSetSigMpiRSA(pgpDigAlg pgpsig, int num, const uint8_t *p)
+{
+ BIGNUM *bn = NULL;
+
+ int mlen = pgpMpiLen(p) - 2;
+ int rc = 1;
+
+ struct pgpDigSigRSA_s *sig = pgpsig->data;
+ if (!sig) {
+ sig = xcalloc(1, sizeof(*sig));
+ }
+
+ switch (num) {
+ case 0:
+ if (sig->bn) {
+ /* This should only ever happen once per signature */
+ return 1;
+ }
+
+ bn = sig->bn = BN_new();
+ if (!bn) return 1;
+
+ /* Create a BIGNUM from the signature pointer.
+ Note: this assumes big-endian data as required
+ by the PGP multiprecision integer format
+ (RFC4880, Section 3.2)
+ This will be useful later, as we can
+ retrieve this value with appropriate
+ padding. */
+ bn = BN_bin2bn(p+2, mlen, bn);
+ if (!bn) return 1;
+
+ sig->bn = bn;
+ sig->len = mlen;
+
+ pgpsig->data = sig;
+ rc = 0;
+ break;
+ }
+ return rc;
+}
+
+static void pgpFreeSigRSA(pgpDigAlg pgpsig)
+{
+ struct pgpDigSigRSA_s *sig = pgpsig->data;
+ if (sig) {
+ BN_clear_free(sig->bn);
+ free(pgpsig->data);
+ }
+}
+
+static int pgpVerifySigRSA(pgpDigAlg pgpkey, pgpDigAlg pgpsig,
+ uint8_t *hash, size_t hashlen, int hash_algo)
+{
+ int rc, ret;
+ EVP_PKEY_CTX *pkey_ctx = NULL;
+ struct pgpDigSigRSA_s *sig = pgpsig->data;
+
+ void *padded_sig = NULL;
+
+ struct pgpDigKeyRSA_s *key = pgpkey->data;
+
+ if (!constructRSASigningKey(key)) {
+ rc = 1;
+ goto done;
+ }
+
+ pkey_ctx = EVP_PKEY_CTX_new(key->evp_pkey, NULL);
+ if (!pkey_ctx) {
+ rc = 1;
+ goto done;
+ }
+
+ ret = EVP_PKEY_verify_init(pkey_ctx);
+ if (ret < 0) {
+ rc = 1;
+ goto done;
+ }
+
+ ret = EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PADDING);
+ if (ret < 0) {
+ rc = 1;
+ goto done;
+ }
+
+ ret = EVP_PKEY_CTX_set_signature_md(pkey_ctx, getEVPMD(hash_algo));
+ if (ret < 0) {
+ rc = 1;
+ goto done;
+ }
+
+ int pkey_len = EVP_PKEY_size(key->evp_pkey);
+ padded_sig = xcalloc(1, pkey_len);
+ if (!BN_bn2binpad(sig->bn, padded_sig, pkey_len)) {
+ rc = 1;
+ goto done;
+ }
+
+ ret = EVP_PKEY_verify(pkey_ctx, padded_sig, pkey_len, hash, hashlen);
+ if (ret == 1)
+ {
+ /* Success */
+ rc = 0;
+ }
+ else
+ {
+ /* Failure */
+ rc = 1;
+ }
+
+done:
+ EVP_PKEY_CTX_free(pkey_ctx);
+ free(padded_sig);
+ return rc;
+}
+
+/****************************** DSA ***************************************/
+/* Key */
+
+struct pgpDigKeyDSA_s {
+ BIGNUM *p; /* Prime */
+ BIGNUM *q; /* Subprime */
+ BIGNUM *g; /* Base */
+ BIGNUM *y; /* Public Key */
+
+ DSA *dsa_key; /* Fully constructed key */
+};
+
+static int constructDSASigningKey(struct pgpDigKeyDSA_s *key)
+{
+ int rc;
+
+ if (key->dsa_key) {
+ /* We've already constructed it, so just reuse it */
+ return 1;
+ }
+
+ /* Create the DSA key */
+ DSA *dsa = DSA_new();
+ if (!dsa) return 0;
+
+ if (!DSA_set0_pqg(dsa, key->p, key->q, key->g)) {
+ rc = 0;
+ goto done;
+ }
+
+ if (!DSA_set0_key(dsa, key->y, NULL)) {
+ rc = 0;
+ goto done;
+ }
+
+ key->dsa_key = dsa;
+
+ rc = 1;
+done:
+ if (rc == 0) {
+ DSA_free(dsa);
+ }
+ return rc;
+}
+
+
+static int pgpSetKeyMpiDSA(pgpDigAlg pgpkey, int num, const uint8_t *p)
+{
+ BIGNUM *bn;
+ size_t mlen = pgpMpiLen(p) - 2;
+ struct pgpDigKeyDSA_s *key = pgpkey->data;
+
+ if (!key) {
+ key = pgpkey->data = xcalloc(1, sizeof(*key));
+ }
+
+ /* Create a BIGNUM from the key pointer.
+ Note: this assumes big-endian data as required
+ by the PGP multiprecision integer format
+ (RFC4880, Section 3.2) */
+ bn = BN_bin2bn(p+2, mlen, NULL);
+ if (!bn) return 1;
+
+ switch (num) {
+ case 0:
+ /* Prime */
+ if (key->p) {
+ /* This should only ever happen once per key */
+ return 1;
+ }
+ key->p = bn;
+ break;
+
+ case 1:
+ /* Subprime */
+ if (key->q) {
+ /* This should only ever happen once per key */
+ return 1;
+ }
+ key->q = bn;
+ break;
+ case 2:
+ /* Base */
+ if (key->g) {
+ /* This should only ever happen once per key */
+ return 1;
+ }
+ key->g = bn;
+ break;
+ case 3:
+ /* Public */
+ if (key->y) {
+ /* This should only ever happen once per key */
+ return 1;
+ }
+ key->y = bn;
+ break;
+ }
+
+ return 0;
+}
+
+static void pgpFreeKeyDSA(pgpDigAlg pgpkey)
+{
+ struct pgpDigKeyDSA_s *key = pgpkey->data;
+ if (key) {
+ if (key->dsa_key) {
+ DSA_free(key->dsa_key);
+ } else {
+ /* If sig->dsa_key was constructed,
+ * the memory management of these BNs
+ * are freed with it. */
+ BN_clear_free(key->p);
+ BN_clear_free(key->q);
+ BN_clear_free(key->g);
+ BN_clear_free(key->y);
+ }
+ free(key);
+ }
+}
+
+/* Signature */
+
+struct pgpDigSigDSA_s {
+ BIGNUM *r;
+ BIGNUM *s;
+
+ DSA_SIG *dsa_sig;
+};
+
+static int constructDSASignature(struct pgpDigSigDSA_s *sig)
+{
+ int rc;
+
+ if (sig->dsa_sig) {
+ /* We've already constructed it, so just reuse it */
+ return 1;
+ }
+
+ /* Create the DSA signature */
+ DSA_SIG *dsa_sig = DSA_SIG_new();
+ if (!dsa_sig) return 0;
+
+ if (!DSA_SIG_set0(dsa_sig, sig->r, sig->s)) {
+ rc = 0;
+ goto done;
+ }
+
+ sig->dsa_sig = dsa_sig;
+
+ rc = 1;
+done:
+ if (rc == 0) {
+ DSA_SIG_free(sig->dsa_sig);
+ }
+ return rc;
+}
+
+static int pgpSetSigMpiDSA(pgpDigAlg pgpsig, int num, const uint8_t *p)
+{
+ BIGNUM *bn = NULL;
+
+ int mlen = pgpMpiLen(p) - 2;
+ int rc = 1;
+
+ struct pgpDigSigDSA_s *sig = pgpsig->data;
+ if (!sig) {
+ sig = xcalloc(1, sizeof(*sig));
+ }
+
+ /* Create a BIGNUM from the signature pointer.
+ Note: this assumes big-endian data as required
+ by the PGP multiprecision integer format
+ (RFC4880, Section 3.2) */
+ bn = BN_bin2bn(p+2, mlen, NULL);
+ if (!bn) return 1;
+
+ switch (num) {
+ case 0:
+ if (sig->r) {
+ /* This should only ever happen once per signature */
+ BN_free(bn);
+ return 1;
+ }
+ sig->r = bn;
+ rc = 0;
+ break;
+ case 1:
+ if (sig->s) {
+ /* This should only ever happen once per signature */
+ BN_free(bn);
+ return 1;
+ }
+ sig->s = bn;
+ rc = 0;
+ break;
+ }
+
+ pgpsig->data = sig;
+
+ return rc;
+}
+
+static void pgpFreeSigDSA(pgpDigAlg pgpsig)
+{
+ struct pgpDigSigDSA_s *sig = pgpsig->data;
+ if (sig) {
+ if (sig->dsa_sig) {
+ DSA_SIG_free(sig->dsa_sig);
+ } else {
+ /* If sig->dsa_sig was constructed,
+ * the memory management of these BNs
+ * are freed with it. */
+ BN_clear_free(sig->r);
+ BN_clear_free(sig->s);
+ }
+ free(pgpsig->data);
+ }
+}
+
+static int pgpVerifySigDSA(pgpDigAlg pgpkey, pgpDigAlg pgpsig,
+ uint8_t *hash, size_t hashlen, int hash_algo)
+{
+ int rc, ret;
+ struct pgpDigSigDSA_s *sig = pgpsig->data;
+
+ struct pgpDigKeyDSA_s *key = pgpkey->data;
+
+ if (!constructDSASigningKey(key)) {
+ rc = 1;
+ goto done;
+ }
+
+ if (!constructDSASignature(sig)) {
+ rc = 1;
+ goto done;
+ }
+
+ ret = DSA_do_verify(hash, hashlen, sig->dsa_sig, key->dsa_key);
+ if (ret == 1)
+ {
+ /* Success */
+ rc = 0;
+ }
+ else
+ {
+ /* Failure */
+ rc = 1;
+ }
+
+done:
+ return rc;
+}
+
+/****************************** NULL **************************************/
+
+static int pgpSetMpiNULL(pgpDigAlg pgpkey, int num, const uint8_t *p)
+{
+ return 1;
+}
+
+static int pgpVerifyNULL(pgpDigAlg pgpkey, pgpDigAlg pgpsig,
+ uint8_t *hash, size_t hashlen, int hash_algo)
+{
+ return 1;
+}
+
+/****************************** PGP **************************************/
+pgpDigAlg pgpPubkeyNew(int algo)
+{
+ pgpDigAlg ka = xcalloc(1, sizeof(*ka));;
+
+ switch (algo) {
+ case PGPPUBKEYALGO_RSA:
+ ka->setmpi = pgpSetKeyMpiRSA;
+ ka->free = pgpFreeKeyRSA;
+ ka->mpis = 2;
+ break;
+ case PGPPUBKEYALGO_DSA:
+ ka->setmpi = pgpSetKeyMpiDSA;
+ ka->free = pgpFreeKeyDSA;
+ ka->mpis = 4;
+ break;
+ default:
+ ka->setmpi = pgpSetMpiNULL;
+ ka->mpis = -1;
+ break;
+ }
+
+ ka->verify = pgpVerifyNULL; /* keys can't be verified */
+
+ return ka;
+}
+
+pgpDigAlg pgpSignatureNew(int algo)
+{
+ pgpDigAlg sa = xcalloc(1, sizeof(*sa));
+
+ switch (algo) {
+ case PGPPUBKEYALGO_RSA:
+ sa->setmpi = pgpSetSigMpiRSA;
+ sa->free = pgpFreeSigRSA;
+ sa->verify = pgpVerifySigRSA;
+ sa->mpis = 1;
+ break;
+ case PGPPUBKEYALGO_DSA:
+ sa->setmpi = pgpSetSigMpiDSA;
+ sa->free = pgpFreeSigDSA;
+ sa->verify = pgpVerifySigDSA;
+ sa->mpis = 2;
+ break;
+ default:
+ sa->setmpi = pgpSetMpiNULL;
+ sa->verify = pgpVerifyNULL;
+ sa->mpis = -1;
+ break;
+ }
+ return sa;
+}
diff --git a/rpmio/macro.c b/rpmio/macro.c
index c1bb04334..7858b10b2 100644
--- a/rpmio/macro.c
+++ b/rpmio/macro.c
@@ -4,6 +4,8 @@
#include "system.h"
#include <stdarg.h>
+#include <pthread.h>
+#include <errno.h>
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#else
@@ -34,21 +36,31 @@ extern int optind;
#include "debug.h"
+enum macroFlags_e {
+ ME_NONE = 0,
+ ME_AUTO = (1 << 0),
+ ME_USED = (1 << 1),
+};
+
/*! The structure used to store a macro. */
struct rpmMacroEntry_s {
struct rpmMacroEntry_s *prev;/*!< Macro entry stack. */
- char *name; /*!< Macro name. */
- char *opts; /*!< Macro parameters (a la getopt) */
- char *body; /*!< Macro body. */
- int used; /*!< No. of expansions. */
+ const char *name; /*!< Macro name. */
+ const char *opts; /*!< Macro parameters (a la getopt) */
+ const char *body; /*!< Macro body. */
+ int flags; /*!< Macro state bits. */
int level; /*!< Scoping level. */
+ char arena[]; /*!< String arena. */
};
/*! The structure used to store the set of macros in a context. */
struct rpmMacroContext_s {
- rpmMacroEntry *macroTable; /*!< Macro entry table for context. */
- int macrosAllocated;/*!< No. of allocated macros. */
- int firstFree; /*!< No. of macros. */
+ rpmMacroEntry *tab; /*!< Macro entry table (array of pointers). */
+ int n; /*!< No. of macros. */
+ int depth; /*!< Depth tracking when recursing from Lua */
+ int level; /*!< Scope level tracking when recursing from Lua */
+ pthread_mutex_t lock;
+ pthread_mutexattr_t lockattr;
};
@@ -58,6 +70,29 @@ rpmMacroContext rpmGlobalMacroContext = &rpmGlobalMacroContext_s;
static struct rpmMacroContext_s rpmCLIMacroContext_s;
rpmMacroContext rpmCLIMacroContext = &rpmCLIMacroContext_s;
+/*
+ * The macro engine internals do not require recursive mutexes but Lua
+ * macro bindings which can get called from the internals use the external
+ * interfaces which do perform locking. Until that is fixed somehow
+ * we'll just have to settle for recursive mutexes.
+ * Unfortunately POSIX doesn't specify static initializers for recursive
+ * mutexes so we need to have a separate PTHREAD_ONCE initializer just
+ * to initialize the otherwise static macro context mutexes. Pooh.
+ */
+static pthread_once_t locksInitialized = PTHREAD_ONCE_INIT;
+
+static void initLocks(void)
+{
+ rpmMacroContext mcs[] = { rpmGlobalMacroContext, rpmCLIMacroContext, NULL };
+
+ for (rpmMacroContext *mcp = mcs; *mcp; mcp++) {
+ rpmMacroContext mc = *mcp;
+ pthread_mutexattr_init(&mc->lockattr);
+ pthread_mutexattr_settype(&mc->lockattr, PTHREAD_MUTEX_RECURSIVE);
+ pthread_mutex_init(&mc->lock, &mc->lockattr);
+ }
+}
+
/**
* Macro expansion state.
*/
@@ -66,12 +101,16 @@ typedef struct MacroBuf_s {
size_t tpos; /*!< Current position in expansion buffer */
size_t nb; /*!< No. bytes remaining in expansion buffer. */
int depth; /*!< Current expansion depth. */
+ int level; /*!< Current scoping level */
+ int error; /*!< Errors encountered during expansion? */
int macro_trace; /*!< Pre-print macro to expand? */
int expand_trace; /*!< Post-print macro expansion? */
+ int escape; /*!< Preserve '%%' during expansion? */
+ int flags; /*!< Flags to control behavior */
rpmMacroContext mc;
} * MacroBuf;
-#define _MAX_MACRO_DEPTH 16
+#define _MAX_MACRO_DEPTH 64
static int max_macro_depth = _MAX_MACRO_DEPTH;
#define _PRINT_MACRO_TRACE 0
@@ -80,110 +119,28 @@ static int print_macro_trace = _PRINT_MACRO_TRACE;
#define _PRINT_EXPAND_TRACE 0
static int print_expand_trace = _PRINT_EXPAND_TRACE;
-#define MACRO_CHUNK_SIZE 16
-
/* forward ref */
static int expandMacro(MacroBuf mb, const char *src, size_t slen);
+static void pushMacro(rpmMacroContext mc,
+ const char * n, const char * o, const char * b, int level, int flags);
+static void popMacro(rpmMacroContext mc, const char * n);
+static int loadMacroFile(rpmMacroContext mc, const char * fn);
/* =============================================================== */
-/**
- * Compare macro entries by name (qsort/bsearch).
- * @param ap 1st macro entry
- * @param bp 2nd macro entry
- * @return result of comparison
- */
-static int
-compareMacroName(const void * ap, const void * bp)
+static rpmMacroContext rpmmctxAcquire(rpmMacroContext mc)
{
- rpmMacroEntry ame = *((const rpmMacroEntry *)ap);
- rpmMacroEntry bme = *((const rpmMacroEntry *)bp);
-
- if (ame == NULL && bme == NULL)
- return 0;
- if (ame == NULL)
- return 1;
- if (bme == NULL)
- return -1;
- return strcmp(ame->name, bme->name);
+ if (mc == NULL)
+ mc = rpmGlobalMacroContext;
+ pthread_once(&locksInitialized, initLocks);
+ pthread_mutex_lock(&mc->lock);
+ return mc;
}
-/**
- * Enlarge macro table.
- * @param mc macro context
- */
-static void
-expandMacroTable(rpmMacroContext mc)
+static rpmMacroContext rpmmctxRelease(rpmMacroContext mc)
{
- if (mc->macroTable == NULL) {
- mc->macrosAllocated = MACRO_CHUNK_SIZE;
- mc->macroTable = (rpmMacroEntry *)
- xmalloc(sizeof(*(mc->macroTable)) * mc->macrosAllocated);
- mc->firstFree = 0;
- } else {
- mc->macrosAllocated += MACRO_CHUNK_SIZE;
- mc->macroTable = (rpmMacroEntry *)
- xrealloc(mc->macroTable, sizeof(*(mc->macroTable)) *
- mc->macrosAllocated);
- }
- memset(&mc->macroTable[mc->firstFree], 0, MACRO_CHUNK_SIZE * sizeof(*(mc->macroTable)));
-}
-
-/**
- * Sort entries in macro table.
- * @param mc macro context
- */
-static void
-sortMacroTable(rpmMacroContext mc)
-{
- int i;
-
- if (mc == NULL || mc->macroTable == NULL)
- return;
-
- qsort(mc->macroTable, mc->firstFree, sizeof(*(mc->macroTable)),
- compareMacroName);
-
- /* Empty pointers are now at end of table. Reset first free index. */
- for (i = 0; i < mc->firstFree; i++) {
- if (mc->macroTable[i] != NULL)
- continue;
- mc->firstFree = i;
- break;
- }
-}
-
-void
-rpmDumpMacroTable(rpmMacroContext mc, FILE * fp)
-{
- int nempty = 0;
- int nactive = 0;
-
- if (mc == NULL) mc = rpmGlobalMacroContext;
- if (fp == NULL) fp = stderr;
-
- fprintf(fp, "========================\n");
- if (mc->macroTable != NULL) {
- int i;
- for (i = 0; i < mc->firstFree; i++) {
- rpmMacroEntry me;
- if ((me = mc->macroTable[i]) == NULL) {
- /* XXX this should never happen */
- nempty++;
- continue;
- }
- fprintf(fp, "%3d%c %s", me->level,
- (me->used > 0 ? '=' : ':'), me->name);
- if (me->opts && *me->opts)
- fprintf(fp, "(%s)", me->opts);
- if (me->body && *me->body)
- fprintf(fp, "\t%s", me->body);
- fprintf(fp, "\n");
- nactive++;
- }
- }
- fprintf(fp, _("======================== active %d empty %d\n"),
- nactive, nempty);
+ pthread_mutex_unlock(&mc->lock);
+ return NULL;
}
/**
@@ -191,33 +148,41 @@ rpmDumpMacroTable(rpmMacroContext mc, FILE * fp)
* @param mc macro context
* @param name macro name
* @param namelen no. of bytes
+ * @param pos found/insert position
* @return address of slot in macro table with name (or NULL)
*/
static rpmMacroEntry *
-findEntry(rpmMacroContext mc, const char * name, size_t namelen)
+findEntry(rpmMacroContext mc, const char *name, size_t namelen, size_t *pos)
{
- rpmMacroEntry key, *ret;
- struct rpmMacroEntry_s keybuf;
- char namebuf[namelen+1];
- const char *mname = name;
-
- if (mc == NULL) mc = rpmGlobalMacroContext;
- if (mc->macroTable == NULL || mc->firstFree == 0)
- return NULL;
-
- if (namelen > 0) {
- strncpy(namebuf, name, namelen);
- namebuf[namelen] = '\0';
- mname = namebuf;
+ /* bsearch */
+ int cmp = 1;
+ size_t l = 0;
+ size_t u = mc->n;
+ size_t i = 0;
+ while (l < u) {
+ i = (l + u) / 2;
+ rpmMacroEntry me = mc->tab[i];
+ if (namelen == 0)
+ cmp = strcmp(me->name, name);
+ else {
+ cmp = strncmp(me->name, name, namelen);
+ /* longer me->name compares greater */
+ if (cmp == 0)
+ cmp = (me->name[namelen] != '\0');
+ }
+ if (cmp < 0)
+ l = i + 1;
+ else if (cmp > 0)
+ u = i;
+ else
+ break;
}
-
- key = &keybuf;
- memset(key, 0, sizeof(*key));
- key->name = (char *)mname;
- ret = (rpmMacroEntry *) bsearch(&key, mc->macroTable, mc->firstFree,
- sizeof(*(mc->macroTable)), compareMacroName);
- /* XXX TODO: find 1st empty slot and return that */
- return ret;
+
+ if (pos)
+ *pos = (cmp < 0) ? i + 1 : i;
+ if (cmp == 0)
+ return &mc->tab[i];
+ return NULL;
}
/* =============================================================== */
@@ -226,7 +191,7 @@ findEntry(rpmMacroContext mc, const char * name, size_t namelen)
* fgets(3) analogue that reads \ continuations. Last newline always trimmed.
* @param buf input buffer
* @param size inbut buffer size (bytes)
- * @param fd file handle
+ * @param f file handle
* @return buffer, or NULL on end-of-file
*/
static char *
@@ -316,11 +281,9 @@ static void
printMacro(MacroBuf mb, const char * s, const char * se)
{
const char *senl;
- const char *ellipsis;
- int choplen;
if (s >= se) { /* XXX just in case */
- fprintf(stderr, _("%3d>%*s(empty)"), mb->depth,
+ fprintf(stderr, _("%3d>%*s(empty)\n"), mb->depth,
(2 * mb->depth + 1), "");
return;
}
@@ -332,19 +295,11 @@ printMacro(MacroBuf mb, const char * s, const char * se)
for (senl = se; *senl && !iseol(*senl); senl++)
{};
- /* Limit trailing non-trace output */
- choplen = 61 - (2 * mb->depth);
- if ((senl - s) > choplen) {
- senl = s + choplen;
- ellipsis = "...";
- } else
- ellipsis = "";
-
/* Substitute caret at end-of-macro position */
fprintf(stderr, "%3d>%*s%%%.*s^", mb->depth,
(2 * mb->depth + 1), "", (int)(se - s), s);
- if (se[1] != '\0' && (senl - (se+1)) > 0)
- fprintf(stderr, "%-.*s%s", (int)(senl - (se+1)), se+1, ellipsis);
+ if (se[0] != '\0' && se[1] != '\0' && (senl - (se+1)) > 0)
+ fprintf(stderr, "%-.*s", (int)(senl - (se+1)), se+1);
fprintf(stderr, "\n");
}
@@ -357,9 +312,6 @@ printMacro(MacroBuf mb, const char * s, const char * se)
static void
printExpansion(MacroBuf mb, const char * t, const char * te)
{
- const char *ellipsis;
- int choplen;
-
if (!(te > t)) {
rpmlog(RPMLOG_DEBUG, _("%3d<%*s(empty)\n"), mb->depth, (2 * mb->depth + 1), "");
return;
@@ -368,7 +320,6 @@ printExpansion(MacroBuf mb, const char * t, const char * te)
/* Shorten output which contains newlines */
while (te > t && iseol(te[-1]))
te--;
- ellipsis = "";
if (mb->depth > 0) {
const char *tenl;
@@ -376,17 +327,11 @@ printExpansion(MacroBuf mb, const char * t, const char * te)
while ((tenl = strchr(t, '\n')) && tenl < te)
t = ++tenl;
- /* Limit expand output */
- choplen = 61 - (2 * mb->depth);
- if ((te - t) > choplen) {
- te = t + choplen;
- ellipsis = "...";
- }
}
rpmlog(RPMLOG_DEBUG,"%3d<%*s", mb->depth, (2 * mb->depth + 1), "");
if (te > t)
- rpmlog(RPMLOG_DEBUG, "%.*s%s", (int)(te - t), t, ellipsis);
+ rpmlog(RPMLOG_DEBUG, "%.*s", (int)(te - t), t);
rpmlog(RPMLOG_DEBUG, "\n");
}
@@ -400,14 +345,14 @@ printExpansion(MacroBuf mb, const char * t, const char * te)
#define COPYNAME(_ne, _s, _c) \
{ SKIPBLANK(_s,_c); \
- while(((_c) = *(_s)) && (risalnum(_c) || (_c) == '_')) \
+ while (((_c) = *(_s)) && (risalnum(_c) || (_c) == '_')) \
*(_ne)++ = *(_s)++; \
*(_ne) = '\0'; \
}
#define COPYOPTS(_oe, _s, _c) \
{ \
- while(((_c) = *(_s)) && (_c) != ')') \
+ while (((_c) = *(_s)) && (_c) != ')') \
*(_oe)++ = *(_s)++; \
*(_oe) = '\0'; \
}
@@ -424,15 +369,18 @@ static int
expandThis(MacroBuf mb, const char * src, size_t slen, char **target)
{
struct MacroBuf_s umb;
- int rc;
/* Copy other state from "parent", but we want a buffer of our own */
umb = *mb;
umb.buf = NULL;
- rc = expandMacro(&umb, src, slen);
+ umb.error = 0;
+ /* In case of error, flag it in the "parent"... */
+ if (expandMacro(&umb, src, slen))
+ mb->error = 1;
*target = umb.buf;
- return rc;
+ /* ...but return code for this operation specifically */
+ return umb.error;
}
static void mbAppend(MacroBuf mb, char c)
@@ -446,6 +394,7 @@ static void mbAppend(MacroBuf mb, char c)
mb->nb--;
}
+#ifdef WITH_LUA
static void mbAppendStr(MacroBuf mb, const char *str)
{
size_t len = strlen(str);
@@ -457,68 +406,66 @@ static void mbAppendStr(MacroBuf mb, const char *str)
mb->tpos += len;
mb->nb -= len;
}
+#endif
+
/**
* Expand output of shell command into target buffer.
* @param mb macro expansion state
* @param cmd shell command
* @param clen no. bytes in shell command
- * @return result of expansion
*/
-static int
+static void
doShellEscape(MacroBuf mb, const char * cmd, size_t clen)
{
char *buf = NULL;
FILE *shf;
- int rc = 0;
int c;
- rpmlog(RPMLOG_WARNING, _("Refusing to run shell code: %s\n"), cmd);
- mbAppendStr(mb, "UNEXPANDEDSHELLSCRIPT");
-#if 0
- rc = expandThis(mb, cmd, clen, &buf);
- if (rc)
+ if (expandThis(mb, cmd, clen, &buf))
goto exit;
if ((shf = popen(buf, "r")) == NULL) {
- rc = 1;
+ mb->error = 1;
goto exit;
}
- while((c = fgetc(shf)) != EOF) {
+
+ size_t tpos = mb->tpos;
+ while ((c = fgetc(shf)) != EOF) {
mbAppend(mb, c);
}
(void) pclose(shf);
- /* XXX delete trailing \r \n */
- while (iseol(mb->buf[mb->tpos-1])) {
- mb->buf[mb->tpos--] = '\0';
+ /* Delete trailing \r \n */
+ while (mb->tpos > tpos && iseol(mb->buf[mb->tpos-1])) {
+ mb->buf[--mb->tpos] = '\0';
mb->nb++;
}
exit:
_free(buf);
-#endif
- return rc;
}
/**
* Parse (and execute) new macro definition.
* @param mb macro expansion state
* @param se macro definition to parse
+ * @param slen length of se argument
* @param level macro recursion level
* @param expandbody should body be expanded?
* @return address to continue parsing
*/
static const char *
-doDefine(MacroBuf mb, const char * se, int level, int expandbody)
+doDefine(MacroBuf mb, const char * se, size_t slen, int level, int expandbody)
{
const char *s = se;
- size_t blen = MACROBUFSIZ;
- char *buf = xmalloc(blen);
+ char *buf = xmalloc(slen + 3); /* Some leeway for termination issues... */
char *n = buf, *ne = n;
char *o = NULL, *oe;
char *b, *be, *ebody = NULL;
int c;
int oc = ')';
+ const char *sbody; /* as-is body start */
+ int rc = 1; /* assume failure */
/* Copy name */
COPYNAME(ne, s, c);
@@ -527,13 +474,20 @@ doDefine(MacroBuf mb, const char * se, int level, int expandbody)
oe = ne + 1;
if (*s == '(') {
s++; /* skip ( */
- o = oe;
- COPYOPTS(oe, s, oc);
- s++; /* skip ) */
+ /* Options must be terminated with ')' */
+ if (strchr(s, ')')) {
+ o = oe;
+ COPYOPTS(oe, s, oc);
+ s++; /* skip ) */
+ } else {
+ rpmlog(RPMLOG_ERR, _("Macro %%%s has unterminated opts\n"), n);
+ goto exit;
+ }
}
/* Copy body, skipping over escaped newlines */
b = be = oe + 1;
+ sbody = s;
SKIPBLANK(s, c);
if (c == '{') { /* XXX permit silent {...} grouping */
if ((se = matchchar(s, c, '}')) == NULL) {
@@ -594,14 +548,8 @@ doDefine(MacroBuf mb, const char * se, int level, int expandbody)
/* Names must start with alphabetic or _ and be at least 3 chars */
if (!((c = *n) && (risalpha(c) || c == '_') && (ne - n) > 2)) {
- rpmlog(RPMLOG_ERR,
- _("Macro %%%s has illegal name (%%define)\n"), n);
- goto exit;
- }
-
- /* Options must be terminated with ')' */
- if (o && oc != ')') {
- rpmlog(RPMLOG_ERR, _("Macro %%%s has unterminated opts\n"), n);
+ rpmlog(RPMLOG_ERR, _("Macro %%%s has illegal name (%s)\n"),
+ n, expandbody ? "%global": "%define");
goto exit;
}
@@ -610,6 +558,9 @@ doDefine(MacroBuf mb, const char * se, int level, int expandbody)
goto exit;
}
+ if (!isblank(*sbody) && !(*sbody == '\\' && iseol(sbody[1])))
+ rpmlog(RPMLOG_WARNING, _("Macro %%%s needs whitespace before body\n"), n);
+
if (expandbody) {
if (expandThis(mb, b, 0, &ebody)) {
rpmlog(RPMLOG_ERR, _("Macro %%%s failed to expand\n"), n);
@@ -618,9 +569,12 @@ doDefine(MacroBuf mb, const char * se, int level, int expandbody)
b = ebody;
}
- addMacro(mb->mc, n, o, b, (level - 1));
+ pushMacro(mb->mc, n, o, b, level, ME_NONE);
+ rc = 0;
exit:
+ if (rc)
+ mb->error = 1;
_free(buf);
_free(ebody);
return se;
@@ -628,15 +582,16 @@ exit:
/**
* Parse (and execute) macro undefinition.
- * @param mc macro context
+ * @param mb macro expansion state
* @param se macro name to undefine
+ * @param slen length of se argument
* @return address to continue parsing
*/
static const char *
-doUndefine(rpmMacroContext mc, const char * se)
+doUndefine(MacroBuf mb, const char * se, size_t slen)
{
const char *s = se;
- char *buf = xmalloc(MACROBUFSIZ);
+ char *buf = xmalloc(slen + 1);
char *n = buf, *ne = n;
int c;
@@ -649,12 +604,12 @@ doUndefine(rpmMacroContext mc, const char * se)
/* Names must start with alphabetic or _ and be at least 3 chars */
if (!((c = *n) && (risalpha(c) || c == '_') && (ne - n) > 2)) {
- rpmlog(RPMLOG_ERR,
- _("Macro %%%s has illegal name (%%undefine)\n"), n);
+ rpmlog(RPMLOG_ERR, _("Macro %%%s has illegal name (%%undefine)\n"), n);
+ mb->error = 1;
goto exit;
}
- delMacro(mc, n);
+ popMacro(mb->mc, n);
exit:
_free(buf);
@@ -662,58 +617,6 @@ exit:
}
/**
- * Push new macro definition onto macro entry stack.
- * @param mep address of macro entry slot
- * @param n macro name
- * @param o macro parameters (NULL if none)
- * @param b macro body (NULL becomes "")
- * @param level macro recursion level
- */
-static void
-pushMacro(rpmMacroEntry * mep,
- const char * n, const char * o,
- const char * b, int level)
-{
- rpmMacroEntry prev = (mep && *mep ? *mep : NULL);
- rpmMacroEntry me = (rpmMacroEntry) xmalloc(sizeof(*me));
-
- me->prev = prev;
- me->name = (prev ? prev->name : xstrdup(n));
- me->opts = (o ? xstrdup(o) : NULL);
- me->body = xstrdup(b ? b : "");
- me->used = 0;
- me->level = level;
- if (mep)
- *mep = me;
- else
- me = _free(me);
-}
-
-/**
- * Pop macro definition from macro entry stack.
- * @param mep address of macro entry slot
- */
-static void
-popMacro(rpmMacroEntry * mep)
-{
- if (mep && *mep) {
- rpmMacroEntry me = *mep;
-
- /* restore previous definition of the macro */
- *mep = me->prev;
-
- /* name is shared between entries, only free if last of its kind */
- if (me->prev == NULL)
- free(me->name);
- free(me->opts);
- free(me->body);
-
- memset(me, 0, sizeof(*me)); /* trash and burn */
- free(me);
- }
-}
-
-/**
* Free parsed arguments for parameterized macro.
* @param mb macro expansion state
*/
@@ -721,41 +624,60 @@ static void
freeArgs(MacroBuf mb)
{
rpmMacroContext mc = mb->mc;
- int ndeleted = 0;
- int i;
-
- if (mc == NULL || mc->macroTable == NULL)
- return;
/* Delete dynamic macro definitions */
- for (i = 0; i < mc->firstFree; i++) {
- rpmMacroEntry *mep, me;
- int skiptest = 0;
- mep = &mc->macroTable[i];
- me = *mep;
-
- if (me == NULL) /* XXX this should never happen */
- continue;
- if (me->level < mb->depth)
+ for (int i = 0; i < mc->n; i++) {
+ rpmMacroEntry me = mc->tab[i];
+ assert(me);
+ if (me->level < mb->level)
continue;
- if (strlen(me->name) == 1 && strchr("#*0", *me->name)) {
- if (*me->name == '*' && me->used > 0)
- skiptest = 1; /* XXX skip test for %# %* %0 */
- } else if (!skiptest && me->used <= 0) {
-#if NOTYET
- rpmlog(RPMLOG_ERR,
- _("Macro %%%s (%s) was not used below level %d\n"),
- me->name, me->body, me->level);
-#endif
+ /* Warn on defined but unused non-automatic, scoped macros */
+ if (!(me->flags & (ME_AUTO|ME_USED))) {
+ rpmlog(RPMLOG_WARNING,
+ _("Macro %%%s defined but not used within scope\n"),
+ me->name);
+ /* Only whine once */
+ me->flags |= ME_USED;
}
- popMacro(mep);
- if (!(mep && *mep))
- ndeleted++;
+
+ /* compensate if the slot is to go away */
+ if (me->prev == NULL)
+ i--;
+ popMacro(mc, me->name);
}
+ mb->level--;
+}
- /* If any deleted macros, sort macro table */
- if (ndeleted)
- sortMacroTable(mc);
+static void splitQuoted(ARGV_t *av, const char * str, const char * seps)
+{
+ const int qchar = 0x1f; /* ASCII unit separator */
+ const char *s = str;
+ const char *start = str;
+ int quoted = 0;
+
+ while (start != NULL) {
+ if (!quoted && strchr(seps, *s)) {
+ size_t slen = s - start;
+ /* quoted arguments are always kept, otherwise skip empty args */
+ if (slen > 0) {
+ char *d, arg[slen + 1];
+ const char *t;
+ for (d = arg, t = start; t - start < slen; t++) {
+ if (*t == qchar)
+ continue;
+ *d++ = *t;
+ }
+ arg[d - arg] = '\0';
+ argvAdd(av, arg);
+ }
+ start = s + 1;
+ }
+ if (*s == qchar)
+ quoted = !quoted;
+ else if (*s == '\0')
+ start = NULL;
+ s++;
+ }
}
/**
@@ -771,31 +693,41 @@ static const char *
grabArgs(MacroBuf mb, const rpmMacroEntry me, const char * se,
const char * lastc)
{
+ const char *cont = NULL;
const char *opts;
char *args = NULL;
ARGV_t argv = NULL;
int argc = 0;
int c;
- /* Copy macro name as argv[0] */
- argvAdd(&argv, me->name);
- addMacro(mb->mc, "0", NULL, me->name, mb->depth);
-
/*
+ * Prepare list of call arguments, starting with macro name as argv[0].
* Make a copy of se up to lastc string that we can pass to argvSplit().
* Append the results to main argv.
*/
- { ARGV_t av = NULL;
- char *s = xcalloc((lastc-se)+1, sizeof(*s));
- memcpy(s, se, (lastc-se));
+ argvAdd(&argv, me->name);
+ if (lastc) {
+ int oescape = mb->escape;
+ char *s = NULL;
- argvSplit(&av, s, " \t");
- argvAppend(&argv, av);
+ /* Expand possible macros in arguments */
+ mb->escape = 1;
+ expandThis(mb, se, lastc-se, &s);
+ mb->escape = oescape;
- argvFree(av);
+ splitQuoted(&argv, s, " \t");
free(s);
+
+ cont = ((*lastc == '\0' || *lastc == '\n') && *(lastc-1) != '\\') ?
+ lastc : lastc + 1;
}
+ /* Bump call depth on entry before first macro define */
+ mb->level++;
+
+ /* Setup macro name as %0 */
+ pushMacro(mb->mc, "0", NULL, me->name, mb->level, ME_AUTO);
+
/*
* The macro %* analoguous to the shell's $* means "Pass all non-macro
* parameters." Consequently, there needs to be a macro that means "Pass all
@@ -805,7 +737,7 @@ grabArgs(MacroBuf mb, const rpmMacroEntry me, const char * se,
* This is the (potential) justification for %{**} ...
*/
args = argvJoin(argv + 1, " ");
- addMacro(mb->mc, "**", NULL, args, mb->depth);
+ pushMacro(mb->mc, "**", NULL, args, mb->level, ME_AUTO);
free(args);
/*
@@ -822,12 +754,13 @@ grabArgs(MacroBuf mb, const rpmMacroEntry me, const char * se,
argc = argvCount(argv);
/* Define option macros. */
- while((c = getopt(argc, argv, opts)) != -1)
+ while ((c = getopt(argc, argv, opts)) != -1)
{
char *name = NULL, *body = NULL;
if (c == '?' || strchr(opts, c) == NULL) {
rpmlog(RPMLOG_ERR, _("Unknown option %c in %s(%s)\n"),
(char)optopt, me->name, opts);
+ mb->error = 1;
goto exit;
}
@@ -837,13 +770,13 @@ grabArgs(MacroBuf mb, const rpmMacroEntry me, const char * se,
} else {
rasprintf(&body, "-%c", c);
}
- addMacro(mb->mc, name, NULL, body, mb->depth);
+ pushMacro(mb->mc, name, NULL, body, mb->level, ME_AUTO);
free(name);
free(body);
if (optarg) {
rasprintf(&name, "-%c*", c);
- addMacro(mb->mc, name, NULL, optarg, mb->depth);
+ pushMacro(mb->mc, name, NULL, optarg, mb->level, ME_AUTO);
free(name);
}
}
@@ -851,7 +784,7 @@ grabArgs(MacroBuf mb, const rpmMacroEntry me, const char * se,
/* Add argument count (remaining non-option items) as macro. */
{ char *ac = NULL;
rasprintf(&ac, "%d", (argc - optind));
- addMacro(mb->mc, "#", NULL, ac, mb->depth);
+ pushMacro(mb->mc, "#", NULL, ac, mb->level, ME_AUTO);
free(ac);
}
@@ -860,41 +793,70 @@ grabArgs(MacroBuf mb, const rpmMacroEntry me, const char * se,
for (c = optind; c < argc; c++) {
char *name = NULL;
rasprintf(&name, "%d", (c - optind + 1));
- addMacro(mb->mc, name, NULL, argv[c], mb->depth);
+ pushMacro(mb->mc, name, NULL, argv[c], mb->level, ME_AUTO);
free(name);
}
}
/* Add concatenated unexpanded arguments as yet another macro. */
args = argvJoin(argv + optind, " ");
- addMacro(mb->mc, "*", NULL, args ? args : "", mb->depth);
+ pushMacro(mb->mc, "*", NULL, args ? args : "", mb->level, ME_AUTO);
free(args);
exit:
argvFree(argv);
- return *lastc ? lastc + 1 : lastc;
+ return cont;
}
/**
* Perform macro message output
* @param mb macro expansion state
* @param waserror use rpmlog()?
- * @param msg message to ouput
+ * @param msg message to output
* @param msglen no. of bytes in message
*/
static void
-doOutput(MacroBuf mb, int waserror, const char * msg, size_t msglen)
+doOutput(MacroBuf mb, int loglevel, const char * msg, size_t msglen)
{
char *buf = NULL;
(void) expandThis(mb, msg, msglen, &buf);
- if (waserror)
- rpmlog(RPMLOG_ERR, "%s\n", buf);
- else
- fprintf(stderr, "%s", buf);
+ rpmlog(loglevel, "%s\n", buf);
_free(buf);
}
+static void doLua(MacroBuf mb, const char * f, size_t fn, const char * g, size_t gn)
+{
+#ifdef WITH_LUA
+ rpmlua lua = NULL; /* Global state. */
+ char *scriptbuf = xmalloc(gn + 1);
+ char *printbuf;
+ rpmMacroContext mc = mb->mc;
+ int odepth = mc->depth;
+ int olevel = mc->level;
+
+ if (g != NULL && gn > 0)
+ memcpy(scriptbuf, g, gn);
+ scriptbuf[gn] = '\0';
+ rpmluaPushPrintBuffer(lua);
+ mc->depth = mb->depth;
+ mc->level = mb->level;
+ if (rpmluaRunScript(lua, scriptbuf, NULL) == -1)
+ mb->error = 1;
+ mc->depth = odepth;
+ mc->level = olevel;
+ printbuf = rpmluaPopPrintBuffer(lua);
+ if (printbuf) {
+ mbAppendStr(mb, printbuf);
+ free(printbuf);
+ }
+ free(scriptbuf);
+#else
+ rpmlog(RPMLOG_ERR, _("<lua> scriptlet support not built in\n"));
+ mb->error = 1;
+#endif
+}
+
/**
* Execute macro primitives.
* @param mb macro expansion state
@@ -911,8 +873,14 @@ doFoo(MacroBuf mb, int negate, const char * f, size_t fn,
char *buf = NULL;
char *b = NULL, *be;
int c;
+ int verbose = (rpmIsVerbose() != 0);
+ int expand = (g != NULL && gn > 0);
+
+ /* Don't expand %{verbose:...} argument on false condition */
+ if (STREQ("verbose", f, fn) && (verbose == negate))
+ expand = 0;
- if (g != NULL) {
+ if (expand) {
(void) expandThis(mb, g, gn, &buf);
} else {
buf = xmalloc(MACROBUFSIZ + fn + gn);
@@ -927,16 +895,38 @@ doFoo(MacroBuf mb, int negate, const char * f, size_t fn,
if ((b = strrchr(buf, '/')) != NULL)
*b = '\0';
b = buf;
+ } else if (STREQ("shrink", f, fn)) {
+ /*
+ * shrink body by removing all leading and trailing whitespaces and
+ * reducing intermediate whitespaces to a single space character.
+ */
+ size_t i = 0, j = 0;
+ size_t buflen = strlen(buf);
+ int was_space = 0;
+ while (i < buflen) {
+ if (risspace(buf[i])) {
+ was_space = 1;
+ i++;
+ continue;
+ } else if (was_space) {
+ was_space = 0;
+ if (j > 0) /* remove leading blanks at all */
+ buf[j++] = ' ';
+ }
+ buf[j++] = buf[i++];
+ }
+ buf[j] = '\0';
+ b = buf;
+ } else if (STREQ("quote", f, fn)) {
+ char *quoted = NULL;
+ rasprintf(&quoted, "%c%s%c", 0x1f, buf, 0x1f);
+ free(buf);
+ b = buf = quoted;
} else if (STREQ("suffix", f, fn)) {
if ((b = strrchr(buf, '.')) != NULL)
b++;
- } else if (STREQ("expand", f, fn)) {
+ } else if (STREQ("expand", f, fn) || STREQ("verbose", f, fn)) {
b = buf;
- } else if (STREQ("verbose", f, fn)) {
- if (negate)
- b = (rpmIsVerbose() ? NULL : buf);
- else
- b = (rpmIsVerbose() ? buf : NULL);
} else if (STREQ("url2path", f, fn) || STREQ("u2p", f, fn)) {
(void)urlPath(buf, (const char **)&b);
if (*b == '\0') b = "/";
@@ -948,7 +938,7 @@ doFoo(MacroBuf mb, int negate, const char * f, size_t fn,
be++;
*be++ = '\0';
(void) rpmFileIsCompressed(b, &compressed);
- switch(compressed) {
+ switch (compressed) {
default:
case COMPRESSED_NOT:
sprintf(be, "%%__cat %s", b);
@@ -975,6 +965,9 @@ doFoo(MacroBuf mb, int negate, const char * f, size_t fn,
case COMPRESSED_7ZIP:
sprintf(be, "%%__7zip x %s", b);
break;
+ case COMPRESSED_ZSTD:
+ sprintf(be, "%%__zstd -dc %s", b);
+ break;
}
b = be;
} else if (STREQ("getenv", f, fn)) {
@@ -1013,6 +1006,7 @@ doFoo(MacroBuf mb, int negate, const char * f, size_t fn,
* The main macro recursion loop.
* @param mb macro expansion state
* @param src string to expand
+ * @param slen length of string buffer
* @return 0 on success, 1 on failure
*/
static int
@@ -1025,13 +1019,19 @@ expandMacro(MacroBuf mb, const char *src, size_t slen)
const char *g, *ge;
size_t fn, gn, tpos;
int c;
- int rc = 0;
int negate;
const char * lastc;
int chkexist;
char *source = NULL;
+ int store_macro_trace;
+ int store_expand_trace;
- /* Handle non-terminated substrings by creating a terminated copy */
+ /*
+ * Always make a (terminated) copy of the source string.
+ * Beware: avoiding the copy when src is known \0-terminated seems like
+ * an obvious opportunity for optimization, but doing that breaks
+ * a special case of macro undefining itself.
+ */
if (!slen)
slen = strlen(src);
source = xmalloc(slen + 1);
@@ -1040,36 +1040,41 @@ expandMacro(MacroBuf mb, const char *src, size_t slen)
s = source;
if (mb->buf == NULL) {
- size_t blen = MACROBUFSIZ + strlen(s);
- mb->buf = xcalloc(blen + 1, sizeof(*mb->buf));
+ size_t blen = MACROBUFSIZ + slen;
+ mb->buf = xmalloc(blen + 1);
+ mb->buf[0] = '\0';
mb->tpos = 0;
mb->nb = blen;
}
tpos = mb->tpos; /* save expansion pointer for printExpand */
+ store_macro_trace = mb->macro_trace;
+ store_expand_trace = mb->expand_trace;
if (++mb->depth > max_macro_depth) {
rpmlog(RPMLOG_ERR,
_("Too many levels of recursion in macro expansion. It is likely caused by recursive macro declaration.\n"));
mb->depth--;
mb->expand_trace = 1;
- _free(source);
- return 1;
+ mb->error = 1;
+ goto exit;
}
- while (rc == 0 && (c = *s) != '\0') {
+ while (mb->error == 0 && (c = *s) != '\0') {
s++;
/* Copy text until next macro */
- switch(c) {
+ switch (c) {
case '%':
- if (*s) { /* Ensure not end-of-string. */
- if (*s != '%')
- break;
- s++; /* skip first % in %% */
- }
+ if (*s) { /* Ensure not end-of-string. */
+ if (*s != '%')
+ break;
+ s++; /* skip first % in %% */
+ if (mb->escape)
+ mbAppend(mb, c);
+ }
default:
- mbAppend(mb, c);
- continue;
- break;
+ mbAppend(mb, c);
+ continue;
+ break;
}
/* Expand next macro */
@@ -1082,189 +1087,183 @@ expandMacro(MacroBuf mb, const char *src, size_t slen)
chkexist = 0;
switch ((c = *s)) {
default: /* %name substitution */
- while (strchr("!?", *s) != NULL) {
- switch(*s++) {
- case '!':
- negate = ((negate + 1) % 2);
- break;
- case '?':
- chkexist++;
- break;
- }
- }
- f = se = s;
- if (*se == '-')
- se++;
- while((c = *se) && (risalnum(c) || c == '_'))
- se++;
- /* Recognize non-alnum macros too */
- switch (*se) {
- case '*':
- se++;
- if (*se == '*') se++;
- break;
- case '#':
- se++;
+ while (*s != '\0' && strchr("!?", *s) != NULL) {
+ switch (*s++) {
+ case '!':
+ negate = ((negate + 1) % 2);
break;
- default:
+ case '?':
+ chkexist++;
break;
}
- fe = se;
- /* For "%name " macros ... */
- if ((c = *fe) && isblank(c))
- if ((lastc = strchr(fe,'\n')) == NULL)
- lastc = strchr(fe, '\0');
+ }
+ f = se = s;
+ if (*se == '-')
+ se++;
+ while ((c = *se) && (risalnum(c) || c == '_'))
+ se++;
+ /* Recognize non-alnum macros too */
+ switch (*se) {
+ case '*':
+ se++;
+ if (*se == '*') se++;
break;
+ case '#':
+ se++;
+ break;
+ default:
+ break;
+ }
+ fe = se;
+ /* For "%name " macros ... */
+ if ((c = *fe) && isblank(c))
+ if ((lastc = strchr(fe,'\n')) == NULL)
+ lastc = strchr(fe, '\0');
+ break;
case '(': /* %(...) shell escape */
- if ((se = matchchar(s, c, ')')) == NULL) {
- rpmlog(RPMLOG_ERR,
- _("Unterminated %c: %s\n"), (char)c, s);
- rc = 1;
- continue;
- }
- if (mb->macro_trace)
- printMacro(mb, s, se+1);
+ if ((se = matchchar(s, c, ')')) == NULL) {
+ rpmlog(RPMLOG_ERR, _("Unterminated %c: %s\n"), (char)c, s);
+ mb->error = 1;
+ continue;
+ }
+ if (mb->macro_trace)
+ printMacro(mb, s, se+1);
- s++; /* skip ( */
- rc = doShellEscape(mb, s, (se - s));
- se++; /* skip ) */
+ s++; /* skip ( */
+ doShellEscape(mb, s, (se - s));
+ se++; /* skip ) */
- s = se;
- continue;
- break;
+ s = se;
+ continue;
+ break;
case '{': /* %{...}/%{...:...} substitution */
- if ((se = matchchar(s, c, '}')) == NULL) {
- rpmlog(RPMLOG_ERR,
- _("Unterminated %c: %s\n"), (char)c, s);
- rc = 1;
- continue;
- }
- f = s+1;/* skip { */
- se++; /* skip } */
- while (strchr("!?", *f) != NULL) {
- switch(*f++) {
- case '!':
- negate = ((negate + 1) % 2);
- break;
- case '?':
- chkexist++;
- break;
- }
- }
- for (fe = f; (c = *fe) && !strchr(" :}", c);)
- fe++;
- switch (c) {
- case ':':
- g = fe + 1;
- ge = se - 1;
- break;
- case ' ':
- lastc = se-1;
- break;
- default:
- break;
+ if ((se = matchchar(s, c, '}')) == NULL) {
+ rpmlog(RPMLOG_ERR, _("Unterminated %c: %s\n"), (char)c, s);
+ mb->error = 1;
+ continue;
+ }
+ f = s+1;/* skip { */
+ se++; /* skip } */
+ while (strchr("!?", *f) != NULL) {
+ switch (*f++) {
+ case '!':
+ negate = ((negate + 1) % 2);
+ break;
+ case '?':
+ chkexist++;
+ break;
}
+ }
+ for (fe = f; (c = *fe) && !strchr(" :}", c);)
+ fe++;
+ switch (c) {
+ case ':':
+ g = fe + 1;
+ ge = se - 1;
+ break;
+ case ' ':
+ lastc = se-1;
break;
+ default:
+ break;
+ }
+ break;
}
/* XXX Everything below expects fe > f */
fn = (fe - f);
gn = (ge - g);
if ((fe - f) <= 0) {
-/* XXX Process % in unknown context */
- c = '%'; /* XXX only need to save % */
- mbAppend(mb, c);
+ /* XXX Process % in unknown context */
+ c = '%'; /* XXX only need to save % */
+ mbAppend(mb, c);
#if 0
- rpmlog(RPMLOG_ERR,
- _("A %% is followed by an unparseable macro\n"));
+ rpmlog(RPMLOG_ERR,
+ _("A %% is followed by an unparseable macro\n"));
#endif
- s = se;
- continue;
+ s = se;
+ continue;
}
if (mb->macro_trace)
- printMacro(mb, s, se);
+ printMacro(mb, s, se);
/* Expand builtin macros */
+ if (STREQ("load", f, fn)) {
+ char *arg = NULL;
+ if (g && gn > 0 && expandThis(mb, g, gn, &arg) == 0) {
+ /* Print failure iff %{load:...} or %{!?load:...} */
+ if (loadMacroFile(mb->mc, arg) && chkexist == negate) {
+ rpmlog(RPMLOG_ERR, _("failed to load macro file %s"), arg);
+ mb->error = 1;
+ }
+ }
+ free(arg);
+ s = se;
+ continue;
+ }
if (STREQ("global", f, fn)) {
- s = doDefine(mb, se, RMIL_GLOBAL, 1);
- continue;
+ s = doDefine(mb, se, slen - (se - s), RMIL_GLOBAL, 1);
+ continue;
}
if (STREQ("define", f, fn)) {
- s = doDefine(mb, se, mb->depth, 0);
- continue;
+ s = doDefine(mb, se, slen - (se - s), mb->level, 0);
+ continue;
}
if (STREQ("undefine", f, fn)) {
- s = doUndefine(mb->mc, se);
- continue;
+ s = doUndefine(mb, se, slen - (se - s));
+ continue;
}
if (STREQ("echo", f, fn) ||
- STREQ("warn", f, fn) ||
- STREQ("error", f, fn)) {
- int waserror = 0;
- if (STREQ("error", f, fn))
- waserror = 1;
- if (g != NULL && g < ge)
- doOutput(mb, waserror, g, gn);
- else
- doOutput(mb, waserror, f, fn);
- s = se;
- continue;
+ STREQ("warn", f, fn) ||
+ STREQ("error", f, fn)) {
+ int loglevel = RPMLOG_NOTICE; /* assume echo */
+ if (STREQ("error", f, fn)) {
+ loglevel = RPMLOG_ERR;
+ mb->error = 1;
+ } else if (STREQ("warn", f, fn)) {
+ loglevel = RPMLOG_WARNING;
+ }
+ if (g != NULL && g < ge)
+ doOutput(mb, loglevel, g, gn);
+ else
+ doOutput(mb, loglevel, "", 0);
+ s = se;
+ continue;
}
if (STREQ("trace", f, fn)) {
- /* XXX TODO restore expand_trace/macro_trace to 0 on return */
- mb->expand_trace = mb->macro_trace = (negate ? 0 : mb->depth);
- if (mb->depth == 1) {
- print_macro_trace = mb->macro_trace;
- print_expand_trace = mb->expand_trace;
- }
- s = se;
- continue;
+ /* XXX TODO restore expand_trace/macro_trace to 0 on return */
+ mb->expand_trace = mb->macro_trace = (negate ? 0 : mb->depth);
+ if (mb->depth == 1) {
+ print_macro_trace = mb->macro_trace;
+ print_expand_trace = mb->expand_trace;
+ }
+ s = se;
+ continue;
}
if (STREQ("dump", f, fn)) {
- rpmDumpMacroTable(mb->mc, NULL);
- while (iseol(*se))
- se++;
- s = se;
- continue;
+ rpmDumpMacroTable(mb->mc, NULL);
+ while (iseol(*se))
+ se++;
+ s = se;
+ continue;
}
-#ifdef WITH_LUA
-#define LUA_FAILURE_OUTPUT "1"
if (STREQ("lua", f, fn)) {
- rpmlua lua = NULL; /* Global state. */
- const char *ls = s+sizeof("{lua:")-1;
- const char *lse = se-sizeof("}")+1;
- char *scriptbuf = (char *)xmalloc((lse-ls)+1);
- char *printbuf;
- memcpy(scriptbuf, ls, lse-ls);
- scriptbuf[lse-ls] = '\0';
- rpmluaPushPrintBuffer(lua);
- if (rpmluaRunScript(lua, scriptbuf, NULL) == -1) {
- printbuf = rpmluaPopPrintBuffer(lua);
- rpmlog(RPMLOG_WARNING, _("lua: using fallback output '%s'\n"), LUA_FAILURE_OUTPUT);
- printbuf = (char *)xcalloc(1, sizeof(LUA_FAILURE_OUTPUT));
- strcpy(printbuf, LUA_FAILURE_OUTPUT);
- } else {
- printbuf = rpmluaPopPrintBuffer(lua);
- }
- if (printbuf) {
- mbAppendStr(mb, printbuf);
- free(printbuf);
- }
- free(scriptbuf);
- s = se;
- continue;
+ doLua(mb, f, fn, g, gn);
+ s = se;
+ continue;
}
-#endif
/* XXX necessary but clunky */
if (STREQ("basename", f, fn) ||
STREQ("dirname", f, fn) ||
+ STREQ("shrink", f, fn) ||
STREQ("suffix", f, fn) ||
+ STREQ("quote", f, fn) ||
STREQ("expand", f, fn) ||
STREQ("verbose", f, fn) ||
STREQ("uncompress", f, fn) ||
@@ -1274,110 +1273,116 @@ expandMacro(MacroBuf mb, const char *src, size_t slen)
STREQ("getconfdir", f, fn) ||
STREQ("S", f, fn) ||
STREQ("P", f, fn) ||
- STREQ("F", f, fn)) {
- /* FIX: verbose may be set */
- doFoo(mb, negate, f, fn, g, gn);
- s = se;
- continue;
+ STREQ("F", f, fn))
+ {
+ /* FIX: verbose may be set */
+ doFoo(mb, negate, f, fn, g, gn);
+ s = se;
+ continue;
}
/* Expand defined macros */
- mep = findEntry(mb->mc, f, fn);
+ mep = findEntry(mb->mc, f, fn, NULL);
me = (mep ? *mep : NULL);
+ if (me) {
+ if ((me->flags & ME_AUTO) && mb->level > me->level) {
+ /* Ignore out-of-scope automatic macros */
+ me = NULL;
+ } else {
+ /* If we looked up a macro, consider it used */
+ me->flags |= ME_USED;
+ }
+ }
+
/* XXX Special processing for flags */
if (*f == '-') {
- if (me)
- me->used++; /* Mark macro as used */
- if ((me == NULL && !negate) || /* Without -f, skip %{-f...} */
+ if ((me == NULL && !negate) || /* Without -f, skip %{-f...} */
(me != NULL && negate)) { /* With -f, skip %{!-f...} */
- s = se;
- continue;
- }
+ s = se;
+ continue;
+ }
- if (g && g < ge) { /* Expand X in %{-f:X} */
- rc = expandMacro(mb, g, gn);
- } else
+ if (g && g < ge) { /* Expand X in %{-f:X} */
+ expandMacro(mb, g, gn);
+ } else
if (me && me->body && *me->body) {/* Expand %{-f}/%{-f*} */
- rc = expandMacro(mb, me->body, 0);
+ expandMacro(mb, me->body, 0);
}
- s = se;
- continue;
+ s = se;
+ continue;
}
/* XXX Special processing for macro existence */
if (chkexist) {
- if ((me == NULL && !negate) || /* Without -f, skip %{?f...} */
+ if ((me == NULL && !negate) || /* Without -f, skip %{?f...} */
(me != NULL && negate)) { /* With -f, skip %{!?f...} */
- s = se;
- continue;
- }
- if (g && g < ge) { /* Expand X in %{?f:X} */
- rc = expandMacro(mb, g, gn);
- } else
- if (me && me->body && *me->body) { /* Expand %{?f}/%{?f*} */
- rc = expandMacro(mb, me->body, 0);
- }
s = se;
continue;
+ }
+ if (g && g < ge) { /* Expand X in %{?f:X} */
+ expandMacro(mb, g, gn);
+ } else
+ if (me && me->body && *me->body) { /* Expand %{?f}/%{?f*} */
+ expandMacro(mb, me->body, 0);
+ }
+ s = se;
+ continue;
}
if (me == NULL) { /* leave unknown %... as is */
- /* XXX hack to permit non-overloaded %foo to be passed */
- c = '%'; /* XXX only need to save % */
- mbAppend(mb, c);
- continue;
+ /* XXX hack to permit non-overloaded %foo to be passed */
+ c = '%'; /* XXX only need to save % */
+ mbAppend(mb, c);
+ continue;
}
/* Setup args for "%name " macros with opts */
if (me && me->opts != NULL) {
- if (lastc != NULL) {
- se = grabArgs(mb, me, fe, lastc);
- } else {
- addMacro(mb->mc, "**", NULL, "", mb->depth);
- addMacro(mb->mc, "*", NULL, "", mb->depth);
- addMacro(mb->mc, "#", NULL, "0", mb->depth);
- addMacro(mb->mc, "0", NULL, me->name, mb->depth);
- }
+ const char *xe = grabArgs(mb, me, fe, lastc);
+ if (xe != NULL)
+ se = xe;
}
/* Recursively expand body of macro */
if (me->body && *me->body) {
- rc = expandMacro(mb, me->body, 0);
- if (rc == 0)
- me->used++; /* Mark macro as used */
+ expandMacro(mb, me->body, 0);
}
/* Free args for "%name " macros with opts */
if (me->opts != NULL)
- freeArgs(mb);
+ freeArgs(mb);
s = se;
}
mb->buf[mb->tpos] = '\0';
mb->depth--;
- if (rc != 0 || mb->expand_trace)
+ if (mb->error != 0 || mb->expand_trace)
printExpansion(mb, mb->buf+tpos, mb->buf+mb->tpos);
+ mb->macro_trace = store_macro_trace;
+ mb->expand_trace = store_expand_trace;
+exit:
_free(source);
- return rc;
+ return mb->error;
}
/* =============================================================== */
-static int doExpandMacros(rpmMacroContext mc, const char *src, char **target)
+static int doExpandMacros(rpmMacroContext mc, const char *src, int flags,
+ char **target)
{
MacroBuf mb = xcalloc(1, sizeof(*mb));
int rc = 0;
- if (mc == NULL) mc = rpmGlobalMacroContext;
-
mb->buf = NULL;
- mb->depth = 0;
+ mb->depth = mc->depth;
+ mb->level = mc->level;
mb->macro_trace = print_macro_trace;
mb->expand_trace = print_expand_trace;
mb->mc = mc;
+ mb->flags = flags;
rc = expandMacro(mb, src, 0);
@@ -1389,91 +1394,111 @@ static int doExpandMacros(rpmMacroContext mc, const char *src, char **target)
return rc;
}
-int expandMacros(void * spec, rpmMacroContext mc, char * sbuf, size_t slen)
+static void pushMacro(rpmMacroContext mc,
+ const char * n, const char * o, const char * b, int level, int flags)
{
- char *target = NULL;
- int rc = doExpandMacros(mc, sbuf, &target);
- rstrlcpy(sbuf, target, slen);
- free(target);
- return rc;
-}
-
-void
-addMacro(rpmMacroContext mc,
- const char * n, const char * o, const char * b, int level)
-{
- rpmMacroEntry * mep;
-
- if (mc == NULL) mc = rpmGlobalMacroContext;
-
- /* If new name, expand macro table */
- if ((mep = findEntry(mc, n, 0)) == NULL) {
- if (mc->firstFree == mc->macrosAllocated)
- expandMacroTable(mc);
- if (mc->macroTable != NULL)
- mep = mc->macroTable + mc->firstFree++;
+ /* new entry */
+ rpmMacroEntry me;
+ /* pointer into me */
+ char *p;
+ /* calculate sizes */
+ size_t olen = o ? strlen(o) : 0;
+ size_t blen = b ? strlen(b) : 0;
+ size_t mesize = sizeof(*me) + blen + 1 + (olen ? olen + 1 : 0);
+
+ size_t pos;
+ rpmMacroEntry *mep = findEntry(mc, n, 0, &pos);
+ if (mep) {
+ /* entry with shared name */
+ me = xmalloc(mesize);
+ /* copy body */
+ me->body = p = me->arena;
+ if (blen)
+ memcpy(p, b, blen + 1);
+ else
+ *p = '\0';
+ p += blen + 1;
+ /* set name */
+ me->name = (*mep)->name;
}
-
- if (mep != NULL) {
- /* Push macro over previous definition */
- pushMacro(mep, n, o, b, level);
-
- /* If new name, sort macro table */
- if ((*mep)->prev == NULL)
- sortMacroTable(mc);
+ else {
+ /* extend macro table */
+ const int delta = 256;
+ if (mc->n % delta == 0)
+ mc->tab = xrealloc(mc->tab, sizeof(me) * (mc->n + delta));
+ /* shift pos+ entries to the right */
+ memmove(mc->tab + pos + 1, mc->tab + pos, sizeof(me) * (mc->n - pos));
+ mc->n++;
+ /* make slot */
+ mc->tab[pos] = NULL;
+ mep = &mc->tab[pos];
+ /* entry with new name */
+ size_t nlen = strlen(n);
+ me = xmalloc(mesize + nlen + 1);
+ /* copy body */
+ me->body = p = me->arena;
+ if (blen)
+ memcpy(p, b, blen + 1);
+ else
+ *p = '\0';
+ p += blen + 1;
+ /* copy name */
+ me->name = memcpy(p, n, nlen + 1);
+ p += nlen + 1;
}
+
+ /* copy options */
+ if (olen)
+ me->opts = memcpy(p, o, olen + 1);
+ else
+ me->opts = o ? "" : NULL;
+ /* initialize */
+ me->flags = flags;
+ me->flags &= ~(ME_USED);
+ me->level = level;
+ /* push over previous definition */
+ me->prev = *mep;
+ *mep = me;
}
-void
-delMacro(rpmMacroContext mc, const char * n)
+static void popMacro(rpmMacroContext mc, const char * n)
{
- rpmMacroEntry * mep;
-
- if (mc == NULL) mc = rpmGlobalMacroContext;
- /* If name exists, pop entry */
- if ((mep = findEntry(mc, n, 0)) != NULL) {
- popMacro(mep);
- /* If deleted name, sort macro table */
- if (!(mep && *mep))
- sortMacroTable(mc);
+ size_t pos;
+ rpmMacroEntry *mep = findEntry(mc, n, 0, &pos);
+ if (mep == NULL)
+ return;
+ /* parting entry */
+ rpmMacroEntry me = *mep;
+ assert(me);
+ /* detach/pop definition */
+ mc->tab[pos] = me->prev;
+ /* shrink macro table */
+ if (me->prev == NULL) {
+ mc->n--;
+ /* move pos+ elements to the left */
+ memmove(mc->tab + pos, mc->tab + pos + 1, sizeof(me) * (mc->n - pos));
+ /* deallocate */
+ if (mc->n == 0)
+ mc->tab = _free(mc->tab);
}
+ /* comes in a single chunk */
+ free(me);
}
-int
-rpmDefineMacro(rpmMacroContext mc, const char * macro, int level)
+static int defineMacro(rpmMacroContext mc, const char * macro, int level)
{
MacroBuf mb = xcalloc(1, sizeof(*mb));
+ int rc;
/* XXX just enough to get by */
- mb->mc = (mc ? mc : rpmGlobalMacroContext);
- (void) doDefine(mb, macro, level, 0);
+ mb->mc = mc;
+ (void) doDefine(mb, macro, strlen(macro), level, 0);
+ rc = mb->error;
_free(mb);
- return 0;
-}
-
-void
-rpmLoadMacros(rpmMacroContext mc, int level)
-{
-
- if (mc == NULL || mc == rpmGlobalMacroContext)
- return;
-
- if (mc->macroTable != NULL) {
- int i;
- for (i = 0; i < mc->firstFree; i++) {
- rpmMacroEntry *mep, me;
- mep = &mc->macroTable[i];
- me = *mep;
-
- if (me == NULL) /* XXX this should never happen */
- continue;
- addMacro(NULL, me->name, me->opts, me->body, (level - 1));
- }
- }
+ return rc;
}
-int
-rpmLoadMacroFile(rpmMacroContext mc, const char * fn)
+static int loadMacroFile(rpmMacroContext mc, const char * fn)
{
FILE *fd = fopen(fn, "r");
size_t blen = MACROBUFSIZ;
@@ -1483,11 +1508,8 @@ rpmLoadMacroFile(rpmMacroContext mc, const char * fn)
if (fd == NULL)
goto exit;
- /* XXX Assume new fangled macro expansion */
- max_macro_depth = 16;
-
buf[0] = '\0';
- while(rdcl(buf, blen, fd) != NULL) {
+ while (rdcl(buf, blen, fd) != NULL) {
char c, *n;
n = buf;
@@ -1496,8 +1518,9 @@ rpmLoadMacroFile(rpmMacroContext mc, const char * fn)
if (c != '%')
continue;
n++; /* skip % */
- rc = rpmDefineMacro(mc, n, RMIL_MACROFILES);
+ rc = defineMacro(mc, n, RMIL_MACROFILES);
}
+
rc = fclose(fd);
exit:
@@ -1505,15 +1528,124 @@ exit:
return rc;
}
+static void copyMacros(rpmMacroContext src, rpmMacroContext dst, int level)
+{
+ for (int i = 0; i < src->n; i++) {
+ rpmMacroEntry me = src->tab[i];
+ assert(me);
+ pushMacro(dst, me->name, me->opts, me->body, level, me->flags);
+ }
+}
+
+/* External interfaces */
+
+int rpmExpandMacros(rpmMacroContext mc, const char * sbuf, char ** obuf, int flags)
+{
+ char *target = NULL;
+ int rc;
+
+ mc = rpmmctxAcquire(mc);
+ rc = doExpandMacros(mc, sbuf, flags, &target);
+ rpmmctxRelease(mc);
+
+ if (rc) {
+ free(target);
+ return -1;
+ } else {
+ *obuf = target;
+ return 1;
+ }
+}
+
+void
+rpmDumpMacroTable(rpmMacroContext mc, FILE * fp)
+{
+ mc = rpmmctxAcquire(mc);
+ if (fp == NULL) fp = stderr;
+
+ fprintf(fp, "========================\n");
+ for (int i = 0; i < mc->n; i++) {
+ rpmMacroEntry me = mc->tab[i];
+ assert(me);
+ fprintf(fp, "%3d%c %s", me->level,
+ ((me->flags & ME_USED) ? '=' : ':'), me->name);
+ if (me->opts && *me->opts)
+ fprintf(fp, "(%s)", me->opts);
+ if (me->body && *me->body)
+ fprintf(fp, "\t%s", me->body);
+ fprintf(fp, "\n");
+ }
+ fprintf(fp, _("======================== active %d empty %d\n"),
+ mc->n, 0);
+ rpmmctxRelease(mc);
+}
+
+int rpmPushMacro(rpmMacroContext mc,
+ const char * n, const char * o, const char * b, int level)
+{
+ mc = rpmmctxAcquire(mc);
+ pushMacro(mc, n, o, b, level, ME_NONE);
+ rpmmctxRelease(mc);
+ return 0;
+}
+
+int rpmPopMacro(rpmMacroContext mc, const char * n)
+{
+ mc = rpmmctxAcquire(mc);
+ popMacro(mc, n);
+ rpmmctxRelease(mc);
+ return 0;
+}
+
+int
+rpmDefineMacro(rpmMacroContext mc, const char * macro, int level)
+{
+ int rc;
+ mc = rpmmctxAcquire(mc);
+ rc = defineMacro(mc, macro, level);
+ rpmmctxRelease(mc);
+ return rc;
+}
+
+void
+rpmLoadMacros(rpmMacroContext mc, int level)
+{
+ rpmMacroContext gmc;
+ if (mc == NULL || mc == rpmGlobalMacroContext)
+ return;
+
+ gmc = rpmmctxAcquire(NULL);
+ mc = rpmmctxAcquire(mc);
+
+ copyMacros(mc, gmc, level);
+
+ rpmmctxRelease(mc);
+ rpmmctxRelease(gmc);
+}
+
+int
+rpmLoadMacroFile(rpmMacroContext mc, const char * fn)
+{
+ int rc;
+
+ mc = rpmmctxAcquire(mc);
+ rc = loadMacroFile(mc, fn);
+ rpmmctxRelease(mc);
+
+ return rc;
+}
+
void
rpmInitMacros(rpmMacroContext mc, const char * macrofiles)
{
ARGV_t pattern, globs = NULL;
+ rpmMacroContext climc;
if (macrofiles == NULL)
return;
argvSplit(&globs, macrofiles, ":");
+ mc = rpmmctxAcquire(mc);
for (pattern = globs; *pattern; pattern++) {
ARGV_t path, files = NULL;
@@ -1529,31 +1661,30 @@ rpmInitMacros(rpmMacroContext mc, const char * macrofiles)
rpmFileHasSuffix(*path, ".rpmorig")) {
continue;
}
- (void) rpmLoadMacroFile(mc, *path);
+ (void) loadMacroFile(mc, *path);
}
argvFree(files);
}
argvFree(globs);
/* Reload cmdline macros */
- rpmLoadMacros(rpmCLIMacroContext, RMIL_CMDLINE);
+ climc = rpmmctxAcquire(rpmCLIMacroContext);
+ copyMacros(climc, mc, RMIL_CMDLINE);
+ rpmmctxRelease(climc);
+
+ rpmmctxRelease(mc);
}
void
rpmFreeMacros(rpmMacroContext mc)
{
-
- if (mc == NULL) mc = rpmGlobalMacroContext;
-
- if (mc->macroTable != NULL) {
- for (int i = 0; i < mc->firstFree; i++) {
- while (mc->macroTable[i] != NULL) {
- popMacro(&mc->macroTable[i]);
- }
- }
- free(mc->macroTable);
+ mc = rpmmctxAcquire(mc);
+ while (mc->n > 0) {
+ /* remove from the end to avoid memmove */
+ rpmMacroEntry me = mc->tab[mc->n - 1];
+ popMacro(mc, me->name);
}
- memset(mc, 0, sizeof(*mc));
+ rpmmctxRelease(mc);
}
char *
@@ -1564,6 +1695,7 @@ rpmExpand(const char *arg, ...)
char *pe;
const char *s;
va_list ap;
+ rpmMacroContext mc;
if (arg == NULL) {
ret = xstrdup("");
@@ -1584,7 +1716,9 @@ rpmExpand(const char *arg, ...)
pe = stpcpy(pe, s);
va_end(ap);
- (void) doExpandMacros(NULL, buf, &ret);
+ mc = rpmmctxAcquire(NULL);
+ (void) doExpandMacros(mc, buf, 0, &ret);
+ rpmmctxRelease(mc);
free(buf);
exit:
diff --git a/rpmio/rpmbase64.h b/rpmio/rpmbase64.h
index 95ee9cd03..3858cc331 100644
--- a/rpmio/rpmbase64.h
+++ b/rpmio/rpmbase64.h
@@ -1,6 +1,12 @@
/* base64 encoder/decoder based on public domain implementation
* by Chris Venter */
+/** \ingroup rpmio
+ * \file rpmio/rpmbase64.h
+ *
+ * Base64 encoding and decoding API
+ */
+
#include <sys/types.h>
#ifdef __cplusplus
diff --git a/rpmio/rpmfileutil.c b/rpmio/rpmfileutil.c
index 6cdfe2552..9e47ff8a5 100644
--- a/rpmio/rpmfileutil.c
+++ b/rpmio/rpmfileutil.c
@@ -19,6 +19,7 @@
#include <errno.h>
#include <popt.h>
#include <ctype.h>
+#include <pthread.h>
#include <rpm/rpmfileutil.h>
#include <rpm/rpmurl.h>
@@ -31,6 +32,7 @@
#include "debug.h"
static const char *rpm_config_dir = NULL;
+static pthread_once_t configDirSet = PTHREAD_ONCE_INIT;
static int is_prelinked(int fdno)
{
@@ -103,28 +105,38 @@ static int open_dso(const char * path, pid_t * pidp, rpm_loff_t *fsizep)
if (pidp != NULL && is_prelinked(fdno)) {
int pipes[2];
pid_t pid;
- int xx;
- xx = close(fdno);
+ close(fdno);
pipes[0] = pipes[1] = -1;
- xx = pipe(pipes);
- if (!(pid = fork())) {
+ if (pipe(pipes) < 0)
+ return -1;
+
+ pid = fork();
+ if (pid < 0) {
+ close(pipes[0]);
+ close(pipes[1]);
+ return -1;
+ }
+
+ if (pid == 0) {
ARGV_t av, lib;
+ int dfd;
argvSplit(&av, cmd, " ");
- xx = close(pipes[0]);
- xx = dup2(pipes[1], STDOUT_FILENO);
- xx = close(pipes[1]);
- if ((lib = argvSearch(av, "library", NULL)) != NULL) {
+ close(pipes[0]);
+ dfd = dup2(pipes[1], STDOUT_FILENO);
+ close(pipes[1]);
+ if (dfd >= 0 && (lib = argvSearch(av, "library", NULL)) != NULL) {
*lib = (char *) path;
unsetenv("MALLOC_CHECK_");
- xx = execve(av[0], av+1, environ);
+ execve(av[0], av+1, environ);
}
- _exit(127);
+ _exit(127); /* not normally reached */
+ } else {
+ *pidp = pid;
+ fdno = pipes[0];
+ close(pipes[1]);
}
- *pidp = pid;
- fdno = pipes[0];
- xx = close(pipes[1]);
}
return fdno;
@@ -136,8 +148,8 @@ int rpmDoDigest(int algo, const char * fn,int asAscii,
const char * path;
urltype ut = urlPath(fn, &path);
unsigned char * dig = NULL;
- size_t diglen;
- unsigned char buf[32*BUFSIZ];
+ size_t diglen, buflen = 32 * BUFSIZ;
+ unsigned char *buf = xmalloc(buflen);
FD_t fd;
rpm_loff_t fsize = 0;
pid_t pid = 0;
@@ -150,7 +162,7 @@ int rpmDoDigest(int algo, const char * fn,int asAscii,
goto exit;
}
- switch(ut) {
+ switch (ut) {
case URL_IS_PATH:
case URL_IS_UNKNOWN:
case URL_IS_HTTPS:
@@ -171,10 +183,10 @@ int rpmDoDigest(int algo, const char * fn,int asAscii,
fdInitDigest(fd, algo, 0);
fsize = 0;
- while ((rc = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0)
+ while ((rc = Fread(buf, sizeof(*buf), buflen, fd)) > 0)
fsize += rc;
fdFiniDigest(fd, algo, (void **)&dig, &diglen, asAscii);
- if (Ferror(fd))
+ if (dig == NULL || Ferror(fd))
rc = 1;
(void) Fclose(fd);
@@ -195,6 +207,7 @@ exit:
if (!rc)
memcpy(digest, dig, diglen);
dig = _free(dig);
+ free(buf);
return rc;
}
@@ -326,7 +339,8 @@ int rpmFileIsCompressed(const char * file, rpmCompressedMagic * compressed)
rc = 0;
- if ((magic[0] == 'B') && (magic[1] == 'Z')) {
+ if ((magic[0] == 'B') && (magic[1] == 'Z') &&
+ (magic[2] == 'h')) {
*compressed = COMPRESSED_BZIP2;
} else if ((magic[0] == 'P') && (magic[1] == 'K') &&
(((magic[2] == 3) && (magic[3] == 4)) ||
@@ -337,6 +351,9 @@ int rpmFileIsCompressed(const char * file, rpmCompressedMagic * compressed)
(magic[4] == 0x5a) && (magic[5] == 0x00)) {
/* new style xz (lzma) with magic */
*compressed = COMPRESSED_XZ;
+ } else if ((magic[0] == 0x28) && (magic[1] == 0x85) &&
+ (magic[2] == 0x2f) ) {
+ *compressed = COMPRESSED_ZSTD;
} else if ((magic[0] == 'L') && (magic[1] == 'Z') &&
(magic[2] == 'I') && (magic[3] == 'P')) {
*compressed = COMPRESSED_LZIP;
@@ -356,6 +373,8 @@ int rpmFileIsCompressed(const char * file, rpmCompressedMagic * compressed)
*compressed = COMPRESSED_7ZIP;
} else if (rpmFileHasSuffix(file, ".lzma")) {
*compressed = COMPRESSED_LZMA;
+ } else if (rpmFileHasSuffix(file, ".gem")) {
+ *compressed = COMPRESSED_GEM;
}
return rc;
@@ -375,7 +394,7 @@ char *rpmCleanPath(char * path)
s = t = te = path;
while (*s != '\0') {
/*fprintf(stderr, "*** got \"%.*s\"\trest \"%s\"\n", (t-path), path, s); */
- switch(*s) {
+ switch (*s) {
case ':': /* handle url's */
if (s[1] == '/' && s[2] == '/') {
*t++ = *s++;
@@ -599,11 +618,14 @@ int rpmMkdirs(const char *root, const char *pathstr)
return rc;
}
+static void setConfigDir(void)
+{
+ char *rpmenv = getenv("RPM_CONFIGDIR");
+ rpm_config_dir = rpmenv ? xstrdup(rpmenv) : RPMCONFIGDIR;
+}
+
const char *rpmConfigDir(void)
{
- if (rpm_config_dir == NULL) {
- char *rpmenv = getenv("RPM_CONFIGDIR");
- rpm_config_dir = rpmenv ? xstrdup(rpmenv) : RPMCONFIGDIR;
- }
+ pthread_once(&configDirSet, setConfigDir);
return rpm_config_dir;
}
diff --git a/rpmio/rpmfileutil.h b/rpmio/rpmfileutil.h
index 79fac8699..916f6b240 100644
--- a/rpmio/rpmfileutil.h
+++ b/rpmio/rpmfileutil.h
@@ -26,7 +26,9 @@ typedef enum rpmCompressedMagic_e {
COMPRESSED_XZ = 5, /*!< xz can handle */
COMPRESSED_LZIP = 6, /*!< lzip can handle */
COMPRESSED_LRZIP = 7, /*!< lrzip can handle */
- COMPRESSED_7ZIP = 8 /*!< 7zip can handle */
+ COMPRESSED_7ZIP = 8, /*!< 7zip can handle */
+ COMPRESSED_GEM = 9, /*!< gem can handle */
+ COMPRESSED_ZSTD = 10 /*!< zstd can handle */
} rpmCompressedMagic;
/** \ingroup rpmfileutil
diff --git a/rpmio/rpmglob.c b/rpmio/rpmglob.c
index 4fc106daf..da5493d75 100644
--- a/rpmio/rpmglob.c
+++ b/rpmio/rpmglob.c
@@ -124,30 +124,15 @@ static inline const char *next_brace_sub(const char *begin)
unsigned int depth = 0;
const char *cp = begin;
- while (1) {
- if (depth == 0) {
- if (*cp != ',' && *cp != '}' && *cp != '\0') {
- if (*cp == '{')
- ++depth;
- ++cp;
- continue;
- }
- } else {
- while (*cp != '\0' && (*cp != '}' || depth > 0)) {
- if (*cp == '}')
- --depth;
- ++cp;
- }
- if (*cp == '\0')
- /* An incorrectly terminated brace expression. */
- return NULL;
+ while (*cp != '\0') {
+ if ((*cp == '}' && depth-- == 0) || (*cp == ',' && depth == 0))
+ break;
- continue;
- }
- break;
+ if (*cp++ == '{')
+ depth++;
}
- return cp;
+ return *cp != '\0' ? cp : NULL;
}
static int __glob_pattern_p(const char *pattern, int quote);
@@ -352,7 +337,7 @@ glob(const char *pattern, int flags,
user_name = dirname + 1;
else {
char *newp;
- newp = (char *) alloca(end_name - dirname);
+ newp = (char *) alloca(end_name - dirname + 1);
*((char *) mempcpy(newp, dirname + 1, end_name - dirname))
= '\0';
user_name = newp;
@@ -649,7 +634,7 @@ static int prefix_array(const char *dirname, char **array, size_t n)
static int __glob_pattern_p(const char *pattern, int quote)
{
register const char *p;
- int open = 0;
+ int openBrackets = 0;
for (p = pattern; *p != '\0'; ++p)
switch (*p) {
@@ -663,11 +648,11 @@ static int __glob_pattern_p(const char *pattern, int quote)
break;
case '[':
- open = 1;
+ openBrackets = 1;
break;
case ']':
- if (open)
+ if (openBrackets)
return 1;
break;
}
@@ -844,6 +829,8 @@ int rpmGlob(const char * patterns, int * argcPtr, ARGV_t * argvPtr)
int i, j;
int rc;
+ gflags |= GLOB_BRACE;
+
if (home != NULL && strlen(home) > 0)
gflags |= GLOB_TILDE;
@@ -966,5 +953,32 @@ exit:
int rpmIsGlob(const char * pattern, int quote)
{
- return __glob_pattern_p(pattern, quote);
+ if (!__glob_pattern_p(pattern, quote)) {
+
+ const char *begin;
+ const char *next;
+ const char *rest;
+
+ begin = strchr(pattern, '{');
+ if (begin == NULL)
+ return 0;
+ /*
+ * Find the first sub-pattern and at the same time find the
+ * rest after the closing brace.
+ */
+ next = next_brace_sub(begin + 1);
+ if (next == NULL)
+ return 0;
+
+ /* Now find the end of the whole brace expression. */
+ rest = next;
+ while (*rest != '}') {
+ rest = next_brace_sub(rest + 1);
+ if (rest == NULL)
+ return 0;
+ }
+ /* Now we can be sure that brace expression is well-foermed. */
+ }
+
+ return 1;
}
diff --git a/rpmio/rpmio.c b/rpmio/rpmio.c
index cd223e829..57df81a9d 100644
--- a/rpmio/rpmio.c
+++ b/rpmio/rpmio.c
@@ -5,6 +5,11 @@
#include "system.h"
#include <stdarg.h>
#include <errno.h>
+#include <ctype.h>
+#if defined(__linux__)
+#include <sys/personality.h>
+#endif
+#include <sys/utsname.h>
#include <rpm/rpmlog.h>
#include <rpm/rpmmacro.h>
@@ -16,11 +21,17 @@
#include "debug.h"
-typedef struct _FDSTACK_s {
+typedef struct FDSTACK_s * FDSTACK_t;
+
+struct FDSTACK_s {
FDIO_t io;
void * fp;
int fdno;
-} FDSTACK_t;
+ int syserrno; /* last system errno encountered */
+ const char *errcookie; /* pointer to custom error string */
+
+ FDSTACK_t prev;
+};
/** \ingroup rpmio
* Cumulative statistics for a descriptor.
@@ -38,13 +49,9 @@ struct _FD_s {
#define RPMIO_DEBUG_IO 0x40000000
int magic;
#define FDMAGIC 0x04463138
- int nfps;
- FDSTACK_t fps[8];
+ FDSTACK_t fps;
int urlType; /* ufdio: */
- int syserrno; /* last system errno encountered */
- const char *errcookie; /* gzdio/bzdio/ufdio/xzdio: */
-
char *descr; /* file name (or other description) */
FDSTAT_t stats; /* I/O statistics */
@@ -57,51 +64,37 @@ struct _FD_s {
#define DBGIO(_f, _x) DBG((_f), RPMIO_DEBUG_IO, _x)
-static FDIO_t fdGetIo(FD_t fd)
-{
- return (fd != NULL) ? fd->fps[fd->nfps].io : NULL;
-}
-
-static void fdSetIo(FD_t fd, FDIO_t io)
-{
- if (fd)
- fd->fps[fd->nfps].io = io;
-}
-
-static void * fdGetFp(FD_t fd)
-{
- return (fd != NULL) ? fd->fps[fd->nfps].fp : NULL;
-}
-
-static void fdSetFp(FD_t fd, void * fp)
+static FDSTACK_t fdGetFps(FD_t fd)
{
- if (fd)
- fd->fps[fd->nfps].fp = fp;
+ return (fd != NULL) ? fd->fps : NULL;
}
static void fdSetFdno(FD_t fd, int fdno)
{
if (fd)
- fd->fps[fd->nfps].fdno = fdno;
+ fd->fps->fdno = fdno;
}
static void fdPush(FD_t fd, FDIO_t io, void * fp, int fdno)
{
- if (fd == NULL || fd->nfps >= (sizeof(fd->fps)/sizeof(fd->fps[0]) - 1))
- return;
- fd->nfps++;
- fdSetIo(fd, io);
- fdSetFp(fd, fp);
- fdSetFdno(fd, fdno);
+ FDSTACK_t fps = xcalloc(1, sizeof(*fps));
+ fps->io = io;
+ fps->fp = fp;
+ fps->fdno = fdno;
+ fps->prev = fd->fps;
+
+ fd->fps = fps;
+ fdLink(fd);
}
-static void fdPop(FD_t fd)
+static FDSTACK_t fdPop(FD_t fd)
{
- if (fd == NULL || fd->nfps < 0) return;
- fdSetIo(fd, NULL);
- fdSetFp(fd, NULL);
- fdSetFdno(fd, -1);
- fd->nfps--;
+ FDSTACK_t fps = fd->fps;
+ fd->fps = fps->prev;
+ free(fps);
+ fps = fd->fps;
+ fdFree(fd);
+ return fps;
}
void fdSetBundle(FD_t fd, rpmDigestBundle bundle)
@@ -110,77 +103,67 @@ void fdSetBundle(FD_t fd, rpmDigestBundle bundle)
fd->digests = bundle;
}
-rpmDigestBundle fdGetBundle(FD_t fd)
-{
- return (fd != NULL) ? fd->digests : NULL;
-}
-
-static void * iotFileno(FD_t fd, FDIO_t iot)
+rpmDigestBundle fdGetBundle(FD_t fd, int create)
{
- void * rc = NULL;
-
- if (fd == NULL)
- return NULL;
-
- for (int i = fd->nfps; i >= 0; i--) {
- FDSTACK_t * fps = &fd->fps[i];
- if (fps->io != iot)
- continue;
- rc = fps->fp;
- break;
+ rpmDigestBundle bundle = NULL;
+ if (fd) {
+ if (fd->digests == NULL && create)
+ fd->digests = rpmDigestBundleNew();
+ bundle = fd->digests;
}
-
- return rc;
+ return bundle;
}
/** \ingroup rpmio
* \name RPMIO Vectors.
*/
-typedef ssize_t (*fdio_read_function_t) (FD_t fd, void *buf, size_t nbytes);
-typedef ssize_t (*fdio_write_function_t) (FD_t fd, const void *buf, size_t nbytes);
-typedef int (*fdio_seek_function_t) (FD_t fd, off_t pos, int whence);
-typedef int (*fdio_close_function_t) (FD_t fd);
-typedef FD_t (*fdio_ref_function_t) (FD_t fd);
-typedef FD_t (*fdio_deref_function_t) (FD_t fd);
-typedef FD_t (*fdio_new_function_t) (const char *descr);
-typedef int (*fdio_fileno_function_t) (FD_t fd);
+typedef ssize_t (*fdio_read_function_t) (FDSTACK_t fps, void *buf, size_t nbytes);
+typedef ssize_t (*fdio_write_function_t) (FDSTACK_t fps, const void *buf, size_t nbytes);
+typedef int (*fdio_seek_function_t) (FDSTACK_t fps, off_t pos, int whence);
+typedef int (*fdio_close_function_t) (FDSTACK_t fps);
typedef FD_t (*fdio_open_function_t) (const char * path, int flags, mode_t mode);
-typedef FD_t (*fdio_fopen_function_t) (const char * path, const char * fmode);
-typedef void * (*fdio_ffileno_function_t) (FD_t fd);
-typedef int (*fdio_fflush_function_t) (FD_t fd);
-typedef long (*fdio_ftell_function_t) (FD_t);
+typedef FD_t (*fdio_fdopen_function_t) (FD_t fd, int fdno, const char * fmode);
+typedef int (*fdio_fflush_function_t) (FDSTACK_t fps);
+typedef off_t (*fdio_ftell_function_t) (FDSTACK_t fps);
+typedef int (*fdio_ferror_function_t) (FDSTACK_t fps);
+typedef const char * (*fdio_fstrerr_function_t)(FDSTACK_t fps);
struct FDIO_s {
+ const char * ioname;
+ const char * name;
fdio_read_function_t read;
fdio_write_function_t write;
fdio_seek_function_t seek;
fdio_close_function_t close;
- fdio_ref_function_t _fdref;
- fdio_deref_function_t _fdderef;
- fdio_new_function_t _fdnew;
- fdio_fileno_function_t _fileno;
-
fdio_open_function_t _open;
- fdio_fopen_function_t _fopen;
- fdio_ffileno_function_t _ffileno;
+ fdio_fdopen_function_t _fdopen;
fdio_fflush_function_t _fflush;
fdio_ftell_function_t _ftell;
+ fdio_ferror_function_t _ferror;
+ fdio_fstrerr_function_t _fstrerr;
};
/* forward refs */
static const FDIO_t fdio;
static const FDIO_t ufdio;
static const FDIO_t gzdio;
+#if HAVE_BZLIB_H
static const FDIO_t bzdio;
+#endif
+#ifdef HAVE_LZMA_H
static const FDIO_t xzdio;
static const FDIO_t lzdio;
+#endif
+#ifdef HAVE_ZSTD
+static const FDIO_t zstdio;
+#endif
/** \ingroup rpmio
* Update digest(s) attached to fd.
*/
static void fdUpdateDigests(FD_t fd, const void * buf, size_t buflen);
-static FD_t fdNew(const char *descr);
+static FD_t fdNew(int fdno, const char *descr);
/**
*/
int _rpmio_debug = 0;
@@ -191,38 +174,23 @@ static const char * fdbg(FD_t fd)
{
static char buf[BUFSIZ];
char *be = buf;
- int i;
buf[0] = '\0';
if (fd == NULL)
return buf;
*be++ = '\t';
- for (i = fd->nfps; i >= 0; i--) {
- FDSTACK_t * fps = &fd->fps[i];
- if (i != fd->nfps)
+ for (FDSTACK_t fps = fd->fps; fps != NULL; fps = fps->prev) {
+ FDIO_t iot = fps->io;
+ if (fps != fd->fps)
*be++ = ' ';
*be++ = '|';
*be++ = ' ';
- if (fps->io == fdio) {
- sprintf(be, "FD %d fp %p", fps->fdno, fps->fp);
- } else if (fps->io == ufdio) {
- sprintf(be, "UFD %d fp %p", fps->fdno, fps->fp);
- } else if (fps->io == gzdio) {
- sprintf(be, "GZD %p fdno %d", fps->fp, fps->fdno);
-#if HAVE_BZLIB_H
- } else if (fps->io == bzdio) {
- sprintf(be, "BZD %p fdno %d", fps->fp, fps->fdno);
-#endif
-#if HAVE_LZMA_H
- } else if (fps->io == xzdio) {
- sprintf(be, "XZD %p fdno %d", fps->fp, fps->fdno);
- } else if (fps->io == lzdio) {
- sprintf(be, "LZD %p fdno %d", fps->fp, fps->fdno);
-#endif
+ /* plain fd io types dont have _fopen() method */
+ if (iot->_fdopen == NULL) {
+ sprintf(be, "%s %d fp %p", iot->ioname, fps->fdno, fps->fp);
} else {
- sprintf(be, "??? io %p fp %p fdno %d ???",
- fps->io, fps->fp, fps->fdno);
+ sprintf(be, "%s %p fp %d", iot->ioname, fps->fp, fps->fdno);
}
be += strlen(be);
*be = '\0';
@@ -238,8 +206,10 @@ static void fdstat_enter(FD_t fd, fdOpX opx)
static void fdstat_exit(FD_t fd, fdOpX opx, ssize_t rc)
{
- if (rc == -1)
- fd->syserrno = errno;
+ if (rc == -1) {
+ FDSTACK_t fps = fdGetFps(fd);
+ fps->syserrno = errno;
+ }
if (fd->stats != NULL)
(void) rpmswExit(fdOp(fd, opx), rc);
}
@@ -291,21 +261,35 @@ FD_t fdDup(int fdno)
if ((nfdno = dup(fdno)) < 0)
return NULL;
- fd = fdNew(NULL);
- fdSetFdno(fd, nfdno);
+ fd = fdNew(nfdno, NULL);
DBGIO(fd, (stderr, "==> fdDup(%d) fd %p %s\n", fdno, (fd ? fd : NULL), fdbg(fd)));
return fd;
}
/* Regular fd doesn't have fflush() equivalent but its not an error either */
-static int fdFlush(FD_t fd)
+static int fdFlush(FDSTACK_t fps)
{
return 0;
}
-static int fdFileno(FD_t fd)
+static int fdError(FDSTACK_t fps)
+{
+ return fps->syserrno;
+}
+
+static int zfdError(FDSTACK_t fps)
{
- return (fd != NULL) ? fd->fps[0].fdno : -2;
+ return (fps->syserrno || fps->errcookie != NULL) ? -1 : 0;
+}
+
+static const char * fdStrerr(FDSTACK_t fps)
+{
+ return (fps->syserrno != 0) ? strerror(fps->syserrno) : "";
+}
+
+static const char * zfdStrerr(FDSTACK_t fps)
+{
+ return (fps->errcookie != NULL) ? fps->errcookie : "";
}
const char * Fdescr(FD_t fd)
@@ -315,7 +299,7 @@ const char * Fdescr(FD_t fd)
/* Lazy lookup if description is not set (eg dupped fd) */
if (fd->descr == NULL) {
- int fdno = fd->fps[fd->nfps].fdno;
+ int fdno = fd->fps->fdno;
#if defined(__linux__)
/* Grab the path from /proc if we can */
char *procpath = NULL;
@@ -358,69 +342,55 @@ FD_t fdFree( FD_t fd)
if (fd->digests) {
fd->digests = rpmDigestBundleFree(fd->digests);
}
+ free(fd->fps);
free(fd->descr);
free(fd);
}
return NULL;
}
-FD_t fdNew(const char *descr)
+static FD_t fdNew(int fdno, const char *descr)
{
FD_t fd = xcalloc(1, sizeof(*fd));
- if (fd == NULL) /* XXX xmalloc never returns NULL */
- return NULL;
fd->nrefs = 0;
fd->flags = 0;
fd->magic = FDMAGIC;
fd->urlType = URL_IS_UNKNOWN;
-
- fd->nfps = 0;
- memset(fd->fps, 0, sizeof(fd->fps));
-
- fd->fps[0].io = fdio;
- fd->fps[0].fp = NULL;
- fd->fps[0].fdno = -1;
-
- fd->syserrno = 0;
- fd->errcookie = NULL;
fd->stats = xcalloc(1, sizeof(*fd->stats));
fd->digests = NULL;
fd->descr = descr ? xstrdup(descr) : NULL;
- return fdLink(fd);
+ fdPush(fd, fdio, NULL, fdno);
+ return fd;
}
-static ssize_t fdRead(FD_t fd, void * buf, size_t count)
+static ssize_t fdRead(FDSTACK_t fps, void * buf, size_t count)
{
- return read(fdFileno(fd), buf, count);
+ return read(fps->fdno, buf, count);
}
-static ssize_t fdWrite(FD_t fd, const void * buf, size_t count)
+static ssize_t fdWrite(FDSTACK_t fps, const void * buf, size_t count)
{
if (count == 0)
return 0;
- return write(fdFileno(fd), buf, count);
+ return write(fps->fdno, buf, count);
}
-static int fdSeek(FD_t fd, off_t pos, int whence)
+static int fdSeek(FDSTACK_t fps, off_t pos, int whence)
{
- return lseek(fdFileno(fd), pos, whence);
+ return lseek(fps->fdno, pos, whence);
}
-static int fdClose(FD_t fd)
+static int fdClose(FDSTACK_t fps)
{
- int fdno;
+ int fdno = fps->fdno;
int rc;
- if (fd == NULL) return -2;
- fdno = fdFileno(fd);
-
- fdSetFdno(fd, -1);
+ fps->fdno = -1;
rc = ((fdno >= 0) ? close(fdno) : -2);
- fdFree(fd);
return rc;
}
@@ -435,20 +405,20 @@ static FD_t fdOpen(const char *path, int flags, mode_t mode)
(void) close(fdno);
return NULL;
}
- fd = fdNew(path);
- fdSetFdno(fd, fdno);
+ fd = fdNew(fdno, path);
fd->flags = flags;
return fd;
}
-static long fdTell(FD_t fd)
+static off_t fdTell(FDSTACK_t fps)
{
- return lseek(Fileno(fd), 0, SEEK_CUR);
+ return lseek(fps->fdno, 0, SEEK_CUR);
}
static const struct FDIO_s fdio_s = {
- fdRead, fdWrite, fdSeek, fdClose, fdLink, fdFree, fdNew, fdFileno,
- fdOpen, NULL, fdGetFp, fdFlush, fdTell
+ "fdio", NULL,
+ fdRead, fdWrite, fdSeek, fdClose,
+ fdOpen, NULL, fdFlush, fdTell, fdError, fdStrerr,
};
static const FDIO_t fdio = &fdio_s ;
@@ -543,21 +513,17 @@ fprintf(stderr, "*** ufdOpen(%s,0x%x,0%o)\n", url, (unsigned)flags, (unsigned)mo
break;
}
- if (fd == NULL) return NULL;
-
- fdSetIo(fd, ufdio);
- fd->urlType = urlType;
-
- if (Fileno(fd) < 0) {
- (void) fdClose(fd);
- return NULL;
+ if (fd != NULL) {
+ fd->fps->io = ufdio;
+ fd->urlType = urlType;
}
return fd;
}
static const struct FDIO_s ufdio_s = {
- fdRead, fdWrite, fdSeek, fdClose, fdLink, fdFree, fdNew, fdFileno,
- ufdOpen, NULL, fdGetFp, fdFlush, fdTell
+ "ufdio", NULL,
+ fdRead, fdWrite, fdSeek, fdClose,
+ ufdOpen, NULL, fdFlush, fdTell, fdError, fdStrerr
};
static const FDIO_t ufdio = &ufdio_s ;
@@ -565,161 +531,104 @@ static const FDIO_t ufdio = &ufdio_s ;
/* Support for GZIP library. */
#include <zlib.h>
-static void * gzdFileno(FD_t fd)
+static FD_t gzdFdopen(FD_t fd, int fdno, const char *fmode)
{
- return iotFileno(fd, gzdio);
-}
+ gzFile gzfile = gzdopen(fdno, fmode);
-static
-FD_t gzdOpen(const char * path, const char * fmode)
-{
- FD_t fd;
- gzFile gzfile;
- if ((gzfile = gzopen(path, fmode)) == NULL)
+ if (gzfile == NULL)
return NULL;
- fd = fdNew(path);
- fdPop(fd); fdPush(fd, gzdio, gzfile, -1);
-
- return fdLink(fd);
-}
-static FD_t gzdFdopen(FD_t fd, const char *fmode)
-{
- int fdno;
- gzFile gzfile;
-
- if (fd == NULL || fmode == NULL) return NULL;
- fdno = fdFileno(fd);
fdSetFdno(fd, -1); /* XXX skip the fdio close */
- if (fdno < 0) return NULL;
- gzfile = gzdopen(fdno, fmode);
- if (gzfile == NULL) return NULL;
-
fdPush(fd, gzdio, gzfile, fdno); /* Push gzdio onto stack */
-
- return fdLink(fd);
+ return fd;
}
-static int gzdFlush(FD_t fd)
+static int gzdFlush(FDSTACK_t fps)
{
- gzFile gzfile;
- gzfile = gzdFileno(fd);
+ gzFile gzfile = fps->fp;
if (gzfile == NULL) return -2;
return gzflush(gzfile, Z_SYNC_FLUSH); /* XXX W2DO? */
}
-static ssize_t gzdRead(FD_t fd, void * buf, size_t count)
+static void gzdSetError(FDSTACK_t fps)
{
- gzFile gzfile;
+ gzFile gzfile = fps->fp;
+ int zerror = 0;
+ fps->errcookie = gzerror(gzfile, &zerror);
+ if (zerror == Z_ERRNO) {
+ fps->syserrno = errno;
+ fps->errcookie = strerror(fps->syserrno);
+ }
+}
+
+static ssize_t gzdRead(FDSTACK_t fps, void * buf, size_t count)
+{
+ gzFile gzfile = fps->fp;
ssize_t rc;
- gzfile = gzdFileno(fd);
if (gzfile == NULL) return -2; /* XXX can't happen */
rc = gzread(gzfile, buf, count);
- if (rc < 0) {
- int zerror = 0;
- fd->errcookie = gzerror(gzfile, &zerror);
- if (zerror == Z_ERRNO) {
- fd->syserrno = errno;
- fd->errcookie = strerror(fd->syserrno);
- }
- }
+ if (rc < 0)
+ gzdSetError(fps);
return rc;
}
-static ssize_t gzdWrite(FD_t fd, const void * buf, size_t count)
+static ssize_t gzdWrite(FDSTACK_t fps, const void * buf, size_t count)
{
gzFile gzfile;
ssize_t rc;
- gzfile = gzdFileno(fd);
+ gzfile = fps->fp;
if (gzfile == NULL) return -2; /* XXX can't happen */
rc = gzwrite(gzfile, (void *)buf, count);
- if (rc < 0) {
- int zerror = 0;
- fd->errcookie = gzerror(gzfile, &zerror);
- if (zerror == Z_ERRNO) {
- fd->syserrno = errno;
- fd->errcookie = strerror(fd->syserrno);
- }
- }
+ if (rc < 0)
+ gzdSetError(fps);
return rc;
}
/* XXX zlib-1.0.4 has not */
-static int gzdSeek(FD_t fd, off_t pos, int whence)
+static int gzdSeek(FDSTACK_t fps, off_t pos, int whence)
{
off_t p = pos;
int rc;
#if HAVE_GZSEEK
- gzFile gzfile;
-
- if (fd == NULL) return -2;
+ gzFile gzfile = fps->fp;
- gzfile = gzdFileno(fd);
if (gzfile == NULL) return -2; /* XXX can't happen */
rc = gzseek(gzfile, p, whence);
- if (rc < 0) {
- int zerror = 0;
- fd->errcookie = gzerror(gzfile, &zerror);
- if (zerror == Z_ERRNO) {
- fd->syserrno = errno;
- fd->errcookie = strerror(fd->syserrno);
- }
- }
+ if (rc < 0)
+ gzdSetError(fps);
#else
rc = -2;
#endif
return rc;
}
-static int gzdClose(FD_t fd)
+static int gzdClose(FDSTACK_t fps)
{
- gzFile gzfile;
+ gzFile gzfile = fps->fp;
int rc;
- gzfile = gzdFileno(fd);
if (gzfile == NULL) return -2; /* XXX can't happen */
rc = gzclose(gzfile);
- /* XXX TODO: preserve fd if errors */
-
- if (fd) {
- if (rc < 0) {
- fd->errcookie = "gzclose error";
- if (rc == Z_ERRNO) {
- fd->syserrno = errno;
- fd->errcookie = strerror(fd->syserrno);
- }
- }
- }
-
- if (_rpmio_debug || rpmIsDebug()) fdstat_print(fd, "GZDIO", stderr);
- if (rc == 0)
- fdFree(fd);
- return rc;
+ return (rc != 0) ? -1 : 0;
}
-static long gzdTell(FD_t fd)
+static off_t gzdTell(FDSTACK_t fps)
{
off_t pos = -1;
- gzFile gzfile = gzdFileno(fd);
+ gzFile gzfile = fps->fp;
if (gzfile != NULL) {
#if HAVE_GZSEEK
pos = gztell(gzfile);
- if (pos < 0) {
- int zerror = 0;
- fd->errcookie = gzerror(gzfile, &zerror);
- if (zerror == Z_ERRNO) {
- fd->syserrno = errno;
- fd->errcookie = strerror(fd->syserrno);
- }
- }
+ if (pos < 0)
+ gzdSetError(fps);
#else
pos = -2;
#endif
@@ -727,8 +636,9 @@ static long gzdTell(FD_t fd)
return pos;
}
static const struct FDIO_s gzdio_s = {
- gzdRead, gzdWrite, gzdSeek, gzdClose, fdLink, fdFree, fdNew, fdFileno,
- NULL, gzdOpen, gzdFileno, gzdFlush, gzdTell
+ "gzdio", "gzip",
+ gzdRead, gzdWrite, gzdSeek, gzdClose,
+ NULL, gzdFdopen, gzdFlush, gzdTell, zfdError, zfdStrerr
};
static const FDIO_t gzdio = &gzdio_s ;
@@ -738,133 +648,73 @@ static const FDIO_t gzdio = &gzdio_s ;
#include <bzlib.h>
-static void * bzdFileno(FD_t fd)
+static FD_t bzdFdopen(FD_t fd, int fdno, const char * fmode)
{
- return iotFileno(fd, bzdio);
-}
+ BZFILE *bzfile = BZ2_bzdopen(fdno, fmode);
-static FD_t bzdOpen(const char * path, const char * mode)
-{
- FD_t fd;
- BZFILE *bzfile;;
- if ((bzfile = BZ2_bzopen(path, mode)) == NULL)
+ if (bzfile == NULL)
return NULL;
- fd = fdNew(path);
- fdPop(fd); fdPush(fd, bzdio, bzfile, -1);
- return fdLink(fd);
-}
-static FD_t bzdFdopen(FD_t fd, const char * fmode)
-{
- int fdno;
- BZFILE *bzfile;
-
- if (fd == NULL || fmode == NULL) return NULL;
- fdno = fdFileno(fd);
fdSetFdno(fd, -1); /* XXX skip the fdio close */
- if (fdno < 0) return NULL;
- bzfile = BZ2_bzdopen(fdno, fmode);
- if (bzfile == NULL) return NULL;
-
fdPush(fd, bzdio, bzfile, fdno); /* Push bzdio onto stack */
-
- return fdLink(fd);
+ return fd;
}
-static int bzdFlush(FD_t fd)
+static int bzdFlush(FDSTACK_t fps)
{
- return BZ2_bzflush(bzdFileno(fd));
+ return BZ2_bzflush(fps->fp);
}
-static ssize_t bzdRead(FD_t fd, void * buf, size_t count)
+static ssize_t bzdRead(FDSTACK_t fps, void * buf, size_t count)
{
- BZFILE *bzfile;
+ BZFILE *bzfile = fps->fp;
ssize_t rc = 0;
- bzfile = bzdFileno(fd);
if (bzfile)
rc = BZ2_bzread(bzfile, buf, count);
if (rc == -1) {
int zerror = 0;
- if (bzfile)
- fd->errcookie = BZ2_bzerror(bzfile, &zerror);
+ if (bzfile) {
+ fps->errcookie = BZ2_bzerror(bzfile, &zerror);
+ }
}
return rc;
}
-static ssize_t bzdWrite(FD_t fd, const void * buf, size_t count)
+static ssize_t bzdWrite(FDSTACK_t fps, const void * buf, size_t count)
{
- BZFILE *bzfile;
+ BZFILE *bzfile = fps->fp;
ssize_t rc;
- bzfile = bzdFileno(fd);
rc = BZ2_bzwrite(bzfile, (void *)buf, count);
if (rc == -1) {
int zerror = 0;
- fd->errcookie = BZ2_bzerror(bzfile, &zerror);
+ fps->errcookie = BZ2_bzerror(bzfile, &zerror);
}
return rc;
}
-static int bzdClose(FD_t fd)
+static int bzdClose(FDSTACK_t fps)
{
- BZFILE *bzfile;
- int rc;
-
- bzfile = bzdFileno(fd);
+ BZFILE *bzfile = fps->fp;
if (bzfile == NULL) return -2;
- /* FIX: check rc */
- BZ2_bzclose(bzfile);
- rc = 0; /* XXX FIXME */
-
- /* XXX TODO: preserve fd if errors */
- if (fd) {
- if (rc == -1) {
- int zerror = 0;
- fd->errcookie = BZ2_bzerror(bzfile, &zerror);
- }
- }
+ /* bzclose() doesn't return errors */
+ BZ2_bzclose(bzfile);
- if (_rpmio_debug || rpmIsDebug()) fdstat_print(fd, "BZDIO", stderr);
- if (rc == 0)
- fdFree(fd);
- return rc;
+ return 0;
}
static const struct FDIO_s bzdio_s = {
- bzdRead, bzdWrite, NULL, bzdClose, fdLink, fdFree, fdNew, fdFileno,
- NULL, bzdOpen, bzdFileno, bzdFlush, NULL
+ "bzdio", "bzip2",
+ bzdRead, bzdWrite, NULL, bzdClose,
+ NULL, bzdFdopen, bzdFlush, NULL, zfdError, zfdStrerr
};
static const FDIO_t bzdio = &bzdio_s ;
#endif /* HAVE_BZLIB_H */
-static const char * getFdErrstr (FD_t fd)
-{
- const char *errstr = NULL;
-
- if (fdGetIo(fd) == gzdio) {
- errstr = fd->errcookie;
- } else
-#ifdef HAVE_BZLIB_H
- if (fdGetIo(fd) == bzdio) {
- errstr = fd->errcookie;
- } else
-#endif /* HAVE_BZLIB_H */
-#ifdef HAVE_LZMA_H
- if (fdGetIo(fd) == xzdio || fdGetIo(fd) == lzdio) {
- errstr = fd->errcookie;
- } else
-#endif /* HAVE_LZMA_H */
- {
- errstr = (fd->syserrno ? strerror(fd->syserrno) : "");
- }
-
- return errstr;
-}
-
/* =============================================================== */
/* Support for LZMA library. */
@@ -873,6 +723,10 @@ static const char * getFdErrstr (FD_t fd)
#include <sys/types.h>
#include <inttypes.h>
#include <lzma.h>
+/* Multithreading support in stable API since xz 5.2.0 */
+#if LZMA_VERSION >= 50020002
+#define HAVE_LZMA_MT
+#endif
#define kBufferSize (1 << 15)
@@ -889,87 +743,138 @@ typedef struct lzfile {
} LZFILE;
-static LZFILE *lzopen_internal(const char *path, const char *mode, int fd, int xz)
+static LZFILE *lzopen_internal(const char *mode, int fd, int xz)
{
- int level = 7; /* Use XZ's default compression level if unspecified */
+ int level = LZMA_PRESET_DEFAULT;
int encoding = 0;
FILE *fp;
LZFILE *lzfile;
lzma_ret ret;
lzma_stream init_strm = LZMA_STREAM_INIT;
-
+ uint64_t mem_limit = rpmExpandNumeric("%{_xz_memlimit}");
+#ifdef HAVE_LZMA_MT
+ int threads = 0;
+#endif
for (; *mode; mode++) {
if (*mode == 'w')
encoding = 1;
else if (*mode == 'r')
encoding = 0;
- else if (*mode >= '1' && *mode <= '9')
+ else if (*mode >= '0' && *mode <= '9')
level = *mode - '0';
+ else if (*mode == 'T') {
+ if (isdigit(*(mode+1))) {
+#ifdef HAVE_LZMA_MT
+ threads = atoi(++mode);
+#endif
+ /* skip past rest of digits in string that atoi()
+ * should've processed
+ * */
+ while (isdigit(*++mode));
+ }
+#ifdef HAVE_LZMA_MT
+ else
+ threads = -1;
+#endif
+ }
}
- if (fd != -1)
- fp = fdopen(fd, encoding ? "w" : "r");
- else
- fp = fopen(path, encoding ? "w" : "r");
+ fp = fdopen(fd, encoding ? "w" : "r");
if (!fp)
- return 0;
+ return NULL;
lzfile = calloc(1, sizeof(*lzfile));
- if (!lzfile) {
- fclose(fp);
- return 0;
- }
-
lzfile->file = fp;
lzfile->encoding = encoding;
lzfile->eof = 0;
lzfile->strm = init_strm;
if (encoding) {
if (xz) {
- ret = lzma_easy_encoder(&lzfile->strm, level, LZMA_CHECK_SHA256);
+#ifdef HAVE_LZMA_MT
+ if (!threads) {
+#endif
+ ret = lzma_easy_encoder(&lzfile->strm, level, LZMA_CHECK_SHA256);
+#ifdef HAVE_LZMA_MT
+ } else {
+ if (threads == -1)
+ threads = sysconf(_SC_NPROCESSORS_ONLN);
+ lzma_mt mt_options = {
+ .flags = 0,
+ .threads = threads,
+ .block_size = 0,
+ .timeout = 0,
+ .preset = level,
+ .filters = NULL,
+ .check = LZMA_CHECK_SHA256 };
+
+#if __WORDSIZE == 32
+ /* In 32 bit environment, required memory easily exceeds memory address
+ * space limit if compressing using multiple threads.
+ * By setting a memory limit, liblzma will automatically adjust number
+ * of threads to avoid exceeding memory.
+ */
+ if (threads > 1) {
+ struct utsname u;
+ uint32_t memlimit = (SIZE_MAX>>1) + (SIZE_MAX>>3);
+ uint64_t memory_usage;
+ /* While a 32 bit linux kernel will have an address limit of 3GiB
+ * for processes (which is why set the memory limit to 2.5GiB as a safety
+ * margin), 64 bit kernels will have a limit of 4GiB for 32 bit binaries.
+ * Therefore the memory limit should be higher if running on a 64 bit
+ * kernel, so we increase it to 3,5GiB.
+ */
+ uname(&u);
+ if (strstr(u.machine, "64") || strstr(u.machine, "s390x")
+#if defined(__linux__)
+ || ((personality(0xffffffff) & PER_MASK) == PER_LINUX32)
+#endif
+ )
+ memlimit += (SIZE_MAX>>2);
+ /* keep reducing the number of threads until memory usage gets below limit */
+ while ((memory_usage = lzma_stream_encoder_mt_memusage(&mt_options)) > memlimit) {
+ /* number of threads shouldn't be able to hit zero with compression
+ * settings aailable to set through rpm... */
+ assert(--mt_options.threads != 0);
+ }
+ lzma_memlimit_set(&lzfile->strm, memlimit);
+
+ if (threads != (int)mt_options.threads)
+ rpmlog(RPMLOG_NOTICE,
+ "XZ: Adjusted the number of threads from %d to %d to not exceed the memory usage limit of %lu bytes",
+ threads, mt_options.threads, memlimit);
+ }
+#endif
+
+ ret = lzma_stream_encoder_mt(&lzfile->strm, &mt_options);
+ }
+#endif
} else {
lzma_options_lzma options;
lzma_lzma_preset(&options, level);
ret = lzma_alone_encoder(&lzfile->strm, &options);
}
- } else { /* lzma_easy_decoder_memusage(level) is not ready yet, use hardcoded limit for now */
- ret = lzma_auto_decoder(&lzfile->strm, 100<<20, 0);
+ } else { /* lzma_easy_decoder_memusage(level) is not ready yet, use hardcoded limit for now */
+ ret = lzma_auto_decoder(&lzfile->strm, mem_limit ? mem_limit : 100<<20, 0);
}
if (ret != LZMA_OK) {
+ switch (ret) {
+ case LZMA_MEM_ERROR:
+ rpmlog(RPMLOG_ERR, "liblzma: Memory allocation failed");
+ break;
+
+ case LZMA_DATA_ERROR:
+ rpmlog(RPMLOG_ERR, "liblzma: File size limits exceeded");
+ break;
+
+ default:
+ rpmlog(RPMLOG_ERR, "liblzma: <Unknown error (%d), possibly a bug", ret);
+ break;
+ }
fclose(fp);
free(lzfile);
- return 0;
+ return NULL;
}
return lzfile;
}
-static LZFILE *xzopen(const char *path, const char *mode)
-{
- return lzopen_internal(path, mode, -1, 1);
-}
-
-static LZFILE *xzdopen(int fd, const char *mode)
-{
- if (fd < 0)
- return 0;
- return lzopen_internal(0, mode, fd, 1);
-}
-
-static LZFILE *lzopen(const char *path, const char *mode)
-{
- return lzopen_internal(path, mode, -1, 0);
-}
-
-static LZFILE *lzdopen(int fd, const char *mode)
-{
- if (fd < 0)
- return 0;
- return lzopen_internal(0, mode, fd, 0);
-}
-
-static int lzflush(LZFILE *lzfile)
-{
- return fflush(lzfile->file);
-}
-
static int lzclose(LZFILE *lzfile)
{
lzma_ret ret;
@@ -1054,170 +959,363 @@ static ssize_t lzwrite(LZFILE *lzfile, void *buf, size_t len)
}
}
-static void * lzdFileno(FD_t fd)
+static FD_t xzdFdopen(FD_t fd, int fdno, const char * fmode)
{
- void * rc = NULL;
-
- if (fd == NULL)
- return NULL;
+ LZFILE *lzfile = lzopen_internal(fmode, fdno, 1);
- for (int i = fd->nfps; i >= 0; i--) {
- FDSTACK_t * fps = &fd->fps[i];
- if (fps->io != xzdio && fps->io != lzdio)
- continue;
- rc = fps->fp;
- break;
- }
- return rc;
-}
-
-static FD_t xzdOpen(const char * path, const char * mode)
-{
- FD_t fd;
- LZFILE *lzfile;
- if ((lzfile = xzopen(path, mode)) == NULL)
+ if (lzfile == NULL)
return NULL;
- fd = fdNew(path);
- fdPop(fd); fdPush(fd, xzdio, lzfile, -1);
- return fdLink(fd);
-}
-
-static FD_t xzdFdopen(FD_t fd, const char * fmode)
-{
- int fdno;
- LZFILE *lzfile;
- if (fd == NULL || fmode == NULL) return NULL;
- fdno = fdFileno(fd);
fdSetFdno(fd, -1); /* XXX skip the fdio close */
- if (fdno < 0) return NULL;
- lzfile = xzdopen(fdno, fmode);
- if (lzfile == NULL) return NULL;
fdPush(fd, xzdio, lzfile, fdno);
- return fdLink(fd);
+ return fd;
}
-static FD_t lzdOpen(const char * path, const char * mode)
+static FD_t lzdFdopen(FD_t fd, int fdno, const char * fmode)
{
- FD_t fd;
- LZFILE *lzfile;
- if ((lzfile = lzopen(path, mode)) == NULL)
- return NULL;
- fd = fdNew(path);
- fdPop(fd); fdPush(fd, xzdio, lzfile, -1);
- return fdLink(fd);
-}
+ LZFILE *lzfile = lzopen_internal(fmode, fdno, 0);
-static FD_t lzdFdopen(FD_t fd, const char * fmode)
-{
- int fdno;
- LZFILE *lzfile;
+ if (lzfile == NULL)
+ return NULL;
- if (fd == NULL || fmode == NULL) return NULL;
- fdno = fdFileno(fd);
fdSetFdno(fd, -1); /* XXX skip the fdio close */
- if (fdno < 0) return NULL;
- lzfile = lzdopen(fdno, fmode);
- if (lzfile == NULL) return NULL;
- fdPush(fd, xzdio, lzfile, fdno);
- return fdLink(fd);
+ fdPush(fd, lzdio, lzfile, fdno);
+ return fd;
}
-static int lzdFlush(FD_t fd)
+static int lzdFlush(FDSTACK_t fps)
{
- return lzflush(lzdFileno(fd));
+ LZFILE *lzfile = fps->fp;
+ return fflush(lzfile->file);
}
-static ssize_t lzdRead(FD_t fd, void * buf, size_t count)
+static ssize_t lzdRead(FDSTACK_t fps, void * buf, size_t count)
{
- LZFILE *lzfile;
+ LZFILE *lzfile = fps->fp;
ssize_t rc = 0;
- lzfile = lzdFileno(fd);
if (lzfile)
rc = lzread(lzfile, buf, count);
if (rc == -1) {
- fd->errcookie = "Lzma: decoding error";
+ fps->errcookie = "Lzma: decoding error";
}
return rc;
}
-static ssize_t lzdWrite(FD_t fd, const void * buf, size_t count)
+static ssize_t lzdWrite(FDSTACK_t fps, const void * buf, size_t count)
{
- LZFILE *lzfile;
+ LZFILE *lzfile = fps->fp;
ssize_t rc = 0;
- lzfile = lzdFileno(fd);
-
rc = lzwrite(lzfile, (void *)buf, count);
if (rc < 0) {
- fd->errcookie = "Lzma: encoding error";
+ fps->errcookie = "Lzma: encoding error";
}
return rc;
}
-static int lzdClose(FD_t fd)
+static int lzdClose(FDSTACK_t fps)
{
- LZFILE *lzfile;
+ LZFILE *lzfile = fps->fp;
int rc;
- lzfile = lzdFileno(fd);
-
if (lzfile == NULL) return -2;
rc = lzclose(lzfile);
- /* XXX TODO: preserve fd if errors */
-
- if (fd) {
- if (rc == -1) {
- fd->errcookie = "lzclose error";
- fd->syserrno = errno;
- fd->errcookie = strerror(fd->syserrno);
- }
- }
-
- if (_rpmio_debug || rpmIsDebug()) fdstat_print(fd, "XZDIO", stderr);
- if (rc == 0)
- fdFree(fd);
return rc;
}
static struct FDIO_s xzdio_s = {
- lzdRead, lzdWrite, NULL, lzdClose, NULL, NULL, NULL, fdFileno,
- NULL, xzdOpen, lzdFileno, lzdFlush, NULL
+ "xzdio", "xz",
+ lzdRead, lzdWrite, NULL, lzdClose,
+ NULL, xzdFdopen, lzdFlush, NULL, zfdError, zfdStrerr
};
static const FDIO_t xzdio = &xzdio_s;
static struct FDIO_s lzdio_s = {
- lzdRead, lzdWrite, NULL, lzdClose, NULL, NULL, NULL, fdFileno,
- NULL, lzdOpen, lzdFileno, lzdFlush, NULL
+ "lzdio", "lzma",
+ lzdRead, lzdWrite, NULL, lzdClose,
+ NULL, lzdFdopen, lzdFlush, NULL, zfdError, zfdStrerr
};
static const FDIO_t lzdio = &lzdio_s;
#endif /* HAVE_LZMA_H */
/* =============================================================== */
+/* Support for ZSTD library. */
+#ifdef HAVE_ZSTD
-const char *Fstrerror(FD_t fd)
+#include <zstd.h>
+
+typedef struct rpmzstd_s {
+ int flags; /*!< open flags. */
+ int fdno;
+ int level; /*!< compression level */
+ FILE * fp;
+ void * _stream; /*!< ZSTD_{C,D}Stream */
+ size_t nb;
+ void * b;
+ ZSTD_inBuffer zib; /*!< ZSTD_inBuffer */
+ ZSTD_outBuffer zob; /*!< ZSTD_outBuffer */
+} * rpmzstd;
+
+static rpmzstd rpmzstdNew(int fdno, const char *fmode)
{
- if (fd == NULL)
- return (errno ? strerror(errno) : "");
- return getFdErrstr(fd);
+ int flags = 0;
+ int level = 3;
+ const char * s = fmode;
+ char stdio[32];
+ char *t = stdio;
+ char *te = t + sizeof(stdio) - 2;
+ int c;
+
+ switch ((c = *s++)) {
+ case 'a':
+ *t++ = (char)c;
+ flags &= ~O_ACCMODE;
+ flags |= O_WRONLY | O_CREAT | O_APPEND;
+ break;
+ case 'w':
+ *t++ = (char)c;
+ flags &= ~O_ACCMODE;
+ flags |= O_WRONLY | O_CREAT | O_TRUNC;
+ break;
+ case 'r':
+ *t++ = (char)c;
+ flags &= ~O_ACCMODE;
+ flags |= O_RDONLY;
+ break;
+ }
+
+ while ((c = *s++) != 0) {
+ switch (c) {
+ case '.':
+ break;
+ case '+':
+ if (t < te) *t++ = c;
+ flags &= ~O_ACCMODE;
+ flags |= O_RDWR;
+ continue;
+ break;
+ default:
+ if (c >= (int)'0' && c <= (int)'9') {
+ level = strtol(s-1, (char **)&s, 10);
+ if (level < 1){
+ level = 1;
+ rpmlog(RPMLOG_WARNING, "Invalid compression level for zstd. Using %i instead.\n", 1);
+ }
+ if (level > 19) {
+ level = 19;
+ rpmlog(RPMLOG_WARNING, "Invalid compression level for zstd. Using %i instead.\n", 19);
+ }
+ }
+ continue;
+ break;
+ }
+ break;
+ }
+ *t = '\0';
+
+ FILE * fp = fdopen(fdno, stdio);
+ if (fp == NULL)
+ return NULL;
+
+ void * _stream = NULL;
+ size_t nb = 0;
+
+ if ((flags & O_ACCMODE) == O_RDONLY) { /* decompressing */
+ if ((_stream = (void *) ZSTD_createDStream()) == NULL
+ || ZSTD_isError(ZSTD_initDStream(_stream))) {
+ return NULL;
+ }
+ nb = ZSTD_DStreamInSize();
+ } else { /* compressing */
+ if ((_stream = (void *) ZSTD_createCStream()) == NULL
+ || ZSTD_isError(ZSTD_initCStream(_stream, level))) {
+ return NULL;
+ }
+ nb = ZSTD_CStreamOutSize();
+ }
+
+ rpmzstd zstd = (rpmzstd) xcalloc(1, sizeof(*zstd));
+ zstd->flags = flags;
+ zstd->fdno = fdno;
+ zstd->level = level;
+ zstd->fp = fp;
+ zstd->_stream = _stream;
+ zstd->nb = nb;
+ zstd->b = xmalloc(nb);
+
+ return zstd;
}
-#define FDIOVEC(_fd, _vec) \
- ((fdGetIo(_fd) && fdGetIo(_fd)->_vec) ? fdGetIo(_fd)->_vec : NULL)
+static FD_t zstdFdopen(FD_t fd, int fdno, const char * fmode)
+{
+ rpmzstd zstd = rpmzstdNew(fdno, fmode);
+
+ if (zstd == NULL)
+ return NULL;
+
+ fdSetFdno(fd, -1); /* XXX skip the fdio close */
+ fdPush(fd, zstdio, zstd, fdno); /* Push zstdio onto stack */
+ return fd;
+}
+
+static int zstdFlush(FDSTACK_t fps)
+{
+ rpmzstd zstd = (rpmzstd) fps->fp;
+assert(zstd);
+ int rc = -1;
+
+ if ((zstd->flags & O_ACCMODE) == O_RDONLY) { /* decompressing */
+ rc = 0;
+ } else { /* compressing */
+ /* close frame */
+ zstd->zob.dst = zstd->b;
+ zstd->zob.size = zstd->nb;
+ zstd->zob.pos = 0;
+ int xx = ZSTD_flushStream(zstd->_stream, &zstd->zob);
+ if (ZSTD_isError(xx))
+ fps->errcookie = ZSTD_getErrorName(xx);
+ else if (zstd->zob.pos != fwrite(zstd->b, 1, zstd->zob.pos, zstd->fp))
+ fps->errcookie = "zstdFlush fwrite failed.";
+ else
+ rc = 0;
+ }
+ return rc;
+}
+
+static ssize_t zstdRead(FDSTACK_t fps, void * buf, size_t count)
+{
+ rpmzstd zstd = (rpmzstd) fps->fp;
+assert(zstd);
+ ZSTD_outBuffer zob = { buf, count, 0 };
+
+ while (zob.pos < zob.size) {
+ /* Re-fill compressed data buffer. */
+ if (zstd->zib.pos >= zstd->zib.size) {
+ zstd->zib.size = fread(zstd->b, 1, zstd->nb, zstd->fp);
+ if (zstd->zib.size == 0)
+ break; /* EOF */
+ zstd->zib.src = zstd->b;
+ zstd->zib.pos = 0;
+ }
+
+ /* Decompress next chunk. */
+ int xx = ZSTD_decompressStream(zstd->_stream, &zob, &zstd->zib);
+ if (ZSTD_isError(xx)) {
+ fps->errcookie = ZSTD_getErrorName(xx);
+ return -1;
+ }
+ }
+ return zob.pos;
+}
+
+static ssize_t zstdWrite(FDSTACK_t fps, const void * buf, size_t count)
+{
+ rpmzstd zstd = (rpmzstd) fps->fp;
+assert(zstd);
+ ZSTD_inBuffer zib = { buf, count, 0 };
+
+ while (zib.pos < zib.size) {
+
+ /* Reset to beginning of compressed data buffer. */
+ zstd->zob.dst = zstd->b;
+ zstd->zob.size = zstd->nb;
+ zstd->zob.pos = 0;
+
+ /* Compress next chunk. */
+ int xx = ZSTD_compressStream(zstd->_stream, &zstd->zob, &zib);
+ if (ZSTD_isError(xx)) {
+ fps->errcookie = ZSTD_getErrorName(xx);
+ return -1;
+ }
+
+ /* Write compressed data buffer. */
+ if (zstd->zob.pos > 0) {
+ size_t nw = fwrite(zstd->b, 1, zstd->zob.pos, zstd->fp);
+ if (nw != zstd->zob.pos) {
+ fps->errcookie = "zstdWrite fwrite failed.";
+ return -1;
+ }
+ }
+ }
+ return zib.pos;
+}
+
+static int zstdClose(FDSTACK_t fps)
+{
+ rpmzstd zstd = (rpmzstd) fps->fp;
+assert(zstd);
+ int rc = -2;
+
+ if ((zstd->flags & O_ACCMODE) == O_RDONLY) { /* decompressing */
+ rc = 0;
+ ZSTD_freeDStream(zstd->_stream);
+ } else { /* compressing */
+ /* close frame */
+ zstd->zob.dst = zstd->b;
+ zstd->zob.size = zstd->nb;
+ zstd->zob.pos = 0;
+ int xx = ZSTD_endStream(zstd->_stream, &zstd->zob);
+ if (ZSTD_isError(xx))
+ fps->errcookie = ZSTD_getErrorName(xx);
+ else if (zstd->zob.pos != fwrite(zstd->b, 1, zstd->zob.pos, zstd->fp))
+ fps->errcookie = "zstdClose fwrite failed.";
+ else
+ rc = 0;
+ ZSTD_freeCStream(zstd->_stream);
+ }
+
+ if (zstd->fp && fileno(zstd->fp) > 2)
+ (void) fclose(zstd->fp);
+
+ if (zstd->b) free(zstd->b);
+ free(zstd);
+
+ return rc;
+}
+
+static const struct FDIO_s zstdio_s = {
+ "zstdio", "zstd",
+ zstdRead, zstdWrite, NULL, zstdClose,
+ NULL, zstdFdopen, zstdFlush, NULL, zfdError, zfdStrerr
+};
+static const FDIO_t zstdio = &zstdio_s ;
+
+#endif /* HAVE_ZSTD */
+
+/* =============================================================== */
+
+#define FDIOVEC(_fps, _vec) \
+ ((_fps) && (_fps)->io) ? (_fps)->io->_vec : NULL
+
+const char *Fstrerror(FD_t fd)
+{
+ const char *err = "";
+
+ if (fd != NULL) {
+ FDSTACK_t fps = fdGetFps(fd);
+ fdio_fstrerr_function_t _fstrerr = FDIOVEC(fps, _fstrerr);
+ if (_fstrerr)
+ err = _fstrerr(fps);
+ } else if (errno){
+ err = strerror(errno);
+ }
+ return err;
+}
ssize_t Fread(void *buf, size_t size, size_t nmemb, FD_t fd)
{
ssize_t rc = -1;
if (fd != NULL) {
- fdio_read_function_t _read = FDIOVEC(fd, read);
+ FDSTACK_t fps = fdGetFps(fd);
+ fdio_read_function_t _read = FDIOVEC(fps, read);
fdstat_enter(fd, FDSTAT_READ);
do {
- rc = (_read ? (*_read) (fd, buf, size * nmemb) : -2);
+ rc = (_read ? (*_read) (fps, buf, size * nmemb) : -2);
} while (rc == -1 && errno == EINTR);
fdstat_exit(fd, FDSTAT_READ, rc);
@@ -1236,11 +1334,12 @@ ssize_t Fwrite(const void *buf, size_t size, size_t nmemb, FD_t fd)
ssize_t rc = -1;
if (fd != NULL) {
- fdio_write_function_t _write = FDIOVEC(fd, write);
+ FDSTACK_t fps = fdGetFps(fd);
+ fdio_write_function_t _write = FDIOVEC(fps, write);
fdstat_enter(fd, FDSTAT_WRITE);
do {
- rc = (_write ? _write(fd, buf, size * nmemb) : -2);
+ rc = (_write ? _write(fps, buf, size * nmemb) : -2);
} while (rc == -1 && errno == EINTR);
fdstat_exit(fd, FDSTAT_WRITE, rc);
@@ -1259,10 +1358,11 @@ int Fseek(FD_t fd, off_t offset, int whence)
int rc = -1;
if (fd != NULL) {
- fdio_seek_function_t _seek = FDIOVEC(fd, seek);
+ FDSTACK_t fps = fdGetFps(fd);
+ fdio_seek_function_t _seek = FDIOVEC(fps, seek);
fdstat_enter(fd, FDSTAT_SEEK);
- rc = (_seek ? _seek(fd, offset, whence) : -2);
+ rc = (_seek ? _seek(fps, offset, whence) : -2);
fdstat_exit(fd, FDSTAT_SEEK, rc);
}
@@ -1281,19 +1381,27 @@ int Fclose(FD_t fd)
fd = fdLink(fd);
fdstat_enter(fd, FDSTAT_CLOSE);
- while (fd->nfps >= 0) {
- fdio_close_function_t _close = FDIOVEC(fd, close);
- rc = _close ? _close(fd) : -2;
+ for (FDSTACK_t fps = fd->fps; fps != NULL; fps = fdPop(fd)) {
+ if (fps->fdno >= 0) {
+ fdio_close_function_t _close = FDIOVEC(fps, close);
+ rc = _close ? _close(fps) : -2;
+
+ if (ec == 0 && rc)
+ ec = rc;
+ }
+
+ /* Debugging stats for compresed types */
+ if ((_rpmio_debug || rpmIsDebug()) && fps->fdno == -1)
+ fdstat_print(fd, fps->io->ioname, stderr);
- if (fd->nfps == 0)
+ /* Leave freeing the last one after stats */
+ if (fps->prev == NULL)
break;
- if (ec == 0 && rc)
- ec = rc;
- fdPop(fd);
}
fdstat_exit(fd, FDSTAT_CLOSE, rc);
DBGIO(fd, (stderr, "==>\tFclose(%p) rc %lx %s\n",
(fd ? fd : NULL), (unsigned long)rc, fdbg(fd)));
+ fdPop(fd);
fdFree(fd);
return ec;
@@ -1320,14 +1428,17 @@ static void cvtfmode (const char *m,
switch (*m) {
case 'a':
+ flags &= ~O_ACCMODE;
flags |= O_WRONLY | O_CREAT | O_APPEND;
if (--nstdio > 0) *stdio++ = *m;
break;
case 'w':
+ flags &= ~O_ACCMODE;
flags |= O_WRONLY | O_CREAT | O_TRUNC;
if (--nstdio > 0) *stdio++ = *m;
break;
case 'r':
+ flags &= ~O_ACCMODE;
flags |= O_RDONLY;
if (--nstdio > 0) *stdio++ = *m;
break;
@@ -1343,7 +1454,7 @@ static void cvtfmode (const char *m,
case '.':
break;
case '+':
- flags &= ~(O_RDONLY|O_WRONLY);
+ flags &= ~O_ACCMODE;
flags |= O_RDWR;
if (--nstdio > 0) *stdio++ = c;
continue;
@@ -1357,6 +1468,11 @@ static void cvtfmode (const char *m,
if (--nstdio > 0) *stdio++ = c;
continue;
break;
+ case '?':
+ flags |= RPMIO_DEBUG_IO;
+ if (--nother > 0) *other++ = c;
+ continue;
+ break;
default:
if (--nother > 0) *other++ = c;
continue;
@@ -1372,17 +1488,49 @@ static void cvtfmode (const char *m,
*f = flags;
}
+static FDIO_t findIOT(const char *name)
+{
+ static FDIO_t fdio_types[] = {
+ &fdio_s,
+ &ufdio_s,
+ &gzdio_s,
+#if HAVE_BZLIB_H
+ &bzdio_s,
+#endif
+#if HAVE_LZMA_H
+ &xzdio_s,
+ &lzdio_s,
+#endif
+#ifdef HAVE_ZSTD
+ &zstdio_s,
+#endif
+ NULL
+ };
+ FDIO_t iot = NULL;
+
+ for (FDIO_t *t = fdio_types; t && *t; t++) {
+ if (rstreq(name, (*t)->ioname) ||
+ ((*t)->name && rstreq(name, (*t)->name))) {
+ iot = (*t);
+ break;
+ }
+ }
+
+ return iot;
+}
+
FD_t Fdopen(FD_t ofd, const char *fmode)
{
char stdio[20], other[20], zstdio[40];
const char *end = NULL;
- FDIO_t iof = NULL;
+ FDIO_t iot = NULL;
FD_t fd = ofd;
+ int fdno = Fileno(ofd);
if (_rpmio_debug)
fprintf(stderr, "*** Fdopen(%p,%s) %s\n", fd, fmode, fdbg(fd));
- if (fd == NULL || fmode == NULL)
+ if (fd == NULL || fmode == NULL || fdno < 0)
return NULL;
cvtfmode(fmode, stdio, sizeof(stdio), other, sizeof(other), &end, NULL);
@@ -1396,37 +1544,16 @@ fprintf(stderr, "*** Fdopen(%p,%s) %s\n", fd, fmode, fdbg(fd));
return fd;
if (end && *end) {
- if (rstreq(end, "fdio")) {
- iof = fdio;
- } else if (rstreq(end, "gzdio") || rstreq(end, "gzip")) {
- iof = gzdio;
- fd = gzdFdopen(fd, zstdio);
-#if HAVE_BZLIB_H
- } else if (rstreq(end, "bzdio") || rstreq(end, "bzip2")) {
- iof = bzdio;
- fd = bzdFdopen(fd, zstdio);
-#endif
-#if HAVE_LZMA_H
- } else if (rstreq(end, "xzdio") || rstreq(end, "xz")) {
- iof = xzdio;
- fd = xzdFdopen(fd, zstdio);
- } else if (rstreq(end, "lzdio") || rstreq(end, "lzma")) {
- iof = lzdio;
- fd = lzdFdopen(fd, zstdio);
-#endif
- } else if (rstreq(end, "ufdio")) {
- iof = ufdio;
- }
+ iot = findIOT(end);
} else if (other[0] != '\0') {
for (end = other; *end && strchr("0123456789fh", *end); end++)
{};
- if (*end == '\0') {
- iof = gzdio;
- fd = gzdFdopen(fd, zstdio);
- }
+ if (*end == '\0')
+ iot = findIOT("gzdio");
}
- if (iof == NULL)
- return fd;
+
+ if (iot && iot->_fdopen)
+ fd = iot->_fdopen(fd, fdno, zstdio);
DBGIO(fd, (stderr, "==> Fdopen(%p,\"%s\") returns fd %p %s\n", ofd, fmode, (fd ? fd : NULL), fdbg(fd)));
return fd;
@@ -1438,7 +1565,7 @@ FD_t Fopen(const char *path, const char *fmode)
const char *end = NULL;
mode_t perms = 0666;
int flags = 0;
- FD_t fd;
+ FD_t fd = NULL;
if (path == NULL || fmode == NULL)
return NULL;
@@ -1449,39 +1576,16 @@ FD_t Fopen(const char *path, const char *fmode)
return NULL;
if (end == NULL || rstreq(end, "fdio")) {
-if (_rpmio_debug)
-fprintf(stderr, "*** Fopen fdio path %s fmode %s\n", path, fmode);
+ if (_rpmio_debug)
+ fprintf(stderr, "*** Fopen fdio path %s fmode %s\n", path, fmode);
fd = fdOpen(path, flags, perms);
- if (fdFileno(fd) < 0) {
- if (fd) (void) fdClose(fd);
- return NULL;
- }
} else {
- /* XXX gzdio and bzdio here too */
-
- switch (urlIsURL(path)) {
- case URL_IS_HTTPS:
- case URL_IS_HTTP:
- case URL_IS_HKP:
- case URL_IS_PATH:
- case URL_IS_DASH:
- case URL_IS_FTP:
- case URL_IS_UNKNOWN:
-if (_rpmio_debug)
-fprintf(stderr, "*** Fopen ufdio path %s fmode %s\n", path, fmode);
- fd = ufdOpen(path, flags, perms);
- if (fd == NULL || !(fdFileno(fd) >= 0))
- return fd;
- break;
- default:
-if (_rpmio_debug)
-fprintf(stderr, "*** Fopen WTFO path %s fmode %s\n", path, fmode);
- return NULL;
- break;
- }
-
+ if (_rpmio_debug)
+ fprintf(stderr, "*** Fopen ufdio path %s fmode %s\n", path, fmode);
+ fd = ufdOpen(path, flags, perms);
}
+ /* Open compressed stream if necessary */
if (fd)
fd = Fdopen(fd, fmode);
@@ -1495,9 +1599,10 @@ int Fflush(FD_t fd)
{
int rc = -1;
if (fd != NULL) {
- fdio_fflush_function_t _fflush = FDIOVEC(fd, _fflush);
+ FDSTACK_t fps = fdGetFps(fd);
+ fdio_fflush_function_t _fflush = FDIOVEC(fps, _fflush);
- rc = (_fflush ? _fflush(fd) : -2);
+ rc = (_fflush ? _fflush(fps) : -2);
}
return rc;
}
@@ -1506,42 +1611,25 @@ off_t Ftell(FD_t fd)
{
off_t pos = -1;
if (fd != NULL) {
- fdio_ftell_function_t _ftell = FDIOVEC(fd, _ftell);
+ FDSTACK_t fps = fdGetFps(fd);
+ fdio_ftell_function_t _ftell = FDIOVEC(fps, _ftell);
- pos = (_ftell ? _ftell(fd) : -2);
+ pos = (_ftell ? _ftell(fps) : -2);
}
return pos;
}
int Ferror(FD_t fd)
{
- int i, rc = 0;
+ int rc = 0;
if (fd == NULL) return -1;
- for (i = fd->nfps; rc == 0 && i >= 0; i--) {
- FDSTACK_t * fps = &fd->fps[i];
- int ec;
-
- if (fps->io == gzdio) {
- ec = (fd->syserrno || fd->errcookie != NULL) ? -1 : 0;
- i--; /* XXX fdio under gzdio always has fdno == -1 */
-#if HAVE_BZLIB_H
- } else if (fps->io == bzdio) {
- ec = (fd->syserrno || fd->errcookie != NULL) ? -1 : 0;
- i--; /* XXX fdio under bzdio always has fdno == -1 */
-#endif
-#if HAVE_LZMA_H
- } else if (fps->io == xzdio || fps->io == lzdio) {
- ec = (fd->syserrno || fd->errcookie != NULL) ? -1 : 0;
- i--; /* XXX fdio under xzdio/lzdio always has fdno == -1 */
-#endif
- } else {
- /* XXX need to check ufdio/gzdio/bzdio/fdio errors correctly. */
- ec = (fdFileno(fd) < 0 ? -1 : 0);
- }
+ for (FDSTACK_t fps = fd->fps; fps != NULL; fps = fps->prev) {
+ fdio_ferror_function_t _ferror = FDIOVEC(fps, _ferror);
+ rc = _ferror(fps);
- if (rc == 0 && ec)
- rc = ec;
+ if (rc)
+ break;
}
DBGIO(fd, (stderr, "==> Ferror(%p) rc %d %s\n", fd, rc, fdbg(fd)));
return rc;
@@ -1549,11 +1637,13 @@ DBGIO(fd, (stderr, "==> Ferror(%p) rc %d %s\n", fd, rc, fdbg(fd)));
int Fileno(FD_t fd)
{
- int i, rc = -1;
+ int rc = -1;
if (fd == NULL) return -1;
- for (i = fd->nfps ; rc == -1 && i >= 0; i--) {
- rc = fd->fps[i].fdno;
+ for (FDSTACK_t fps = fd->fps; fps != NULL; fps = fps->prev) {
+ rc = fps->fdno;
+ if (rc != -1)
+ break;
}
DBGIO(fd, (stderr, "==> Fileno(%p) rc %d %s\n", (fd ? fd : NULL), rc, fdbg(fd)));
@@ -1627,11 +1717,16 @@ exit:
void fdInitDigest(FD_t fd, int hashalgo, rpmDigestFlags flags)
{
+ return fdInitDigestID(fd, hashalgo, hashalgo, flags);
+}
+
+void fdInitDigestID(FD_t fd, int hashalgo, int id, rpmDigestFlags flags)
+{
if (fd->digests == NULL) {
fd->digests = rpmDigestBundleNew();
}
fdstat_enter(fd, FDSTAT_DIGEST);
- rpmDigestBundleAdd(fd->digests, hashalgo, flags);
+ rpmDigestBundleAddID(fd->digests, hashalgo, id, flags);
fdstat_exit(fd, FDSTAT_DIGEST, (ssize_t) 0);
}
@@ -1644,14 +1739,22 @@ static void fdUpdateDigests(FD_t fd, const void * buf, size_t buflen)
}
}
-void fdFiniDigest(FD_t fd, int hashalgo,
+void fdFiniDigest(FD_t fd, int id,
void ** datap, size_t * lenp, int asAscii)
{
if (fd && fd->digests) {
fdstat_enter(fd, FDSTAT_DIGEST);
- rpmDigestBundleFinal(fd->digests, hashalgo, datap, lenp, asAscii);
+ rpmDigestBundleFinal(fd->digests, id, datap, lenp, asAscii);
fdstat_exit(fd, FDSTAT_DIGEST, (ssize_t) 0);
}
}
+DIGEST_CTX fdDupDigest(FD_t fd, int id)
+{
+ DIGEST_CTX ctx = NULL;
+ if (fd && fd->digests)
+ ctx = rpmDigestBundleDupCtx(fd->digests, id);
+
+ return ctx;
+}
diff --git a/rpmio/rpmio.h b/rpmio/rpmio.h
index 8cebe16ca..9bd108649 100644
--- a/rpmio/rpmio.h
+++ b/rpmio/rpmio.h
@@ -4,6 +4,7 @@
/** \ingroup rpmio
* \file rpmio/rpmio.h
*
+ * RPM I/O API (Fd_t is RPM equivalent to libc's FILE)
*/
#include <sys/types.h>
diff --git a/rpmio/rpmio_internal.h b/rpmio/rpmio_internal.h
index 8c9f1a81a..fbed183b0 100644
--- a/rpmio/rpmio_internal.h
+++ b/rpmio/rpmio_internal.h
@@ -13,20 +13,24 @@ extern "C" {
#endif
void fdSetBundle(FD_t fd, rpmDigestBundle bundle);
-rpmDigestBundle fdGetBundle(FD_t fd);
+rpmDigestBundle fdGetBundle(FD_t fd, int create);
/** \ingroup rpmio
* Attach digest to fd.
*/
void fdInitDigest(FD_t fd, int hashalgo, rpmDigestFlags flags);
+void fdInitDigestID(FD_t fd, int hashalgo, int id, rpmDigestFlags flags);
+
/** \ingroup rpmio
*/
-void fdFiniDigest(FD_t fd, int hashalgo,
+void fdFiniDigest(FD_t fd, int id,
void ** datap,
size_t * lenp,
int asAscii);
+DIGEST_CTX fdDupDigest(FD_t fd, int id);
+
/**
* Read an entire file into a buffer.
* @param fn file name to read
diff --git a/rpmio/rpmkeyring.c b/rpmio/rpmkeyring.c
index 18fdfa01c..4e14de1e5 100644
--- a/rpmio/rpmkeyring.c
+++ b/rpmio/rpmkeyring.c
@@ -1,5 +1,7 @@
#include "system.h"
+#include <pthread.h>
+
#include <rpm/rpmstring.h>
#include <rpm/rpmpgp.h>
#include <rpm/rpmfileutil.h>
@@ -17,17 +19,16 @@ struct rpmPubkey_s {
pgpKeyID_t keyid;
pgpDigParams pgpkey;
int nrefs;
+ pthread_rwlock_t lock;
};
struct rpmKeyring_s {
struct rpmPubkey_s **keys;
size_t numkeys;
int nrefs;
+ pthread_rwlock_t lock;
};
-static rpmPubkey rpmPubkeyUnlink(rpmPubkey key);
-static rpmKeyring rpmKeyringUnlink(rpmKeyring keyring);
-
static int keyidcmp(const void *k1, const void *k2)
{
const struct rpmPubkey_s *key1 = *(const struct rpmPubkey_s **) k1;
@@ -41,27 +42,30 @@ rpmKeyring rpmKeyringNew(void)
rpmKeyring keyring = xcalloc(1, sizeof(*keyring));
keyring->keys = NULL;
keyring->numkeys = 0;
- keyring->nrefs = 0;
- return rpmKeyringLink(keyring);
+ keyring->nrefs = 1;
+ pthread_rwlock_init(&keyring->lock, NULL);
+ return keyring;
}
rpmKeyring rpmKeyringFree(rpmKeyring keyring)
{
- if (keyring == NULL) {
+ if (keyring == NULL)
return NULL;
- }
-
- if (keyring->nrefs > 1) {
- return rpmKeyringUnlink(keyring);
- }
- if (keyring->keys) {
- for (int i = 0; i < keyring->numkeys; i++) {
- keyring->keys[i] = rpmPubkeyFree(keyring->keys[i]);
+ pthread_rwlock_wrlock(&keyring->lock);
+ if (--keyring->nrefs == 0) {
+ if (keyring->keys) {
+ for (int i = 0; i < keyring->numkeys; i++) {
+ keyring->keys[i] = rpmPubkeyFree(keyring->keys[i]);
+ }
+ free(keyring->keys);
}
- free(keyring->keys);
+ pthread_rwlock_unlock(&keyring->lock);
+ pthread_rwlock_destroy(&keyring->lock);
+ free(keyring);
+ } else {
+ pthread_rwlock_unlock(&keyring->lock);
}
- free(keyring);
return NULL;
}
@@ -74,38 +78,36 @@ static rpmPubkey rpmKeyringFindKeyid(rpmKeyring keyring, rpmPubkey key)
int rpmKeyringAddKey(rpmKeyring keyring, rpmPubkey key)
{
+ int rc = 1; /* assume already seen key */
if (keyring == NULL || key == NULL)
return -1;
- /* check if we already have this key */
- if (rpmKeyringFindKeyid(keyring, key)) {
- return 1;
+ /* check if we already have this key, but always wrlock for simplicity */
+ pthread_rwlock_wrlock(&keyring->lock);
+ if (!rpmKeyringFindKeyid(keyring, key)) {
+ keyring->keys = xrealloc(keyring->keys,
+ (keyring->numkeys + 1) * sizeof(rpmPubkey));
+ keyring->keys[keyring->numkeys] = rpmPubkeyLink(key);
+ keyring->numkeys++;
+ qsort(keyring->keys, keyring->numkeys, sizeof(*keyring->keys),
+ keyidcmp);
+ rc = 0;
}
-
- keyring->keys = xrealloc(keyring->keys, (keyring->numkeys + 1) * sizeof(rpmPubkey));
- keyring->keys[keyring->numkeys] = rpmPubkeyLink(key);
- keyring->numkeys++;
- qsort(keyring->keys, keyring->numkeys, sizeof(*keyring->keys), keyidcmp);
+ pthread_rwlock_unlock(&keyring->lock);
- return 0;
+ return rc;
}
rpmKeyring rpmKeyringLink(rpmKeyring keyring)
{
if (keyring) {
+ pthread_rwlock_wrlock(&keyring->lock);
keyring->nrefs++;
+ pthread_rwlock_unlock(&keyring->lock);
}
return keyring;
}
-static rpmKeyring rpmKeyringUnlink(rpmKeyring keyring)
-{
- if (keyring) {
- keyring->nrefs--;
- }
- return NULL;
-}
-
rpmPubkey rpmPubkeyRead(const char *filename)
{
uint8_t *pkt = NULL;
@@ -131,7 +133,7 @@ rpmPubkey rpmPubkeyNew(const uint8_t *pkt, size_t pktlen)
if (pkt == NULL || pktlen == 0)
goto exit;
- if (pgpPubkeyFingerprint(pkt, pktlen, keyid))
+ if (pgpPubkeyKeyID(pkt, pktlen, keyid))
goto exit;
if (pgpPrtParams(pkt, pktlen, PGPTAG_PUBLIC_KEY, &pgpkey))
@@ -141,12 +143,45 @@ rpmPubkey rpmPubkeyNew(const uint8_t *pkt, size_t pktlen)
key->pkt = xmalloc(pktlen);
key->pktlen = pktlen;
key->pgpkey = pgpkey;
- key->nrefs = 0;
+ key->nrefs = 1;
memcpy(key->pkt, pkt, pktlen);
memcpy(key->keyid, keyid, sizeof(keyid));
+ pthread_rwlock_init(&key->lock, NULL);
exit:
- return rpmPubkeyLink(key);
+ return key;
+}
+
+rpmPubkey *rpmGetSubkeys(rpmPubkey mainkey, int *count)
+{
+ rpmPubkey *subkeys = NULL;
+ pgpDigParams *pgpsubkeys = NULL;
+ int pgpsubkeysCount = 0;
+ int i;
+
+ if (mainkey && !pgpPrtParamsSubkeys(mainkey->pkt, mainkey->pktlen,
+ mainkey->pgpkey, &pgpsubkeys, &pgpsubkeysCount)) {
+
+ subkeys = xmalloc(pgpsubkeysCount * sizeof(*subkeys));
+
+ for (i = 0; i < pgpsubkeysCount; i++) {
+ rpmPubkey subkey = xcalloc(1, sizeof(*subkey));
+ subkeys[i] = subkey;
+
+ /* Packets with all subkeys already stored in main key */
+ subkey->pkt = NULL;
+ subkey->pktlen = 0;
+
+ subkey->pgpkey = pgpsubkeys[i];
+ memcpy(subkey->keyid, pgpsubkeys[i]->signid, sizeof(subkey->keyid));
+ subkey->nrefs = 1;
+ pthread_rwlock_init(&subkey->lock, NULL);
+ }
+ free(pgpsubkeys);
+ }
+ *count = pgpsubkeysCount;
+
+ return subkeys;
}
rpmPubkey rpmPubkeyFree(rpmPubkey key)
@@ -154,31 +189,29 @@ rpmPubkey rpmPubkeyFree(rpmPubkey key)
if (key == NULL)
return NULL;
- if (key->nrefs > 1)
- return rpmPubkeyUnlink(key);
-
- pgpDigParamsFree(key->pgpkey);
- free(key->pkt);
- free(key);
+ pthread_rwlock_wrlock(&key->lock);
+ if (--key->nrefs == 0) {
+ pgpDigParamsFree(key->pgpkey);
+ free(key->pkt);
+ pthread_rwlock_unlock(&key->lock);
+ pthread_rwlock_destroy(&key->lock);
+ free(key);
+ } else {
+ pthread_rwlock_unlock(&key->lock);
+ }
return NULL;
}
rpmPubkey rpmPubkeyLink(rpmPubkey key)
{
if (key) {
+ pthread_rwlock_wrlock(&key->lock);
key->nrefs++;
+ pthread_rwlock_unlock(&key->lock);
}
return key;
}
-static rpmPubkey rpmPubkeyUnlink(rpmPubkey key)
-{
- if (key) {
- key->nrefs--;
- }
- return NULL;
-}
-
pgpDig rpmPubkeyDig(rpmPubkey key)
{
pgpDig dig = NULL;
@@ -189,12 +222,15 @@ pgpDig rpmPubkeyDig(rpmPubkey key)
return NULL;
dig = pgpNewDig();
+
+ pthread_rwlock_rdlock(&key->lock);
rc = pgpPrtPkts(key->pkt, key->pktlen, dig, 0);
+ pthread_rwlock_unlock(&key->lock);
+
if (rc == 0) {
pgpDigParams pubp = pgpDigGetParams(dig, PGPTAG_PUBLIC_KEY);
if (!pubp || !memcmp(pubp->signid, zeros, sizeof(pubp->signid)) ||
- !memcmp(pubp->time, zeros, sizeof(pubp->time)) ||
- pubp->userid == NULL) {
+ pubp->time == 0 || pubp->userid == NULL) {
rc = -1;
}
}
@@ -210,11 +246,23 @@ char * rpmPubkeyBase64(rpmPubkey key)
char *enc = NULL;
if (key) {
+ pthread_rwlock_rdlock(&key->lock);
enc = rpmBase64Encode(key->pkt, key->pktlen, -1);
+ pthread_rwlock_unlock(&key->lock);
}
return enc;
}
+pgpDigParams rpmPubkeyPgpDigParams(rpmPubkey key)
+{
+ pgpDigParams params= NULL;
+
+ if (key) {
+ params = key->pgpkey;
+ }
+ return params;
+}
+
static rpmPubkey findbySig(rpmKeyring keyring, pgpDigParams sig)
{
rpmPubkey key = NULL;
@@ -239,6 +287,8 @@ static rpmPubkey findbySig(rpmKeyring keyring, pgpDigParams sig)
rpmRC rpmKeyringLookup(rpmKeyring keyring, pgpDig sig)
{
+ pthread_rwlock_rdlock(&keyring->lock);
+
rpmRC res = RPMRC_NOKEY;
pgpDigParams sigp = pgpDigGetParams(sig, PGPTAG_SIGNATURE);
rpmPubkey key = findbySig(keyring, sigp);
@@ -253,6 +303,7 @@ rpmRC rpmKeyringLookup(rpmKeyring keyring, pgpDig sig)
res = RPMRC_OK;
}
+ pthread_rwlock_unlock(&keyring->lock);
return res;
}
@@ -261,6 +312,8 @@ rpmRC rpmKeyringVerifySig(rpmKeyring keyring, pgpDigParams sig, DIGEST_CTX ctx)
rpmRC rc = RPMRC_FAIL;
if (sig && ctx) {
+ pthread_rwlock_rdlock(&keyring->lock);
+
pgpDigParams pgpkey = NULL;
rpmPubkey key = findbySig(keyring, sig);
@@ -269,6 +322,8 @@ rpmRC rpmKeyringVerifySig(rpmKeyring keyring, pgpDigParams sig, DIGEST_CTX ctx)
/* We call verify even if key not found for a signature sanity check */
rc = pgpVerifySignature(pgpkey, sig, ctx);
+
+ pthread_rwlock_unlock(&keyring->lock);
}
return rc;
diff --git a/rpmio/rpmkeyring.h b/rpmio/rpmkeyring.h
index 9fcab5feb..8aeed8c6c 100644
--- a/rpmio/rpmkeyring.h
+++ b/rpmio/rpmkeyring.h
@@ -3,6 +3,8 @@
/** \ingroup rpmkeyring
* \file rpmio/rpmkeyring.h
+ *
+ * RPM keyring API
*/
#include <rpm/rpmtypes.h>
@@ -65,6 +67,14 @@ rpmKeyring rpmKeyringLink(rpmKeyring keyring);
rpmPubkey rpmPubkeyNew(const uint8_t *pkt, size_t pktlen);
/** \ingroup rpmkeyring
+ * Return array of subkeys belonging to maikey
+ * param mainkey main rpmPubkey
+ * param count count of returned subkeys
+ * @return an array of subkey's handles
+ */
+rpmPubkey *rpmGetSubkeys(rpmPubkey mainkey, int *count);
+
+/** \ingroup rpmkeyring
* Create a new rpmPubkey from ASCII-armored pubkey file
* @param filename Path to pubkey file
* @return new pubkey handle
@@ -99,6 +109,13 @@ pgpDig rpmPubkeyDig(rpmPubkey key);
*/
char * rpmPubkeyBase64(rpmPubkey key);
+/** \ingroup rpmkeyring
+ * Return pgp params of key
+ * @param key Pubkey
+ * @return pgp params, NULL on error
+ */
+pgpDigParams rpmPubkeyPgpDigParams(rpmPubkey key);
+
#ifdef __cplusplus
}
#endif
diff --git a/rpmio/rpmlog.c b/rpmio/rpmlog.c
index 8023d5c44..223af32aa 100644
--- a/rpmio/rpmlog.c
+++ b/rpmio/rpmlog.c
@@ -5,11 +5,22 @@
#include "system.h"
#include <stdarg.h>
#include <stdlib.h>
+#include <pthread.h>
+#include <errno.h>
#include <rpm/rpmlog.h>
+#include <rpm/rpmmacro.h>
#include "debug.h"
-static int nrecs = 0;
-static rpmlogRec recs = NULL;
+typedef struct rpmlogCtx_s * rpmlogCtx;
+struct rpmlogCtx_s {
+ pthread_rwlock_t lock;
+ unsigned mask;
+ int nrecs;
+ rpmlogRec recs;
+ rpmlogCallback cbfunc;
+ rpmlogCallbackData cbdata;
+ FILE *stdlog;
+};
struct rpmlogRec_s {
int code; /* unused */
@@ -17,64 +28,110 @@ struct rpmlogRec_s {
char * message; /* log message string */
};
+/* Force log context acquisition through a function */
+static rpmlogCtx rpmlogCtxAcquire(int write)
+{
+ static struct rpmlogCtx_s _globalCtx = { PTHREAD_RWLOCK_INITIALIZER,
+ RPMLOG_UPTO(RPMLOG_NOTICE),
+ 0, NULL, NULL, NULL, NULL };
+ rpmlogCtx ctx = &_globalCtx;
+ int xx;
+
+ /* XXX Silently failing is bad, but we can't very well use log here... */
+ if (write)
+ xx = pthread_rwlock_wrlock(&ctx->lock);
+ else
+ xx = pthread_rwlock_rdlock(&ctx->lock);
+
+ return (xx == 0) ? ctx : NULL;
+}
+
+/* Release log context */
+static rpmlogCtx rpmlogCtxRelease(rpmlogCtx ctx)
+{
+ if (ctx)
+ pthread_rwlock_unlock(&ctx->lock);
+ return NULL;
+}
+
int rpmlogGetNrecs(void)
{
+ rpmlogCtx ctx = rpmlogCtxAcquire(0);
+ int nrecs = -1;
+ if (ctx)
+ nrecs = ctx->nrecs;
+ rpmlogCtxRelease(ctx);
return nrecs;
}
int rpmlogCode(void)
{
- if (recs != NULL && nrecs > 0)
- return recs[nrecs-1].code;
- return -1;
-}
+ int code = -1;
+ rpmlogCtx ctx = rpmlogCtxAcquire(0);
+
+ if (ctx && ctx->recs != NULL && ctx->nrecs > 0)
+ code = ctx->recs[ctx->nrecs-1].code;
+ rpmlogCtxRelease(ctx);
+ return code;
+}
const char * rpmlogMessage(void)
{
- if (recs != NULL && nrecs > 0)
- return recs[nrecs-1].message;
- return _("(no error)");
+ const char *msg = _("(no error)");
+ rpmlogCtx ctx = rpmlogCtxAcquire(0);
+
+ if (ctx && ctx->recs != NULL && ctx->nrecs > 0)
+ msg = ctx->recs[ctx->nrecs-1].message;
+
+ rpmlogCtxRelease(ctx);
+ return msg;
}
const char * rpmlogRecMessage(rpmlogRec rec)
{
- assert(rec != NULL);
- return (rec->message);
+ return (rec != NULL) ? rec->message : NULL;
}
rpmlogLvl rpmlogRecPriority(rpmlogRec rec)
{
- assert(rec != NULL);
- return (rec->pri);
+ return (rec != NULL) ? rec->pri : (rpmlogLvl)-1;
}
void rpmlogPrint(FILE *f)
{
- int i;
+ rpmlogCtx ctx = rpmlogCtxAcquire(0);
+
+ if (ctx == NULL)
+ return;
if (f == NULL)
f = stderr;
- if (recs)
- for (i = 0; i < nrecs; i++) {
- rpmlogRec rec = recs + i;
+ for (int i = 0; i < ctx->nrecs; i++) {
+ rpmlogRec rec = ctx->recs + i;
if (rec->message && *rec->message)
fprintf(f, " %s", rec->message);
}
+
+ rpmlogCtxRelease(ctx);
}
void rpmlogClose (void)
{
- int i;
+ rpmlogCtx ctx = rpmlogCtxAcquire(1);
- if (recs)
- for (i = 0; i < nrecs; i++) {
- rpmlogRec rec = recs + i;
+ if (ctx == NULL)
+ return;
+
+ for (int i = 0; i < ctx->nrecs; i++) {
+ rpmlogRec rec = ctx->recs + i;
rec->message = _free(rec->message);
}
- recs = _free(recs);
- nrecs = 0;
+ ctx->recs = _free(ctx->recs);
+ ctx->nrecs = 0;
+
+ rpmlogCtxRelease(ctx);
}
void rpmlogOpen (const char *ident, int option,
@@ -82,65 +139,51 @@ void rpmlogOpen (const char *ident, int option,
{
}
-static unsigned rpmlogMask = RPMLOG_UPTO( RPMLOG_NOTICE );
-
#ifdef NOTYET
static unsigned rpmlogFacility = RPMLOG_USER;
#endif
int rpmlogSetMask (int mask)
{
- int omask = rpmlogMask;
- if (mask)
- rpmlogMask = mask;
- return omask;
-}
+ rpmlogCtx ctx = rpmlogCtxAcquire(mask ? 1 : 0);
-static rpmlogCallback _rpmlogCallback = NULL;
-static rpmlogCallbackData _rpmlogCallbackData = NULL;
+ int omask = -1;
+ if (ctx) {
+ omask = ctx->mask;
+ if (mask)
+ ctx->mask = mask;
+ }
-rpmlogCallback rpmlogSetCallback(rpmlogCallback cb, rpmlogCallbackData data)
-{
- rpmlogCallback ocb = _rpmlogCallback;
- _rpmlogCallback = cb;
- _rpmlogCallbackData = data;
- return ocb;
+ rpmlogCtxRelease(ctx);
+ return omask;
}
-static FILE * _stdlog = NULL;
-
-static int rpmlogDefault(rpmlogRec rec)
+rpmlogCallback rpmlogSetCallback(rpmlogCallback cb, rpmlogCallbackData data)
{
- FILE *msgout = (_stdlog ? _stdlog : stderr);
+ rpmlogCtx ctx = rpmlogCtxAcquire(1);
- switch (rec->pri) {
- case RPMLOG_INFO:
- case RPMLOG_NOTICE:
- msgout = (_stdlog ? _stdlog : stdout);
- break;
- case RPMLOG_EMERG:
- case RPMLOG_ALERT:
- case RPMLOG_CRIT:
- case RPMLOG_ERR:
- case RPMLOG_WARNING:
- case RPMLOG_DEBUG:
- default:
- break;
+ rpmlogCallback ocb = NULL;
+ if (ctx) {
+ ocb = ctx->cbfunc;
+ ctx->cbfunc = cb;
+ ctx->cbdata = data;
}
- (void) fputs(rpmlogLevelPrefix(rec->pri), msgout);
-
- (void) fputs(rec->message, msgout);
- (void) fflush(msgout);
-
- return (rec->pri <= RPMLOG_CRIT ? RPMLOG_EXIT : 0);
+ rpmlogCtxRelease(ctx);
+ return ocb;
}
-
FILE * rpmlogSetFile(FILE * fp)
{
- FILE * ofp = _stdlog;
- _stdlog = fp;
+ rpmlogCtx ctx = rpmlogCtxAcquire(1);
+
+ FILE * ofp = NULL;
+ if (ctx) {
+ ofp = ctx->stdlog;
+ ctx->stdlog = fp;
+ }
+
+ rpmlogCtxRelease(ctx);
return ofp;
}
@@ -155,6 +198,38 @@ static const char * const rpmlogMsgPrefix[] = {
"D: ", /*!< RPMLOG_DEBUG */
};
+#define ANSI_COLOR_BLACK "\x1b[30m"
+#define ANSI_COLOR_RED "\x1b[31m"
+#define ANSI_COLOR_GREEN "\x1b[32m"
+#define ANSI_COLOR_YELLOW "\x1b[33m"
+#define ANSI_COLOR_BLUE "\x1b[34m"
+#define ANSI_COLOR_MAGENTA "\x1b[35m"
+#define ANSI_COLOR_CYAN "\x1b[36m"
+#define ANSI_COLOR_WHITE "\x1b[37m"
+
+#define ANSI_BRIGHT_BLACK "\x1b[30;1m"
+#define ANSI_BRIGHT_RED "\x1b[31;1m"
+#define ANSI_BRIGHT_GREEN "\x1b[32;1m"
+#define ANSI_BRIGHT_YELLOW "\x1b[33;1m"
+#define ANSI_BRIGHT_BLUE "\x1b[34;1m"
+#define ANSI_BRIGHT_MAGENTA "\x1b[35;1m"
+#define ANSI_BRIGHT_CYAN "\x1b[36;1m"
+#define ANSI_BRIGHT_WHITE "\x1b[37;1m"
+
+#define ANSI_COLOR_BOLD "\x1b[1m"
+#define ANSI_COLOR_RESET "\x1b[0m"
+
+static const char *rpmlogMsgPrefixColor[] = {
+ ANSI_BRIGHT_RED, /*!< RPMLOG_EMERG */
+ ANSI_BRIGHT_RED, /*!< RPMLOG_ALERT */
+ ANSI_BRIGHT_RED, /*!< RPMLOG_CRIT */
+ ANSI_BRIGHT_RED, /*!< RPMLOG_ERR */
+ ANSI_BRIGHT_MAGENTA,/*!< RPMLOG_WARNING */
+ "", /*!< RPMLOG_NOTICE */
+ "", /*!< RPMLOG_INFO */
+ ANSI_BRIGHT_BLUE, /*!< RPMLOG_DEBUG */
+};
+
const char * rpmlogLevelPrefix(rpmlogLvl pri)
{
const char * prefix = "";
@@ -163,46 +238,174 @@ const char * rpmlogLevelPrefix(rpmlogLvl pri)
return prefix;
}
+static const char * rpmlogLevelColor(rpmlogLvl pri)
+{
+ return rpmlogMsgPrefixColor[pri&0x7];
+}
+
+enum {
+ COLOR_NO = 0,
+ COLOR_AUTO = 1,
+ COLOR_ALWAYS = 2,
+};
+
+static int getColorConfig(void)
+{
+ int rc = COLOR_NO;
+ char * color = rpmExpand("%{?_color_output}%{!?_color_output:auto}", NULL);
+ if (rstreq(color, "auto"))
+ rc = COLOR_AUTO;
+ else if (rstreq(color, "always"))
+ rc = COLOR_ALWAYS;
+ free(color);
+ return rc;
+}
+
+static int rpmlogDefault(FILE *stdlog, rpmlogRec rec)
+{
+ static const char fubar[] =
+ "Error occurred during writing of a log message";
+ FILE *msgout = (stdlog ? stdlog : stderr);
+ static __thread int color = -1;
+ const char * colorOn = NULL;
+
+ if (color < 0)
+ color = getColorConfig();
+
+ if (color == COLOR_ALWAYS ||
+ (color == COLOR_AUTO && isatty(fileno(msgout))))
+ colorOn = rpmlogLevelColor(rec->pri);
+
+ switch (rec->pri) {
+ case RPMLOG_INFO:
+ case RPMLOG_NOTICE:
+ msgout = (stdlog ? stdlog : stdout);
+ break;
+ case RPMLOG_EMERG:
+ case RPMLOG_ALERT:
+ case RPMLOG_CRIT:
+ case RPMLOG_ERR:
+ case RPMLOG_WARNING:
+ case RPMLOG_DEBUG:
+ if (colorOn && *colorOn)
+ if (fputs(rpmlogLevelColor(rec->pri), msgout) == EOF
+ && errno != EPIPE)
+ perror(fubar);
+ break;
+ default:
+ break;
+ }
+
+ if (fputs(rpmlogLevelPrefix(rec->pri), msgout) == EOF && errno != EPIPE)
+ perror(fubar);
+
+ switch (rec->pri) {
+ case RPMLOG_INFO:
+ case RPMLOG_NOTICE:
+ break;
+ case RPMLOG_EMERG:
+ case RPMLOG_ALERT:
+ case RPMLOG_CRIT:
+ case RPMLOG_ERR:
+ case RPMLOG_WARNING:
+ if (colorOn && *colorOn) {
+ if (fputs(ANSI_COLOR_RESET, msgout) == EOF && errno != EPIPE)
+ perror(fubar);
+ if (fputs(ANSI_COLOR_BOLD, msgout) == EOF && errno != EPIPE)
+ perror(fubar);
+ }
+ case RPMLOG_DEBUG:
+ default:
+ break;
+ }
+
+ if (rec->message)
+ (void) fputs(rec->message, msgout);
+
+ switch (rec->pri) {
+ case RPMLOG_INFO:
+ case RPMLOG_NOTICE:
+ break;
+ case RPMLOG_EMERG:
+ case RPMLOG_ALERT:
+ case RPMLOG_CRIT:
+ case RPMLOG_ERR:
+ case RPMLOG_WARNING:
+ case RPMLOG_DEBUG:
+ if (colorOn && *colorOn)
+ if (fputs(ANSI_COLOR_RESET, msgout) == EPIPE && errno != EPIPE)
+ perror(fubar);
+ break;
+ default:
+ break;
+ }
+
+ (void) fflush(msgout);
+
+ return (rec->pri <= RPMLOG_CRIT ? RPMLOG_EXIT : 0);
+}
+
/* FIX: rpmlogMsgPrefix[] dependent, not unqualified */
/* FIX: rpmlogMsgPrefix[] may be NULL */
-static void dolog (struct rpmlogRec_s *rec)
+static void dolog(struct rpmlogRec_s *rec, int saverec)
{
+ static pthread_mutex_t serialize = PTHREAD_MUTEX_INITIALIZER;
+
int cbrc = RPMLOG_DEFAULT;
int needexit = 0;
+ FILE *clog = NULL;
+ rpmlogCallbackData *cbdata = NULL;
+ rpmlogCallback cbfunc = NULL;
+ rpmlogCtx ctx = rpmlogCtxAcquire(saverec);
+
+ if (ctx == NULL)
+ return;
/* Save copy of all messages at warning (or below == "more important"). */
- if (rec->pri <= RPMLOG_WARNING) {
- recs = xrealloc(recs, (nrecs+2) * sizeof(*recs));
- recs[nrecs].code = rec->code;
- recs[nrecs].pri = rec->pri;
- recs[nrecs].message = xstrdup(rec->message);
- recs[nrecs+1].code = 0;
- recs[nrecs+1].message = NULL;
- ++nrecs;
+ if (saverec) {
+ ctx->recs = xrealloc(ctx->recs, (ctx->nrecs+2) * sizeof(*ctx->recs));
+ ctx->recs[ctx->nrecs].code = rec->code;
+ ctx->recs[ctx->nrecs].pri = rec->pri;
+ ctx->recs[ctx->nrecs].message = xstrdup(rec->message);
+ ctx->recs[ctx->nrecs+1].code = 0;
+ ctx->recs[ctx->nrecs+1].message = NULL;
+ ctx->nrecs++;
}
-
- if (_rpmlogCallback) {
- cbrc = _rpmlogCallback(rec, _rpmlogCallbackData);
- needexit += cbrc & RPMLOG_EXIT;
- }
-
- if (cbrc & RPMLOG_DEFAULT) {
- cbrc = rpmlogDefault(rec);
- needexit += cbrc & RPMLOG_EXIT;
+ cbfunc = ctx->cbfunc;
+ cbdata = ctx->cbdata;
+ clog = ctx->stdlog;
+
+ /* Free the context for callback and actual log output */
+ ctx = rpmlogCtxRelease(ctx);
+
+ /* Always serialize callback and output to avoid interleaved messages. */
+ if (pthread_mutex_lock(&serialize) == 0) {
+ if (cbfunc) {
+ cbrc = cbfunc(rec, cbdata);
+ needexit += cbrc & RPMLOG_EXIT;
+ }
+
+ if (cbrc & RPMLOG_DEFAULT) {
+ cbrc = rpmlogDefault(clog, rec);
+ needexit += cbrc & RPMLOG_EXIT;
+ }
+ pthread_mutex_unlock(&serialize);
}
if (needexit)
exit(EXIT_FAILURE);
+
}
void rpmlog (int code, const char *fmt, ...)
{
unsigned pri = RPMLOG_PRI(code);
unsigned mask = RPMLOG_MASK(pri);
+ int saverec = (pri <= RPMLOG_WARNING);
va_list ap;
int n;
- if ((mask & rpmlogMask) == 0)
+ if ((mask & rpmlogSetMask(0)) == 0)
return;
va_start(ap, fmt);
@@ -222,9 +425,8 @@ void rpmlog (int code, const char *fmt, ...)
rec.pri = pri;
rec.message = msg;
- dolog(&rec);
+ dolog(&rec, saverec);
free(msg);
}
}
-
diff --git a/rpmio/rpmlog.h b/rpmio/rpmlog.h
index 0766086f4..6b0d8f70a 100644
--- a/rpmio/rpmlog.h
+++ b/rpmio/rpmlog.h
@@ -42,33 +42,6 @@ typedef enum rpmlogLvl_e {
#define RPMLOG_PRI(p) ((p) & RPMLOG_PRIMASK)
#define RPMLOG_MAKEPRI(fac, pri) ((((unsigned)(fac)) << 3) | (pri))
-#ifdef RPMLOG_NAMES
-#define _RPMLOG_NOPRI 0x10 /* the "no priority" priority */
- /* mark "facility" */
-#define _RPMLOG_MARK RPMLOG_MAKEPRI(RPMLOG_NFACILITIES, 0)
-typedef struct _rpmcode {
- const char *c_name;
- int c_val;
-} RPMCODE;
-
-RPMCODE rpmprioritynames[] =
- {
- { "alert", RPMLOG_ALERT },
- { "crit", RPMLOG_CRIT },
- { "debug", RPMLOG_DEBUG },
- { "emerg", RPMLOG_EMERG },
- { "err", RPMLOG_ERR },
- { "error", RPMLOG_ERR }, /* DEPRECATED */
- { "info", RPMLOG_INFO },
- { "none", _RPMLOG_NOPRI }, /* INTERNAL */
- { "notice", RPMLOG_NOTICE },
- { "panic", RPMLOG_EMERG }, /* DEPRECATED */
- { "warn", RPMLOG_WARNING }, /* DEPRECATED */
- { "warning",RPMLOG_WARNING },
- { NULL, -1 }
- };
-#endif
-
/** \ingroup rpmlog
* facility codes
*/
@@ -104,35 +77,6 @@ typedef enum rpmlogFac_e {
#define RPMLOG_FAC(p) (((p) & RPMLOG_FACMASK) >> 3)
-#ifdef RPMLOG_NAMES
-RPMCODE facilitynames[] =
- {
- { "auth", RPMLOG_AUTH },
- { "authpriv",RPMLOG_AUTHPRIV },
- { "cron", RPMLOG_CRON },
- { "daemon", RPMLOG_DAEMON },
- { "ftp", RPMLOG_FTP },
- { "kern", RPMLOG_KERN },
- { "lpr", RPMLOG_LPR },
- { "mail", RPMLOG_MAIL },
- { "mark", _RPMLOG_MARK }, /* INTERNAL */
- { "news", RPMLOG_NEWS },
- { "security",RPMLOG_AUTH }, /* DEPRECATED */
- { "syslog", RPMLOG_SYSLOG },
- { "user", RPMLOG_USER },
- { "uucp", RPMLOG_UUCP },
- { "local0", RPMLOG_LOCAL0 },
- { "local1", RPMLOG_LOCAL1 },
- { "local2", RPMLOG_LOCAL2 },
- { "local3", RPMLOG_LOCAL3 },
- { "local4", RPMLOG_LOCAL4 },
- { "local5", RPMLOG_LOCAL5 },
- { "local6", RPMLOG_LOCAL6 },
- { "local7", RPMLOG_LOCAL7 },
- { NULL, -1 }
- };
-#endif
-
/*
* arguments to setlogmask.
*/
diff --git a/rpmio/rpmlua.c b/rpmio/rpmlua.c
index 96f4dc1ca..c96fb6b67 100644
--- a/rpmio/rpmlua.c
+++ b/rpmio/rpmlua.c
@@ -60,6 +60,9 @@ struct rpmluapb_s {
static rpmlua globalLuaState = NULL;
+static char *(*nextFileFunc)(void *) = NULL;
+static void *nextFileFuncParam = NULL;
+
static int luaopen_rpm(lua_State *L);
static int rpm_print(lua_State *L);
@@ -80,7 +83,7 @@ rpmlua rpmluaNew()
{"posix", luaopen_posix},
{"rex", luaopen_rex},
{"rpm", luaopen_rpm},
- /*{"os", luaopen_rpm_os},*/
+ {"os", luaopen_rpm_os},
{NULL, NULL},
};
@@ -94,12 +97,6 @@ rpmlua rpmluaNew()
lua_call(L, 1, 0);
lua_settop(L, 0);
}
- /* Disable os and io standard libraries */
- lua_pushnil (L);
- lua_setglobal(L, "os");
- lua_pushnil (L);
- lua_setglobal(L, "io");
-
#ifndef LUA_GLOBALSINDEX
lua_pushglobaltable(L);
#endif
@@ -218,6 +215,12 @@ static int pushvar(lua_State *L, rpmluavType type, void *value)
return ret;
}
+void rpmluaSetNextFileFunc(char *(*func)(void *), void *funcParam)
+{
+ nextFileFunc = func;
+ nextFileFuncParam = funcParam;
+}
+
void rpmluaSetVar(rpmlua _lua, rpmluav var)
{
INITSTATE(_lua, lua);
@@ -532,13 +535,15 @@ int rpmluaRunScript(rpmlua _lua, const char *script, const char *name)
int ret = 0;
if (name == NULL)
name = "<lua>";
+ if (script == NULL)
+ script = "";
if (luaL_loadbuffer(L, script, strlen(script), name) != 0) {
rpmlog(RPMLOG_ERR, _("invalid syntax in lua script: %s\n"),
lua_tostring(L, -1));
lua_pop(L, 1);
ret = -1;
} else if (lua_pcall(L, 0, 0, 0) != 0) {
- rpmlog(RPMLOG_WARNING, _("lua script failed: %s\n"),
+ rpmlog(RPMLOG_ERR, _("lua script failed: %s\n"),
lua_tostring(L, -1));
lua_pop(L, 1);
ret = -1;
@@ -662,7 +667,9 @@ static int rpm_b64decode(lua_State *L)
static int rpm_expand(lua_State *L)
{
const char *str = luaL_checkstring(L, 1);
- char *val = rpmExpand(str, NULL);
+ char *val = NULL;
+ if (rpmExpandMacros(NULL, str, &val, 0) < 0)
+ return luaL_error(L, "error expanding macro");
lua_pushstring(L, val);
free(val);
return 1;
@@ -671,16 +678,42 @@ static int rpm_expand(lua_State *L)
static int rpm_define(lua_State *L)
{
const char *str = luaL_checkstring(L, 1);
- (void) rpmDefineMacro(NULL, str, 0);
+ if (rpmDefineMacro(NULL, str, 0))
+ return luaL_error(L, "error defining macro");
+ return 0;
+}
+
+static int rpm_undefine(lua_State *L)
+{
+ const char *str = luaL_checkstring(L, 1);
+ rpmPopMacro(NULL, str);
return 0;
}
+static int rpm_load(lua_State *L)
+{
+ const char *str = luaL_checkstring(L, 1);
+ int rc = rpmLoadMacroFile(NULL, str);
+ lua_pushnumber(L, rc);
+ return 1;
+}
+
static int rpm_interactive(lua_State *L)
{
_rpmluaInteractive(L);
return 0;
}
+static int rpm_next_file(lua_State *L)
+{
+ if (nextFileFunc)
+ lua_pushstring(L, nextFileFunc(nextFileFuncParam));
+ else
+ lua_pushstring(L, NULL);
+
+ return 1;
+}
+
typedef struct rpmluaHookData_s {
lua_State *L;
int funcRef;
@@ -867,10 +900,13 @@ static const luaL_Reg rpmlib[] = {
{"b64decode", rpm_b64decode},
{"expand", rpm_expand},
{"define", rpm_define},
+ {"undefine", rpm_undefine},
+ {"load", rpm_load},
{"register", rpm_register},
{"unregister", rpm_unregister},
{"call", rpm_call},
{"interactive", rpm_interactive},
+ {"next_file", rpm_next_file},
{NULL, NULL}
};
diff --git a/rpmio/rpmlua.h b/rpmio/rpmlua.h
index 7298ed57d..935b892bc 100644
--- a/rpmio/rpmlua.h
+++ b/rpmio/rpmlua.h
@@ -62,6 +62,8 @@ void rpmluaSetData(rpmlua lua, const char *key, const void *data);
char *rpmluaPopPrintBuffer(rpmlua lua);
void rpmluaPushPrintBuffer(rpmlua lua);
+void rpmluaSetNextFileFunc(char *(*func)(void *), void *funcParam);
+
void rpmluaGetVar(rpmlua lua, rpmluav var);
void rpmluaSetVar(rpmlua lua, rpmluav var);
void rpmluaDelVar(rpmlua lua, const char *key, ...);
diff --git a/rpmio/rpmmacro.h b/rpmio/rpmmacro.h
index 765c78c6d..a31beb76a 100644
--- a/rpmio/rpmmacro.h
+++ b/rpmio/rpmmacro.h
@@ -3,6 +3,8 @@
/** \ingroup rpmio
* \file rpmio/rpmmacro.h
+ *
+ * Macro API
*/
#include <stdio.h>
@@ -43,6 +45,10 @@ extern const char * macrofiles;
#define RMIL_OLDSPEC -1
#define RMIL_GLOBAL 0
+/* Deprecated compatibility wrappers */
+#define addMacro(_mc, _n, _o, _b, _l) rpmPushMacro(_mc, _n, _o, _b, _l)
+#define delMacro(_mc, _n) rpmPopMacro(_mc, _n)
+
/** \ingroup rpmmacro
* Print macros to file stream.
* @param mc macro context (NULL uses global context).
@@ -53,37 +59,35 @@ void rpmDumpMacroTable (rpmMacroContext mc,
/** \ingroup rpmmacro
* Expand macro into buffer.
- * @deprecated Use rpmExpand().
- * @todo Eliminate from API.
- * @param spec cookie (unused)
* @param mc macro context (NULL uses global context).
- * @retval sbuf input macro to expand, output expansion
- * @param slen size of buffer
- * @return 0 on success
+ * @param sbuf input macro to expand
+ * @param obuf macro expansion (malloc'ed)
+ * @param flags flags (currently unused)
+ * @return negative on failure
*/
-int expandMacros (void * spec, rpmMacroContext mc,
- char * sbuf,
- size_t slen);
+int rpmExpandMacros (rpmMacroContext mc, const char * sbuf,
+ char ** obuf, int flags);
/** \ingroup rpmmacro
- * Add macro to context.
- * @deprecated Use rpmDefineMacro().
+ * Push macro to context.
* @param mc macro context (NULL uses global context).
* @param n macro name
- * @param o macro paramaters
+ * @param o macro parameters
* @param b macro body
* @param level macro recursion level (0 is entry API)
+ * @return 0 on success
*/
-void addMacro (rpmMacroContext mc, const char * n,
+int rpmPushMacro (rpmMacroContext mc, const char * n,
const char * o,
const char * b, int level);
/** \ingroup rpmmacro
- * Delete macro from context.
+ * Pop macro from context.
* @param mc macro context (NULL uses global context).
* @param n macro name
+ * @return 0 on success
*/
-void delMacro (rpmMacroContext mc, const char * n);
+int rpmPopMacro (rpmMacroContext mc, const char * n);
/** \ingroup rpmmacro
* Define macro in context.
diff --git a/rpmio/rpmpgp.c b/rpmio/rpmpgp.c
index e70cf706b..15cce2275 100644
--- a/rpmio/rpmpgp.c
+++ b/rpmio/rpmpgp.c
@@ -248,6 +248,19 @@ static void pgpPrtVal(const char * pre, pgpValTbl vs, uint8_t val)
fprintf(stderr, "%s(%u)", pgpValStr(vs, val), (unsigned)val);
}
+static void pgpPrtTime(const char * pre, const uint8_t *p, size_t plen)
+{
+ if (!_print) return;
+ if (pre && *pre)
+ fprintf(stderr, "%s", pre);
+ if (plen == 4) {
+ time_t t = pgpGrab(p, plen);
+ fprintf(stderr, " %-24.24s(0x%08x)", ctime(&t), (unsigned)t);
+ } else {
+ pgpPrtHex("", p+1, plen-1);
+ }
+}
+
/** \ingroup rpmpgp
* Return hex formatted representation of a multiprecision integer.
* @param p bytes
@@ -384,15 +397,24 @@ unsigned int pgpCRC(const uint8_t *octets, size_t len)
return crc & 0xffffff;
}
+static int pgpVersion(const uint8_t *h, size_t hlen, uint8_t *version)
+{
+ if (hlen < 1)
+ return -1;
+
+ *version = h[0];
+ return 0;
+}
+
static int pgpPrtSubType(const uint8_t *h, size_t hlen, pgpSigType sigtype,
pgpDigParams _digp)
{
const uint8_t *p = h;
- size_t plen, i;
+ size_t plen = 0, i;
while (hlen > 0) {
i = pgpLen(p, hlen, &plen);
- if (i == 0 || i + plen > hlen)
+ if (i == 0 || plen < 1 || i + plen > hlen)
break;
p += i;
@@ -423,23 +445,22 @@ static int pgpPrtSubType(const uint8_t *h, size_t hlen, pgpSigType sigtype,
if (!(_digp->saved & PGPDIG_SAVED_TIME) &&
(sigtype == PGPSIGTYPE_POSITIVE_CERT || sigtype == PGPSIGTYPE_BINARY || sigtype == PGPSIGTYPE_TEXT || sigtype == PGPSIGTYPE_STANDALONE))
{
+ if (plen-1 != sizeof(_digp->time))
+ break;
_digp->saved |= PGPDIG_SAVED_TIME;
- memcpy(_digp->time, p+1, sizeof(_digp->time));
+ _digp->time = pgpGrab(p+1, sizeof(_digp->time));
}
case PGPSUBTYPE_SIG_EXPIRE_TIME:
case PGPSUBTYPE_KEY_EXPIRE_TIME:
- if ((plen - 1) == 4) {
- time_t t = pgpGrab(p+1, plen-1);
- if (_print)
- fprintf(stderr, " %-24.24s(0x%08x)", ctime(&t), (unsigned)t);
- } else
- pgpPrtHex("", p+1, plen-1);
+ pgpPrtTime(" ", p+1, plen-1);
break;
case PGPSUBTYPE_ISSUER_KEYID: /* issuer key ID */
if (!(_digp->saved & PGPDIG_SAVED_ID) &&
(sigtype == PGPSIGTYPE_POSITIVE_CERT || sigtype == PGPSIGTYPE_BINARY || sigtype == PGPSIGTYPE_TEXT || sigtype == PGPSIGTYPE_STANDALONE))
{
+ if (plen-1 != sizeof(_digp->signid))
+ break;
_digp->saved |= PGPDIG_SAVED_ID;
memcpy(_digp->signid, p+1, sizeof(_digp->signid));
}
@@ -499,11 +520,15 @@ static int pgpPrtSigParams(pgpTag tag, uint8_t pubkey_algo, uint8_t sigtype,
int i;
pgpDigAlg sigalg = pgpSignatureNew(pubkey_algo);
- for (i = 0; p < pend && i < sigalg->mpis; i++, p += pgpMpiLen(p)) {
+ for (i = 0; i < sigalg->mpis && p + 2 <= pend; i++) {
+ int mpil = pgpMpiLen(p);
+ if (p + mpil > pend)
+ break;
if (sigtype == PGPSIGTYPE_BINARY || sigtype == PGPSIGTYPE_TEXT) {
- if (sigalg->setmpi(sigalg, i, p, pend))
+ if (sigalg->setmpi(sigalg, i, p))
break;
}
+ p += mpil;
}
/* Does the size and number of MPI's match our expectations? */
@@ -519,18 +544,33 @@ static int pgpPrtSigParams(pgpTag tag, uint8_t pubkey_algo, uint8_t sigtype,
return rc;
}
+static int pgpGet(const uint8_t *s, size_t nbytes, const uint8_t *send,
+ unsigned int *valp)
+{
+ int rc = -1;
+
+ if (s + nbytes <= send) {
+ *valp = pgpGrab(s, nbytes);
+ rc = 0;
+ }
+
+ return rc;
+}
+
static int pgpPrtSig(pgpTag tag, const uint8_t *h, size_t hlen,
pgpDigParams _digp)
{
- uint8_t version = h[0];
+ uint8_t version = 0;
uint8_t * p;
- size_t plen;
- int rc;
+ unsigned int plen;
+ int rc = 1;
+
+ if (pgpVersion(h, hlen, &version))
+ return rc;
switch (version) {
case 3:
{ pgpPktSigV3 v = (pgpPktSigV3)h;
- time_t t;
if (hlen <= sizeof(*v) || v->hashlen != 5)
return 1;
@@ -540,9 +580,7 @@ static int pgpPrtSig(pgpTag tag, const uint8_t *h, size_t hlen,
pgpPrtVal(" ", pgpHashTbl, v->hash_algo);
pgpPrtVal(" ", pgpSigTypeTbl, v->sigtype);
pgpPrtNL();
- t = pgpGrab(v->time, sizeof(v->time));
- if (_print)
- fprintf(stderr, " %-24.24s(0x%08x)", ctime(&t), (unsigned)t);
+ pgpPrtTime(" ", v->time, sizeof(v->time));
pgpPrtNL();
pgpPrtHex(" signer keyid", v->signid, sizeof(v->signid));
plen = pgpGrab(v->signhash16, sizeof(v->signhash16));
@@ -554,7 +592,7 @@ static int pgpPrtSig(pgpTag tag, const uint8_t *h, size_t hlen,
_digp->hashlen = v->hashlen;
_digp->sigtype = v->sigtype;
_digp->hash = memcpy(xmalloc(v->hashlen), &v->sigtype, v->hashlen);
- memcpy(_digp->time, v->time, sizeof(_digp->time));
+ _digp->time = pgpGrab(v->time, sizeof(v->time));
memcpy(_digp->signid, v->signid, sizeof(_digp->signid));
_digp->pubkey_algo = v->pubkey_algo;
_digp->hash_algo = v->hash_algo;
@@ -577,7 +615,8 @@ static int pgpPrtSig(pgpTag tag, const uint8_t *h, size_t hlen,
pgpPrtNL();
p = &v->hashlen[0];
- plen = pgpGrab(v->hashlen, sizeof(v->hashlen));
+ if (pgpGet(v->hashlen, sizeof(v->hashlen), h + hlen, &plen))
+ return 1;
p += sizeof(v->hashlen);
if ((p + plen) > (h + hlen))
@@ -591,7 +630,8 @@ static int pgpPrtSig(pgpTag tag, const uint8_t *h, size_t hlen,
return 1;
p += plen;
- plen = pgpGrab(p,2);
+ if (pgpGet(p, 2, h + hlen, &plen))
+ return 1;
p += 2;
if ((p + plen) > (h + hlen))
@@ -601,7 +641,8 @@ static int pgpPrtSig(pgpTag tag, const uint8_t *h, size_t hlen,
return 1;
p += plen;
- plen = pgpGrab(p,2);
+ if (pgpGet(p, 2, h + hlen, &plen))
+ return 1;
pgpPrtHex(" signhash16", p, 2);
pgpPrtNL();
@@ -620,6 +661,7 @@ static int pgpPrtSig(pgpTag tag, const uint8_t *h, size_t hlen,
rc = pgpPrtSigParams(tag, v->pubkey_algo, v->sigtype, p, h, hlen, _digp);
} break;
default:
+ rpmlog(RPMLOG_WARNING, _("Unsupported version of key: V%d\n"), version);
rc = 1;
break;
}
@@ -650,9 +692,13 @@ static int pgpPrtPubkeyParams(uint8_t pubkey_algo,
int i;
pgpDigAlg keyalg = pgpPubkeyNew(pubkey_algo);
- for (i = 0; p < pend && i < keyalg->mpis; i++, p += pgpMpiLen(p)) {
- if (keyalg->setmpi(keyalg, i, p, pend))
+ for (i = 0; i < keyalg->mpis && p + 2 <= pend; i++) {
+ int mpil = pgpMpiLen(p);
+ if (p + mpil > pend)
+ break;
+ if (keyalg->setmpi(keyalg, i, p))
break;
+ p += mpil;
}
/* Does the size and number of MPI's match our expectations? */
@@ -660,7 +706,9 @@ static int pgpPrtPubkeyParams(uint8_t pubkey_algo,
rc = 0;
/* We can't handle more than one key at a time */
- if (rc == 0 && keyp->alg == NULL && keyp->tag == PGPTAG_PUBLIC_KEY)
+ if (rc == 0 && keyp->alg == NULL && (keyp->tag == PGPTAG_PUBLIC_KEY ||
+ keyp->tag == PGPTAG_PUBLIC_SUBKEY))
+
keyp->alg = keyalg;
else
pgpDigAlgFree(keyalg);
@@ -671,11 +719,13 @@ static int pgpPrtPubkeyParams(uint8_t pubkey_algo,
static int pgpPrtKey(pgpTag tag, const uint8_t *h, size_t hlen,
pgpDigParams _digp)
{
- uint8_t version = *h;
+ uint8_t version = 0;
const uint8_t * p = NULL;
- time_t t;
int rc = 1;
+ if (pgpVersion(h, hlen, &version))
+ return rc;
+
/* We only permit V4 keys, V3 keys are long long since deprecated */
switch (version) {
case 4:
@@ -684,14 +734,13 @@ static int pgpPrtKey(pgpTag tag, const uint8_t *h, size_t hlen,
if (hlen > sizeof(*v)) {
pgpPrtVal("V4 ", pgpTagTbl, tag);
pgpPrtVal(" ", pgpPubkeyTbl, v->pubkey_algo);
- t = pgpGrab(v->time, sizeof(v->time));
- if (_print)
- fprintf(stderr, " %-24.24s(0x%08x)", ctime(&t), (unsigned)t);
+ pgpPrtTime(" ", v->time, sizeof(v->time));
pgpPrtNL();
- if (_digp->tag == tag) {
+ /* If _digp->hash is not NULL then signature is already loaded */
+ if (_digp->hash == NULL) {
_digp->version = v->version;
- memcpy(_digp->time, v->time, sizeof(_digp->time));
+ _digp->time = pgpGrab(v->time, sizeof(v->time));
_digp->pubkey_algo = v->pubkey_algo;
}
@@ -699,6 +748,8 @@ static int pgpPrtKey(pgpTag tag, const uint8_t *h, size_t hlen,
rc = pgpPrtPubkeyParams(v->pubkey_algo, p, h, hlen, _digp);
}
} break;
+ default:
+ rpmlog(RPMLOG_WARNING, _("Unsupported version of key: V%d\n"), h[0]);
}
return rc;
}
@@ -716,14 +767,19 @@ static int pgpPrtUserID(pgpTag tag, const uint8_t *h, size_t hlen,
return 0;
}
-static int getFingerprint(const uint8_t *h, size_t hlen, pgpKeyID_t keyid)
+int pgpPubkeyFingerprint(const uint8_t *h, size_t hlen,
+ uint8_t **fp, size_t *fplen)
{
int rc = -1; /* assume failure */
const uint8_t *se;
const uint8_t *pend = h + hlen;
+ uint8_t version = 0;
+
+ if (pgpVersion(h, hlen, &version))
+ return rc;
/* We only permit V4 keys, V3 keys are long long since deprecated */
- switch (h[0]) {
+ switch (version) {
case 4:
{ pgpPktKeyV4 v = (pgpPktKeyV4) (h);
int mpis = -1;
@@ -747,8 +803,8 @@ static int getFingerprint(const uint8_t *h, size_t hlen, pgpKeyID_t keyid)
/* Does the size and number of MPI's match our expectations? */
if (se == pend && mpis == 0) {
DIGEST_CTX ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
- uint8_t * d = NULL;
- size_t dlen;
+ uint8_t *d = NULL;
+ size_t dlen = 0;
int i = se - h;
uint8_t in[3] = { 0x99, (i >> 8), i };
@@ -756,42 +812,42 @@ static int getFingerprint(const uint8_t *h, size_t hlen, pgpKeyID_t keyid)
(void) rpmDigestUpdate(ctx, h, i);
(void) rpmDigestFinal(ctx, (void **)&d, &dlen, 0);
- if (d) {
- memcpy(keyid, (d + (dlen-8)), 8);
- free(d);
+ if (dlen == 20) {
rc = 0;
+ *fp = d;
+ *fplen = dlen;
+ } else {
+ free(d);
}
}
} break;
+ default:
+ rpmlog(RPMLOG_WARNING, _("Unsupported version of key: V%d\n"), version);
+ }
+ return rc;
+}
+
+static int getKeyID(const uint8_t *h, size_t hlen, pgpKeyID_t keyid)
+{
+ uint8_t *fp = NULL;
+ size_t fplen = 0;
+ int rc = pgpPubkeyFingerprint(h, hlen, &fp, &fplen);
+ if (fp && fplen > 8) {
+ memcpy(keyid, (fp + (fplen-8)), 8);
+ free(fp);
}
return rc;
}
-int pgpPubkeyFingerprint(const uint8_t * pkt, size_t pktlen, pgpKeyID_t keyid)
+int pgpPubkeyKeyID(const uint8_t * pkt, size_t pktlen, pgpKeyID_t keyid)
{
struct pgpPkt p;
if (decodePkt(pkt, pktlen, &p))
return -1;
- return getFingerprint(p.body, p.blen, keyid);
-}
-
-int pgpExtractPubkeyFingerprint(const char * b64pkt, pgpKeyID_t keyid)
-{
- uint8_t * pkt;
- size_t pktlen;
- int rc = -1; /* assume failure */
-
- if (rpmBase64Decode(b64pkt, (void **)&pkt, &pktlen) == 0) {
- if (pgpPubkeyFingerprint(pkt, pktlen, keyid) == 0) {
- /* if there ever was a bizarre return code for success... */
- rc = 8;
- }
- free(pkt);
- }
- return rc;
+ return getKeyID(p.body, p.blen, keyid);
}
static int pgpPrtPkt(struct pgpPkt *p, pgpDigParams _digp)
@@ -803,8 +859,8 @@ static int pgpPrtPkt(struct pgpPkt *p, pgpDigParams _digp)
rc = pgpPrtSig(p->tag, p->body, p->blen, _digp);
break;
case PGPTAG_PUBLIC_KEY:
- /* Get the public key fingerprint. */
- if (!getFingerprint(p->body, p->blen, _digp->signid))
+ /* Get the public key Key ID. */
+ if (!getKeyID(p->body, p->blen, _digp->signid))
_digp->saved |= PGPDIG_SAVED_ID;
else
memset(_digp->signid, 0, sizeof(_digp->signid));
@@ -813,12 +869,14 @@ static int pgpPrtPkt(struct pgpPkt *p, pgpDigParams _digp)
case PGPTAG_USER_ID:
rc = pgpPrtUserID(p->tag, p->body, p->blen, _digp);
break;
+ case PGPTAG_RESERVED:
+ rc = -1;
+ break;
case PGPTAG_COMMENT:
case PGPTAG_COMMENT_OLD:
case PGPTAG_PUBLIC_SUBKEY:
case PGPTAG_SECRET_KEY:
case PGPTAG_SECRET_SUBKEY:
- case PGPTAG_RESERVED:
case PGPTAG_PUBLIC_SESSION_KEY:
case PGPTAG_SYMMETRIC_SESSION_KEY:
case PGPTAG_COMPRESSED_DATA:
@@ -903,6 +961,8 @@ int pgpDigParamsCmp(pgpDigParams p1, pgpDigParams p2)
int rc = 1; /* assume different, eg if either is NULL */
if (p1 && p2) {
/* XXX Should we compare something else too? */
+ if (p1->tag != p2->tag)
+ goto exit;
if (p1->hash_algo != p2->hash_algo)
goto exit;
if (p1->pubkey_algo != p2->pubkey_algo)
@@ -913,6 +973,8 @@ int pgpDigParamsCmp(pgpDigParams p1, pgpDigParams p2)
goto exit;
if (memcmp(p1->signid, p2->signid, sizeof(p1->signid)) != 0)
goto exit;
+ if (p1->userid && p2->userid && strcmp(p1->userid, p2->userid) != 0)
+ goto exit;
/* Parameters match ... at least for our purposes */
rc = 0;
@@ -937,36 +999,128 @@ unsigned int pgpDigParamsAlgo(pgpDigParams digp, unsigned int algotype)
return algo;
}
+static pgpDigParams pgpDigParamsNew(uint8_t tag)
+{
+ pgpDigParams digp = xcalloc(1, sizeof(*digp));
+ digp->tag = tag;
+ return digp;
+}
+
+static int hashKey(DIGEST_CTX hash, const struct pgpPkt *pkt, int exptag)
+{
+ int rc = -1;
+ if (pkt->tag == exptag) {
+ uint8_t head[] = {
+ 0x99,
+ (pkt->blen >> 8),
+ (pkt->blen ),
+ };
+
+ rpmDigestUpdate(hash, head, 3);
+ rpmDigestUpdate(hash, pkt->body, pkt->blen);
+ rc = 0;
+ }
+ return rc;
+}
+
+static int pgpVerifySelf(pgpDigParams key, pgpDigParams selfsig,
+ const struct pgpPkt *all, int i)
+{
+ int rc = -1;
+ DIGEST_CTX hash = NULL;
+
+ switch (selfsig->sigtype) {
+ case PGPSIGTYPE_SUBKEY_BINDING:
+ hash = rpmDigestInit(selfsig->hash_algo, 0);
+ if (hash) {
+ rc = hashKey(hash, &all[0], PGPTAG_PUBLIC_KEY);
+ if (!rc)
+ rc = hashKey(hash, &all[i-1], PGPTAG_PUBLIC_SUBKEY);
+ }
+ break;
+ default:
+ /* ignore types we can't handle */
+ rc = 0;
+ break;
+ }
+
+ if (hash && rc == 0)
+ rc = pgpVerifySignature(key, selfsig, hash);
+
+ rpmDigestFinal(hash, NULL, NULL, 0);
+
+ return rc;
+}
+
int pgpPrtParams(const uint8_t * pkts, size_t pktlen, unsigned int pkttype,
pgpDigParams * ret)
{
const uint8_t *p = pkts;
const uint8_t *pend = pkts + pktlen;
pgpDigParams digp = NULL;
- struct pgpPkt pkt;
+ pgpDigParams selfsig = NULL;
+ int i = 0;
+ int alloced = 16; /* plenty for normal cases */
+ struct pgpPkt *all = xmalloc(alloced * sizeof(*all));
int rc = -1; /* assume failure */
+ int expect = 0;
+ int prevtag = 0;
while (p < pend) {
- if (decodePkt(p, (pend - p), &pkt))
+ struct pgpPkt *pkt = &all[i];
+ if (decodePkt(p, (pend - p), pkt))
break;
if (digp == NULL) {
- if (pkttype && pkt.tag != pkttype) {
+ if (pkttype && pkt->tag != pkttype) {
break;
} else {
- digp = xcalloc(1, sizeof(*digp));
- digp->tag = pkt.tag;
+ digp = pgpDigParamsNew(pkt->tag);
}
}
- if (pgpPrtPkt(&pkt, digp))
+ if (expect) {
+ if (pkt->tag != expect)
+ break;
+ selfsig = pgpDigParamsNew(pkt->tag);
+ }
+
+ if (pgpPrtPkt(pkt, selfsig ? selfsig : digp))
break;
- p += (pkt.body - pkt.head) + pkt.blen;
+ if (selfsig) {
+ /* subkeys must be followed by binding signature */
+ if (prevtag == PGPTAG_PUBLIC_SUBKEY) {
+ if (selfsig->sigtype != PGPSIGTYPE_SUBKEY_BINDING)
+ break;
+ }
+
+ int xx = pgpVerifySelf(digp, selfsig, all, i);
+
+ selfsig = pgpDigParamsFree(selfsig);
+ if (xx)
+ break;
+ expect = 0;
+ }
+
+ if (pkt->tag == PGPTAG_PUBLIC_SUBKEY)
+ expect = PGPTAG_SIGNATURE;
+ prevtag = pkt->tag;
+
+ i++;
+ p += (pkt->body - pkt->head) + pkt->blen;
+ if (pkttype == PGPTAG_SIGNATURE)
+ break;
+
+ if (alloced <= i) {
+ alloced *= 2;
+ all = xrealloc(all, alloced * sizeof(*all));
+ }
}
- rc = (digp && (p == pend)) ? 0 : -1;
+ rc = (digp && (p == pend) && expect == 0) ? 0 : -1;
+ free(all);
if (ret && rc == 0) {
*ret = digp;
} else {
@@ -975,6 +1129,63 @@ int pgpPrtParams(const uint8_t * pkts, size_t pktlen, unsigned int pkttype,
return rc;
}
+int pgpPrtParamsSubkeys(const uint8_t *pkts, size_t pktlen,
+ pgpDigParams mainkey, pgpDigParams **subkeys,
+ int *subkeysCount)
+{
+ const uint8_t *p = pkts;
+ const uint8_t *pend = pkts + pktlen;
+ pgpDigParams *digps = NULL;
+ int count = 0;
+ int alloced = 10;
+ struct pgpPkt pkt;
+ int rc, i;
+
+ digps = xmalloc(alloced * sizeof(*digps));
+
+ while (p < pend) {
+ if (decodePkt(p, (pend - p), &pkt))
+ break;
+
+ p += (pkt.body - pkt.head) + pkt.blen;
+
+ if (pkt.tag == PGPTAG_PUBLIC_SUBKEY) {
+ if (count == alloced) {
+ alloced <<= 1;
+ digps = xrealloc(digps, alloced * sizeof(*digps));
+ }
+
+ digps[count] = xcalloc(1, sizeof(**digps));
+ digps[count]->tag = PGPTAG_PUBLIC_SUBKEY;
+ /* Copy UID from main key to subkey */
+ digps[count]->userid = xstrdup(mainkey->userid);
+
+ if (getKeyID(pkt.body, pkt.blen, digps[count]->signid)) {
+ pgpDigParamsFree(digps[count]);
+ continue;
+ }
+
+ if (pgpPrtKey(pkt.tag, pkt.body, pkt.blen, digps[count])) {
+ pgpDigParamsFree(digps[count]);
+ continue;
+ }
+ count++;
+ }
+ }
+ rc = (p == pend) ? 0 : -1;
+
+ if (rc == 0) {
+ *subkeys = xrealloc(digps, count * sizeof(*digps));
+ *subkeysCount = count;
+ } else {
+ for (i = 0; i < count; i++)
+ pgpDigParamsFree(digps[i]);
+ free(digps);
+ }
+
+ return rc;
+}
+
int pgpPrtPkts(const uint8_t * pkts, size_t pktlen, pgpDig dig, int printing)
{
int rc;
@@ -1230,6 +1441,29 @@ pgpArmor pgpParsePkts(const char *armor, uint8_t ** pkt, size_t * pktlen)
return ec;
}
+int pgpPubKeyCertLen(const uint8_t *pkts, size_t pktslen, size_t *certlen)
+{
+ const uint8_t *p = pkts;
+ const uint8_t *pend = pkts + pktslen;
+ struct pgpPkt pkt;
+
+ while (p < pend) {
+ if (decodePkt(p, (pend - p), &pkt))
+ return -1;
+
+ if (pkt.tag == PGPTAG_PUBLIC_KEY && pkts != p) {
+ *certlen = p - pkts;
+ return 0;
+ }
+
+ p += (pkt.body - pkt.head) + pkt.blen;
+ }
+
+ *certlen = pktslen;
+
+ return 0;
+}
+
char * pgpArmorWrap(int atype, const unsigned char * s, size_t ns)
{
char *buf = NULL, *val = NULL;
diff --git a/rpmio/rpmpgp.h b/rpmio/rpmpgp.h
index d45465636..d37a2e92c 100644
--- a/rpmio/rpmpgp.h
+++ b/rpmio/rpmpgp.h
@@ -244,14 +244,16 @@ typedef enum pgpCompressAlgo_e {
4 - Reserved for double-width SHA (experimental)
5 - MD2 "MD2"
6 - Reserved for TIGER/192 "TIGER192"
- 7 - Reserved for HAVAL (5 pass, 160-bit)
- "HAVAL-5-160"
+ 7 - Reserved for HAVAL (5 pass, 160-bit) "HAVAL-5-160"
+ 8 - SHA-256 "SHA256"
+ 9 - SHA-384 "SHA384"
+ 10 - SHA-512 "SHA512"
+ 11 - SHA-224 "SHA224"
100 to 110 - Private/Experimental algorithm.
\endverbatim
*
* Implementations MUST implement SHA-1. Implementations SHOULD
* implement MD5.
- * @todo Add SHA256.
*/
typedef enum pgpHashAlgo_e {
PGPHASHALGO_MD5 = 1, /*!< MD5 */
@@ -970,23 +972,23 @@ char * pgpHexStr(const uint8_t *p, size_t plen);
/** \ingroup rpmpgp
* Calculate OpenPGP public key fingerprint.
- * @todo V3 non-RSA public keys not implemented.
* @param pkt OpenPGP packet (i.e. PGPTAG_PUBLIC_KEY)
* @param pktlen OpenPGP packet length (no. of bytes)
- * @retval keyid public key fingerprint
- * @return 0 on sucess, else -1
+ * @retval fp public key fingerprint
+ * @retval fplen public key fingerprint length
+ * @return 0 on success, else -1
*/
int pgpPubkeyFingerprint(const uint8_t * pkt, size_t pktlen,
- pgpKeyID_t keyid);
+ uint8_t **fp, size_t *fplen);
/** \ingroup rpmpgp
-* Extract OpenPGP public key fingerprint from base64 encoded packet.
-* @todo V3 non-RSA public keys not implemented.
-* @param b64pkt base64 encoded openpgp packet
-* @retval keyid public key fingerprint
-* @return 8 (no. of bytes) on success, < 0 on error
-*/
-int pgpExtractPubkeyFingerprint(const char * b64pkt, pgpKeyID_t keyid);
+ * Calculate OpenPGP public key Key ID
+ * @param pkt OpenPGP packet (i.e. PGPTAG_PUBLIC_KEY)
+ * @param pktlen OpenPGP packet length (no. of bytes)
+ * @retval keyid public key Key ID
+ * @return 0 on success, else -1
+ */
+int pgpPubkeyKeyID(const uint8_t * pkt, size_t pktlen, pgpKeyID_t keyid);
/** \ingroup rpmpgp
* Parse a OpenPGP packet(s).
@@ -1000,6 +1002,18 @@ int pgpPrtParams(const uint8_t *pkts, size_t pktlen, unsigned int pkttype,
pgpDigParams * ret);
/** \ingroup rpmpgp
+ * Parse subkey parameters from OpenPGP packet(s).
+ * @param pkts OpenPGP packet(s)
+ * @param pktlen OpenPGP packet(s) length (no. of bytes)
+ * @param mainkey parameters of main key
+ * @param subkeys array of subkey parameters (alloced)
+ * @param subkeysCount count of subkeys
+ * @return -1 on error, 0 on success
+ */
+int pgpPrtParamsSubkeys(const uint8_t *pkts, size_t pktlen,
+ pgpDigParams mainkey, pgpDigParams **subkeys,
+ int *subkeysCount);
+/** \ingroup rpmpgp
* Print/parse a OpenPGP packet(s).
* @param pkts OpenPGP packet(s)
* @param pktlen OpenPGP packet(s) length (no. of bytes)
@@ -1028,6 +1042,20 @@ pgpArmor pgpReadPkts(const char * fn, uint8_t ** pkt, size_t * pktlen);
pgpArmor pgpParsePkts(const char *armor, uint8_t ** pkt, size_t * pktlen);
/** \ingroup rpmpgp
+ * Return a length of the first public key certificate in a buffer given
+ * by pkts that contains one or more certificates. A public key certificate
+ * consits of packets like Public key packet, User ID packet and so on.
+ * In a buffer every certificate starts with Public key packet and it ends
+ * with the start of the next certificate or with the end of the buffer.
+ *
+ * @param pkts pointer to a buffer with certificates
+ * @param pktslen length of the buffer with certificates
+ * @param certlen length of the first certificate in the buffer
+ * @return 0 on success
+ */
+int pgpPubKeyCertLen(const uint8_t *pkts, size_t pktslen, size_t *certlen);
+
+/** \ingroup rpmpgp
* Wrap a OpenPGP packets in ascii armor for transport.
* @param atype type of armor
* @param s binary pkt data
@@ -1187,7 +1215,8 @@ rpmDigestBundle rpmDigestBundleNew(void);
rpmDigestBundle rpmDigestBundleFree(rpmDigestBundle bundle);
/** \ingroup rpmpgp
- * Add a new type of digest to a bundle.
+ * Add a new type of digest to a bundle. Same as calling
+ * rpmDigestBundleAddID() with algo == id value.
* @param bundle digest bundle
* @param algo type of digest
* @param flags bit(s) to control digest operation
@@ -1197,6 +1226,17 @@ int rpmDigestBundleAdd(rpmDigestBundle bundle, int algo,
rpmDigestFlags flags);
/** \ingroup rpmpgp
+ * Add a new type of digest to a bundle.
+ * @param bundle digest bundle
+ * @param algo type of digest
+ * @param id id of digest (arbitrary, must be > 0)
+ * @param flags bit(s) to control digest operation
+ * @return 0 on success
+ */
+int rpmDigestBundleAddID(rpmDigestBundle bundle, int algo, int id,
+ rpmDigestFlags flags);
+
+/** \ingroup rpmpgp
* Update contexts within bundle with next plain text buffer.
* @param bundle digest bundle
* @param data next data buffer
@@ -1209,22 +1249,22 @@ int rpmDigestBundleUpdate(rpmDigestBundle bundle, const void *data, size_t len);
* Return digest from a bundle and destroy context, see rpmDigestFinal().
*
* @param bundle digest bundle
- * @param algo type of digest to return
+ * @param id id of digest to return
* @retval datap address of returned digest
* @retval lenp address of digest length
* @param asAscii return digest as ascii string?
* @return 0 on success
*/
-int rpmDigestBundleFinal(rpmDigestBundle bundle,
- int algo, void ** datap, size_t * lenp, int asAscii);
+int rpmDigestBundleFinal(rpmDigestBundle bundle, int id,
+ void ** datap, size_t * lenp, int asAscii);
/** \ingroup rpmpgp
* Duplicate a digest context from a bundle.
* @param bundle digest bundle
- * @param algo type of digest to dup
+ * @param id id of digest to dup
* @return duplicated digest context
*/
-DIGEST_CTX rpmDigestBundleDupCtx(rpmDigestBundle bundle, int algo);
+DIGEST_CTX rpmDigestBundleDupCtx(rpmDigestBundle bundle, int id);
#ifdef __cplusplus
}
diff --git a/rpmio/rpmsq.c b/rpmio/rpmsq.c
index bfd4db004..1bbdd0a6d 100644
--- a/rpmio/rpmsq.c
+++ b/rpmio/rpmsq.c
@@ -8,107 +8,221 @@
#include <sys/signal.h>
#include <errno.h>
#include <stdio.h>
-
-#define ADD_REF(__tbl) (__tbl)->active++
-#define SUB_REF(__tbl) --(__tbl)->active
+#include <stdlib.h>
+#include <string.h>
#include <rpm/rpmsq.h>
+#include <rpm/rpmlog.h>
#include "debug.h"
-static sigset_t rpmsqCaught;
+static __thread int disableInterruptSafety;
+static __thread sigset_t rpmsqCaught;
+static __thread sigset_t rpmsqActive;
typedef struct rpmsig_s * rpmsig;
+static void rpmsqIgn(int signum, siginfo_t *info, void *context)
+{
+}
+
+static void rpmsqTerm(int signum, siginfo_t *info, void *context)
+{
+ if (info->si_pid == 0) {
+ rpmlog(RPMLOG_DEBUG,
+ "exiting on signal %d (killed by death, eh?)\n", signum);
+ } else {
+ int lvl = (signum == SIGPIPE) ? RPMLOG_DEBUG : RPMLOG_WARNING;
+ rpmlog(lvl,
+ _("exiting on signal %d from pid %d\n"), signum, info->si_pid);
+ }
+ /* exit 128 + signum for compatibility with bash(1) */
+ exit(128 + signum);
+}
+
static struct rpmsig_s {
int signum;
+ rpmsqAction_t defhandler;
rpmsqAction_t handler;
- int active;
+ siginfo_t siginfo;
struct sigaction oact;
} rpmsigTbl[] = {
- { SIGINT, rpmsqAction },
-#define rpmsigTbl_sigint (&rpmsigTbl[0])
- { SIGQUIT, rpmsqAction },
-#define rpmsigTbl_sigquit (&rpmsigTbl[1])
- { SIGHUP, rpmsqAction },
-#define rpmsigTbl_sighup (&rpmsigTbl[3])
- { SIGTERM, rpmsqAction },
-#define rpmsigTbl_sigterm (&rpmsigTbl[4])
- { SIGPIPE, rpmsqAction },
-#define rpmsigTbl_sigpipe (&rpmsigTbl[5])
- { -1, NULL },
+ { SIGINT, rpmsqTerm, NULL },
+ { SIGQUIT, rpmsqTerm, NULL },
+ { SIGHUP, rpmsqTerm, NULL },
+ { SIGTERM, rpmsqTerm, NULL },
+ { SIGPIPE, rpmsqTerm, NULL },
+ { -1, NULL, NULL },
};
+static int rpmsigGet(int signum, struct rpmsig_s **sig)
+{
+ for (rpmsig tbl = rpmsigTbl; tbl->signum >= 0; tbl++) {
+ if (tbl->signum == signum) {
+ *sig = tbl;
+ return 1;
+ }
+ }
+ return 0;
+}
+
int rpmsqIsCaught(int signum)
{
return sigismember(&rpmsqCaught, signum);
}
-#ifdef SA_SIGINFO
-void rpmsqAction(int signum, siginfo_t * info, void * context)
-#else
-void rpmsqAction(int signum)
-#endif
+static void rpmsqHandler(int signum, siginfo_t * info, void * context)
{
int save = errno;
- rpmsig tbl;
- for (tbl = rpmsigTbl; tbl->signum >= 0; tbl++) {
- if (tbl->signum != signum)
- continue;
-
- (void) sigaddset(&rpmsqCaught, signum);
- break;
+ if (sigismember(&rpmsqActive, signum)) {
+ if (!sigismember(&rpmsqCaught, signum)) {
+ rpmsig sig = NULL;
+ if (rpmsigGet(signum, &sig)) {
+ (void) sigaddset(&rpmsqCaught, signum);
+ memcpy(&sig->siginfo, info, sizeof(*info));
+ }
+ }
}
+
errno = save;
}
-int rpmsqEnable(int signum, rpmsqAction_t handler)
+rpmsqAction_t rpmsqSetAction(int signum, rpmsqAction_t handler)
{
- int tblsignum = (signum >= 0 ? signum : -signum);
- struct sigaction sa;
- rpmsig tbl;
- int ret = -1;
+ rpmsig sig = NULL;
+ rpmsqAction_t oh = RPMSQ_ERR;
- for (tbl = rpmsigTbl; tbl->signum >= 0; tbl++) {
- if (tblsignum != tbl->signum)
- continue;
+ if (rpmsigGet(signum, &sig)) {
+ oh = sig->handler;
+ sig->handler = (handler == RPMSQ_IGN) ? rpmsqIgn : handler;
+ }
+ return oh;
+}
- if (signum >= 0) { /* Enable. */
- if (ADD_REF(tbl) <= 0) {
- (void) sigdelset(&rpmsqCaught, tbl->signum);
+int rpmsqActivate(int state)
+{
+ sigset_t newMask, oldMask;
+
+ if (disableInterruptSafety)
+ return 0;
+
+ (void) sigfillset(&newMask);
+ (void) pthread_sigmask(SIG_BLOCK, &newMask, &oldMask);
+
+ if (state) {
+ struct sigaction sa;
+ for (rpmsig tbl = rpmsigTbl; tbl->signum >= 0; tbl++) {
+ sigdelset(&rpmsqCaught, tbl->signum);
+ memset(&tbl->siginfo, 0, sizeof(tbl->siginfo));
+
+ /* XXX Don't set a signal handler if already SIG_IGN */
+ sigaction(tbl->signum, NULL, &tbl->oact);
+ if (tbl->oact.sa_handler == SIG_IGN)
+ continue;
+
+ sigemptyset (&sa.sa_mask);
+ sa.sa_flags = SA_SIGINFO;
+ sa.sa_sigaction = rpmsqHandler;
+ if (sigaction(tbl->signum, &sa, &tbl->oact) == 0)
+ sigaddset(&rpmsqActive, tbl->signum);
+ }
+ } else {
+ for (rpmsig tbl = rpmsigTbl; tbl->signum >= 0; tbl++) {
+ if (!sigismember(&rpmsqActive, tbl->signum))
+ continue;
+ if (sigaction(tbl->signum, &tbl->oact, NULL) == 0) {
+ sigdelset(&rpmsqActive, tbl->signum);
+ sigdelset(&rpmsqCaught, tbl->signum);
+ memset(&tbl->siginfo, 0, sizeof(tbl->siginfo));
+ }
+ }
+ }
+ pthread_sigmask(SIG_SETMASK, &oldMask, NULL);
+ return 0;
+}
- /* XXX Don't set a signal handler if already SIG_IGN */
- (void) sigaction(tbl->signum, NULL, &tbl->oact);
- if (tbl->oact.sa_handler == SIG_IGN)
- continue;
+int rpmsqPoll(void)
+{
+ sigset_t newMask, oldMask;
+ int n = 0;
+
+ /* block all signals while processing the queue */
+ (void) sigfillset(&newMask);
+ (void) pthread_sigmask(SIG_BLOCK, &newMask, &oldMask);
+
+ for (rpmsig tbl = rpmsigTbl; tbl->signum >= 0; tbl++) {
+ /* honor blocked signals in polling too */
+ if (sigismember(&oldMask, tbl->signum))
+ continue;
+ if (sigismember(&rpmsqCaught, tbl->signum)) {
+ rpmsqAction_t handler = (tbl->handler != NULL) ? tbl->handler :
+ tbl->defhandler;
+ /* delete signal before running handler to prevent recursing */
+ sigdelset(&rpmsqCaught, tbl->signum);
+ handler(tbl->signum, &tbl->siginfo, NULL);
+ memset(&tbl->siginfo, 0, sizeof(tbl->siginfo));
+ n++;
+ }
+ }
+ pthread_sigmask(SIG_SETMASK, &oldMask, NULL);
+ return n;
+}
- (void) sigemptyset (&sa.sa_mask);
-#ifdef SA_SIGINFO
- sa.sa_flags = SA_SIGINFO;
-#else
- sa.sa_flags = 0;
+int rpmsqBlock(int op)
+{
+ static __thread sigset_t oldMask;
+ static __thread int blocked = 0;
+ sigset_t newMask;
+ int ret = 0;
+
+ if (op == SIG_BLOCK) {
+ blocked++;
+ if (blocked == 1) {
+ sigfillset(&newMask);
+ sigdelset(&newMask, SIGABRT);
+ sigdelset(&newMask, SIGBUS);
+ sigdelset(&newMask, SIGFPE);
+ sigdelset(&newMask, SIGILL);
+ sigdelset(&newMask, SIGSEGV);
+ sigdelset(&newMask, SIGTSTP);
+#ifdef HWASAN_BUILD
+ sigdelset(&newMask, SIGTRAP);
#endif
- sa.sa_sigaction = (handler != NULL ? handler : tbl->handler);
- if (sigaction(tbl->signum, &sa, &tbl->oact) < 0) {
- SUB_REF(tbl);
- break;
- }
- tbl->active = 1; /* XXX just in case */
- if (handler != NULL)
- tbl->handler = handler;
- }
- } else { /* Disable. */
- if (SUB_REF(tbl) <= 0) {
- if (sigaction(tbl->signum, &tbl->oact, NULL) < 0)
- break;
- tbl->active = 0; /* XXX just in case */
- tbl->handler = (handler != NULL ? handler : rpmsqAction);
- }
+ ret = pthread_sigmask(SIG_BLOCK, &newMask, &oldMask);
+ }
+ } else if (op == SIG_UNBLOCK) {
+ blocked--;
+ if (blocked == 0) {
+ ret = pthread_sigmask(SIG_SETMASK, &oldMask, NULL);
+ rpmsqPoll();
+ } else if (blocked < 0) {
+ blocked = 0;
+ ret = -1;
}
- ret = tbl->active;
- break;
}
+
return ret;
}
+/** \ingroup rpmio
+ *
+ * By default, librpm will trap various unix signals such as SIGINT and SIGTERM,
+ * in order to avoid process exit while locks are held or a transaction is being
+ * performed. However, there exist tools that operate on non-running roots (traditionally
+ * build systems such as mock), as well as deployment tools such as rpm-ostree.
+ *
+ * These tools are more robust against interruption - typically they
+ * will just throw away the partially constructed root. This function
+ * is designed for use by those tools, so an operator can happily
+ * press Control-C.
+ *
+ * It's recommended to call this once only at process startup if this
+ * behavior is desired (and to then avoid using librpm against "live"
+ * databases), because currently signal handlers will not be retroactively
+ * applied if a database is open.
+ */
+void rpmsqSetInterruptSafety(int on)
+{
+ disableInterruptSafety = !on;
+}
diff --git a/rpmio/rpmsq.h b/rpmio/rpmsq.h
index 00a1a72cf..23206457c 100644
--- a/rpmio/rpmsq.h
+++ b/rpmio/rpmsq.h
@@ -4,6 +4,7 @@
/** \ingroup rpmio
* \file rpmio/rpmsq.h
*
+ * Signal Queue API
*/
#include <rpm/rpmsw.h>
#include <signal.h>
@@ -18,11 +19,14 @@ extern "C" {
* @param info (siginfo_t) signal info
* @param context signal context
*/
-#ifdef SA_SIGINFO
typedef void (*rpmsqAction_t) (int signum, siginfo_t * info, void * context);
-#else
-typedef void (*rpmsqAction_t) (int signum);
-#endif
+
+/** \ingroup rpmsq
+ * SIG_DFL, SIG_IGN and SIG_ERR counterparts
+ */
+#define RPMSQ_DFL ((rpmsqAction_t)0)
+#define RPMSQ_IGN ((rpmsqAction_t)1)
+#define RPMSQ_ERR ((rpmsqAction_t)-1)
/** \ingroup rpmsq
* Test if given signal has been caught (while signals blocked).
@@ -33,24 +37,36 @@ typedef void (*rpmsqAction_t) (int signum);
int rpmsqIsCaught(int signum);
/** \ingroup rpmsq
- * Default signal handler.
+ * Activate (or disable) the signal queue.
+ * @param state 1 to enable, 0 to disable
+ * @return 0 on success, negative on error
+ */
+int rpmsqActivate(int state);
+
+/** \ingroup rpmsq
+ * Set or delete a signal handler for a signal.
* @param signum signal number
- * @param info (siginfo_t) signal info
- * @param context signal context
+ * @param handler signal handler or NULL to delete
+ * @return previous handler, RPMSQ_ERR on error
*/
-#ifdef SA_SIGINFO
-void rpmsqAction(int signum, siginfo_t * info, void * context);
-#else
-void rpmsqAction(int signum);
-#endif
+rpmsqAction_t rpmsqSetAction(int signum, rpmsqAction_t handler);
/** \ingroup rpmsq
- * Enable or disable a signal handler.
- * @param signum signal to enable (or disable if negative)
- * @param handler sa_sigaction handler (or NULL to use rpmsqHandler())
- * @return no. of refs, -1 on error
+ * Block or unblock (almost) all signals.
+ * The operation is "reference counted" so the calls can be nested,
+ * and signals are only unblocked when the reference count falls to zero.
+ * @param op SIG_BLOCK/SIG_UNBLOCK
+ * @return 0 on success, -1 on error
*/
-int rpmsqEnable(int signum, rpmsqAction_t handler);
+int rpmsqBlock(int op);
+
+/** \ingroup rpmsq
+ * Poll for caught signals, executing their handlers.
+ * @return no. active signals found
+ */
+int rpmsqPoll(void);
+
+void rpmsqSetInterruptSafety(int on);
#ifdef __cplusplus
}
diff --git a/rpmio/rpmstrpool.c b/rpmio/rpmstrpool.c
index 742afaa22..30a57eb10 100644
--- a/rpmio/rpmstrpool.c
+++ b/rpmio/rpmstrpool.c
@@ -27,7 +27,7 @@ struct poolHash_s {
};
struct rpmstrPool_s {
- char ** offs; /* pointers into data area */
+ const char ** offs; /* pointers into data area */
rpmsid offs_size; /* largest offset index */;
rpmsid offs_alloced; /* offsets allocation size */
@@ -35,6 +35,7 @@ struct rpmstrPool_s {
size_t chunks_size; /* current chunk */
size_t chunks_allocated; /* allocated size of the chunks array */
size_t chunk_allocated; /* size of the current chunk */
+ size_t chunk_used; /* usage of the current chunk */
poolHash hash; /* string -> sid hash table */
int frozen; /* are new id additions allowed? */
@@ -137,7 +138,7 @@ static void poolHashAddHEntry(rpmstrPool pool, const char * key, unsigned int ke
{
poolHash ht = pool->hash;
- /* keep load factor inbetween 0.25 and 0.5 */
+ /* keep load factor between 0.25 and 0.5 */
if (2*(ht->keyCount) > ht->numBuckets) {
poolHashResize(pool, ht->numBuckets * 2);
}
@@ -219,7 +220,7 @@ static void rpmstrPoolRehash(rpmstrPool pool)
pool->hash = poolHashFree(pool->hash);
pool->hash = poolHashCreate(sizehint);
- for (int i = 1; i < pool->offs_size; i++)
+ for (int i = 1; i <= pool->offs_size; i++)
poolHashAddEntry(pool, rpmstrPoolStr(pool, i), i);
}
@@ -234,8 +235,8 @@ rpmstrPool rpmstrPoolCreate(void)
pool->chunks = xcalloc(pool->chunks_allocated, sizeof(*pool->chunks));
pool->chunks_size = 1;
pool->chunk_allocated = STRDATA_CHUNK;
- pool->offs[1] = xcalloc(1, pool->chunk_allocated);
- pool->chunks[pool->chunks_size] = pool->offs[1];
+ pool->chunks[pool->chunks_size] = xcalloc(1, pool->chunk_allocated);
+ pool->offs[1] = pool->chunks[pool->chunks_size];
rpmstrPoolRehash(pool);
pool->nrefs = 1;
@@ -296,43 +297,40 @@ static rpmsid rpmstrPoolPut(rpmstrPool pool, const char *s, size_t slen, unsigne
{
char *t = NULL;
size_t ssize = slen + 1;
- size_t chunk_used;
pool->offs_size += 1;
- /* need one extra for end of string */
- /* and one extra to mark the end of the chunk */
- if (pool->offs_alloced <= pool->offs_size + 2) {
+ if (pool->offs_alloced <= pool->offs_size) {
pool->offs_alloced += STROFFS_CHUNK;
pool->offs = xrealloc(pool->offs,
pool->offs_alloced * sizeof(*pool->offs));
}
- chunk_used = pool->offs[pool->offs_size] - pool->chunks[pool->chunks_size];
- if (ssize + 1 > pool->chunk_allocated - chunk_used) {
- /* check size of ->chunks */
+ /* Do we need a new chunk to store the string? */
+ if (ssize > pool->chunk_allocated - pool->chunk_used) {
pool->chunks_size += 1;
+ /* Grow chunks array if needed */
if (pool->chunks_size >= pool->chunks_allocated) {
pool->chunks_allocated += pool->chunks_allocated;
pool->chunks = xrealloc(pool->chunks,
pool->chunks_allocated * sizeof(*pool->chunks));
}
- /* Check if string is bigger than chunks */
+ /* Ensure the string fits in the new chunk we're about to allocate */
if (ssize > pool->chunk_allocated) {
pool->chunk_allocated = 2 * ssize;
}
- /* Dummy entry for end of last string*/
- pool->offs_size += 1;
-
- pool->offs[pool->offs_size] = xcalloc(1, pool->chunk_allocated);
- pool->chunks[pool->chunks_size] = pool->offs[pool->offs_size];
+ pool->chunks[pool->chunks_size] = xcalloc(1, pool->chunk_allocated);
+ pool->chunk_used = 0;
}
- t = memcpy(pool->offs[pool->offs_size], s, slen);
+ /* Copy the string into current chunk, ensure termination */
+ t = memcpy(pool->chunks[pool->chunks_size] + pool->chunk_used, s, slen);
t[slen] = '\0';
- pool->offs[pool->offs_size+1] = t + ssize;
+ pool->chunk_used += ssize;
+ /* Actually add the string to the pool */
+ pool->offs[pool->offs_size] = t;
poolHashAddHEntry(pool, t, hash, pool->offs_size);
return pool->offs_size;
@@ -406,8 +404,8 @@ const char * rpmstrPoolStr(rpmstrPool pool, rpmsid sid)
size_t rpmstrPoolStrlen(rpmstrPool pool, rpmsid sid)
{
size_t slen = 0;
- if (pool && sid <= pool->offs_size) {
- slen = pool->offs[sid+1] - pool->offs[sid] - 1;
+ if (pool && sid > 0 && sid <= pool->offs_size) {
+ slen = strlen(pool->offs[sid]);
}
return slen;
}
diff --git a/rpmio/rpmstrpool.h b/rpmio/rpmstrpool.h
index 0db07bb40..11c946973 100644
--- a/rpmio/rpmstrpool.h
+++ b/rpmio/rpmstrpool.h
@@ -1,6 +1,13 @@
#ifndef _RPMSTRPOOL_H
#define _RPMSTRPOOL_H
+/** \ingroup rpmstrpool
+ * \file rpmio/rpmstrpool.h
+ *
+ * String pools manipulation helper functions
+ *
+ */
+
#include <rpm/rpmtypes.h>
#ifdef __cplusplus
@@ -80,11 +87,11 @@ const char * rpmstrPoolStr(rpmstrPool pool, rpmsid sid);
/** \ingroup rpmstrpool
* Return length of a string by its pool id. The result is equal to
- * calling strlen() on a string retrieved through rpmstrPoolStr() but
- * runs in constant time regardless of the length of the string.
+ * calling strlen() on a string retrieved through rpmstrPoolStr(), but
+ * the pool might be able to optimize the calculation.
* @param pool string pool
* @param sid pool id of a string
- * @return length of the string
+ * @return length of the string, 0 for invalid pool or id
*/
size_t rpmstrPoolStrlen(rpmstrPool pool, rpmsid sid);
diff --git a/rpmio/rpmsw.h b/rpmio/rpmsw.h
index 7c285e784..61d6fe317 100644
--- a/rpmio/rpmsw.h
+++ b/rpmio/rpmsw.h
@@ -3,6 +3,8 @@
/** \ingroup rpmio
* \file rpmio/rpmsw.h
+ *
+ * Statistics API
*/
#include <unistd.h>
diff --git a/rpmio/rpmurl.h b/rpmio/rpmurl.h
index e820e95e7..588c95df1 100644
--- a/rpmio/rpmurl.h
+++ b/rpmio/rpmurl.h
@@ -3,6 +3,8 @@
/** \ingroup rpmio
* \file rpmio/rpmurl.h
+ *
+ * A couple utils for URL Manipulation
*/
#ifdef __cplusplus
diff --git a/rpmio/rpmutil.h b/rpmio/rpmutil.h
index 68a21f980..9e8a25d0f 100644
--- a/rpmio/rpmutil.h
+++ b/rpmio/rpmutil.h
@@ -3,8 +3,9 @@
#include <unistd.h>
-/*
- * Miscellanous utility macros:
+/** \file rpmio/rpmutil.h
+ *
+ * Miscellaneous utility macros:
* - portability wrappers for various gcc extensions like __attribute__()
* - ...
*
diff --git a/rpmio/stubs.c b/rpmio/stubs.c
deleted file mode 100644
index 694306e47..000000000
--- a/rpmio/stubs.c
+++ /dev/null
@@ -1,18 +0,0 @@
-/**
- * \file rpmio/stubs.c
- */
-
-/* XXX Portable shared libraries require rpmlib to contain these functions. */
-
-#include "system.h"
-
-#if !defined(HAVE_STPCPY)
-#include "misc/stpcpy.c"
-#endif
-
-#if !defined(HAVE_STPNCPY)
-#include "misc/stpncpy.c"
-#endif
-
-#include "misc/fnmatch.h"
-#include "misc/fnmatch.c"