- add sha1 test vectors, verify on ix86/alpha/sparc.
authorjbj <devnull@localhost>
Sat, 21 Jul 2001 19:44:22 +0000 (19:44 +0000)
committerjbj <devnull@localhost>
Sat, 21 Jul 2001 19:44:22 +0000 (19:44 +0000)
- add (but disable for now) rpm-perl subpackage from Perl-RPM.
- python: parameterize with PYVER to handle 1.5 and/or 2.1 builds.
- add build dependency on zlib-devel (#49575).

CVS patchset: 4969
CVS date: 2001/07/21 19:44:22

14 files changed:
CHANGES
Makefile.am
build/pack.c
configure.in
lib/rpmlib.h
lib/verify.c
python/Makefile.am
python/Makefile.in
python/poptmodule.c
python/rpmmodule.c
rpm.spec.in
rpmio/digest.c
rpmio/rpmio_internal.h
rpmio/tdigest.c

diff --git a/CHANGES b/CHANGES
index ae564cb..2343bc4 100644 (file)
--- a/CHANGES
+++ b/CHANGES
        - resurrect --specedit for i18n.
        - fix: 4 memory leaks eliminated.
        - fix: yet another segfault from bad metadata prevented.
+       - add sha1 test vectors, verify on ix86/alpha/sparc.
+       - add (but disable for now) rpm-perl subpackage from Perl-RPM.
+       - python: parameterize with PYVER to handle 1.5 and/or 2.1 builds.
+       - add build dependency on zlib-devel (#49575).
 
 4.0 -> 4.0.[12]
        - add doxygen and lclint annotations most everywhere.
index f0780ae..05a3893 100644 (file)
@@ -6,10 +6,9 @@ EXTRA_DIST = CHANGES CREDITS Doxyheader GROUPS README.amiga INSTALL \
        RPM-GPG-KEY RPM-PGP-KEY \
        autodeps/none autodeps/*.prov autodeps/*.req autogen.sh \
        config.site db db3/configure gendiff installplatform platform* \
-       po/*.in po/*.po po/rpm.pot \
+       Perl-RPM po/*.in po/*.po po/rpm.pot \
        rpm.magic rpmpopt-$(VERSION) rpmqv.c rpm.c
 
-# XXX TODO: perl
 SUBDIRS = intl po @WITH_DB_SUBDIR@ popt rpmio rpmdb lib build misc @WITH_PYTHON_SUBDIR@ tools scripts tests doc .
 
 INCLUDES = \
index a141202..3f1f8a3 100644 (file)
@@ -486,7 +486,7 @@ int writeRPM(Header *hdrp, const char *fileName, int type,
                        sigtarget, Fstrerror(fd));
     }
 
-    fdInitSHA1(fd);
+    fdInitSHA1(fd, 0);
     if (headerWrite(fd, h, HEADER_MAGIC_NO))
        rc = RPMERR_NOSPACE;
     (void) Fflush(fd);
index a7e8b16..d37c109 100644 (file)
@@ -1096,7 +1096,7 @@ AC_OUTPUT([ Doxyfile Makefile rpmrc macros platform rpmpopt rpm.spec
        misc/Makefile po/Makefile.in intl/Makefile
        doc/Makefile doc/manual/Makefile
        doc/ja/Makefile doc/pl/Makefile doc/ru/Makefile doc/sk/Makefile
-       python/Makefile perl/Makefile perl/Makefile.PL ],
+       python/Makefile ],
   [    echo timestamp > popt/stamp-h.in
        echo timestamp > stamp-h.in
   ]
index a34c729..7d8cc8d 100644 (file)
@@ -208,14 +208,15 @@ typedef enum rpmTag_e {
 /* XXX 2nd underscore prevents tagTable generation */
     RPMTAG_SIG_BASE            = HEADER_SIGBASE,
     RPMTAG_SIGSIZE             = RPMTAG_SIG_BASE+1,
-    RPMTAG_SIGLEMD5_1          = RPMTAG_SIG_BASE+2,
+    RPMTAG_SIGLEMD5_1          = RPMTAG_SIG_BASE+2,    /*!< internal */
     RPMTAG_SIGPGP              = RPMTAG_SIG_BASE+3,
-    RPMTAG_SIGLEMD5_2          = RPMTAG_SIG_BASE+4,
+    RPMTAG_SIGLEMD5_2          = RPMTAG_SIG_BASE+4,    /*!< internal */
     RPMTAG_SIGMD5              = RPMTAG_SIG_BASE+5,
     RPMTAG_SIGGPG              = RPMTAG_SIG_BASE+6,
     RPMTAG_SIGPGP5             = RPMTAG_SIG_BASE+7,    /*!< internal */
 
-    RPMTAG_SHA1HEADER          = RPMTAG_SIG_BASE+8,
+    RPMTAG_BADSHA1HEADER       = RPMTAG_SIG_BASE+8,    /*!< internal */
+    RPMTAG_SHA1HEADER          = RPMTAG_SIG_BASE+9,
 
     RPMTAG_NAME                = 1000,
     RPMTAG_VERSION             = 1001,
index 4f79692..4d6cf47 100644 (file)
@@ -326,27 +326,32 @@ int rpmVerifyDigest(Header h)
     int_32 uhc;
     const char * hdigest;
     rpmTagType hdt;
+    int flags = RPMDIGEST_SHA1;
     int ec = 0;                /* assume no problems */
 
     /* Retrieve header digest. */
-    if (!hge(h, RPMTAG_SHA1HEADER, &hdt, (void **) &hdigest, NULL))
-       return 0;
-    if (hdigest == NULL)
-       return 0;
-
+    if (!hge(h, RPMTAG_SHA1HEADER, &hdt, (void **) &hdigest, NULL)) {
+       if (hge(h, RPMTAG_BADSHA1HEADER, &hdt, (void **) &hdigest, NULL))
+           flags |= (RPMDIGEST_REVERSE|RPMDIGEST_BCSWAP);
+       else
+           return 0;
+    }
     /* Regenerate original header. */
     if (!hge(h, RPMTAG_HEADERIMMUTABLE, &uht, &uh, &uhc))
        return 0;
 
+    if (hdigest == NULL || uh == NULL)
+       return 0;
+
     /* Compute header digest. */
-    {  const char * digest;
+    {  DIGEST_CTX ctx = rpmDigestInit(flags);
+       const char * digest;
        size_t digestlen;
-       int flags = RPMDIGEST_SHA1;
-       DIGEST_CTX ctx = rpmDigestInit(flags);
 
        rpmDigestUpdate(ctx, uh, uhc);
        rpmDigestFinal(ctx, (void **)&digest, &digestlen, 1);
 
+       /* XXX can't happen: report NULL malloc return as a digest failure. */
        ec = (digest == NULL || strcmp(hdigest, digest)) ? 1 : 0;
        digest = _free(digest);
     }
index d29aa99..95db6a9 100644 (file)
@@ -2,13 +2,15 @@
 
 AUTOMAKE_OPTIONS = 1.4 foreign
 
+PYVER=1.5
+
 INCLUDES = \
        -I$(top_srcdir) \
        -I$(top_srcdir)/lib \
        -I$(top_srcdir)/rpmdb \
        -I$(top_srcdir)/rpmio \
        -I$(top_srcdir)/popt \
-       -I/usr/include/python1.5 \
+       -I/usr/include/python${PYVER} \
        @INCPATH@
 
 EXTRA_DIST = hash.h upgrade.h
@@ -20,7 +22,7 @@ mylibs= \
 
 LDADD =
 
-pythondir = $(prefix)/lib/python1.5/site-packages
+pythondir = $(prefix)/lib/python${PYVER}/site-packages
 python_PROGRAMS = rpmmodule.so poptmodule.so
 
 rpmmodule_so_SOURCES =
@@ -32,10 +34,10 @@ noinst_LTLIBRARIES = librpmmodule.la
 librpmmodule_la_SOURCES = rpmmodule.c hash.c upgrade.c
 
 rpmmodule.so: $(librpmmodule_la_OBJECTS)
-       $(LINK) -o $@ $^ $(rpmmodule_so_LDFLAGS)
+       $(LINK) -o $@ $(librpmmodule_la_OBJECTS) $(rpmmodule_so_LDFLAGS)
 
 poptmodule.so: $(poptmodule_so_OBJECTS)
-       $(LINK) -o $@ $^ $(poptmodule_so_LDFLAGS)
+       $(LINK) -o $@ $(poptmodule_so_OBJECTS) $(poptmodule_so_LDFLAGS)
 
 .PHONY:        lclint
 lclint:
index a0168e0..f9dd475 100644 (file)
@@ -184,7 +184,9 @@ varprefix = @varprefix@
 
 AUTOMAKE_OPTIONS = 1.4 foreign
 
-INCLUDES =     -I$(top_srcdir)         -I$(top_srcdir)/lib     -I$(top_srcdir)/rpmdb   -I$(top_srcdir)/rpmio   -I$(top_srcdir)/popt    -I/usr/include/python1.5        @INCPATH@
+PYVER = 1.5
+
+INCLUDES =     -I$(top_srcdir)         -I$(top_srcdir)/lib     -I$(top_srcdir)/rpmdb   -I$(top_srcdir)/rpmio   -I$(top_srcdir)/popt    -I/usr/include/python${PYVER}   @INCPATH@
 
 
 EXTRA_DIST = hash.h upgrade.h
@@ -193,7 +195,7 @@ mylibs =    $(top_builddir)/lib/librpm.la   $(top_builddir)/rpmdb/librpmdb.la       $(t
 
 LDADD = 
 
-pythondir = $(prefix)/lib/python1.5/site-packages
+pythondir = $(prefix)/lib/python${PYVER}/site-packages
 python_PROGRAMS = rpmmodule.so poptmodule.so
 
 rpmmodule_so_SOURCES = 
@@ -492,10 +494,10 @@ mostlyclean distclean maintainer-clean
 
 
 rpmmodule.so: $(librpmmodule_la_OBJECTS)
-       $(LINK) -o $@ $^ $(rpmmodule_so_LDFLAGS)
+       $(LINK) -o $@ $(librpmmodule_la_OBJECTS) $(rpmmodule_so_LDFLAGS)
 
 poptmodule.so: $(poptmodule_so_OBJECTS)
-       $(LINK) -o $@ $^ $(poptmodule_so_LDFLAGS)
+       $(LINK) -o $@ $(poptmodule_so_OBJECTS) $(poptmodule_so_LDFLAGS)
 
 .PHONY:        lclint
 lclint:
index 15c73e0..158743a 100644 (file)
@@ -6,7 +6,7 @@
 
 #define PY_POPT_VERSION "0.2"
 
-static const char *rcs_id = "$Id: poptmodule.c,v 1.3 2001/07/20 17:09:08 jbj Exp $";
+static const char *rcs_id = "$Id: poptmodule.c,v 1.4 2001/07/21 19:44:22 jbj Exp $";
 
 static char *module_doc = "Python bindings for the popt library\n\
 \n\
@@ -35,6 +35,9 @@ typedef struct poptContext_s {
     int opt;
 } poptContextObject;
 
+/* The exception */
+static PyObject *pypoptError;
+
 /* Misc functions */
 void __printPopt(struct poptOption *opts)
 {
index 8a0d22e..356b475 100644 (file)
@@ -12,6 +12,7 @@
 #include <glob.h>      /* XXX rpmio.h */
 #include <dirent.h>    /* XXX rpmio.h */
 #include <locale.h>
+#include <time.h>
 
 #include "Python.h"
 #include "rpmcli.h"    /* XXX for rpmCheckSig */
@@ -23,7 +24,7 @@ extern int _rpmio_debug;
 
 #ifdef __LCLINT__
 #undef PyObject_HEAD
-#defin PyObject_HEAD   int _PyObjectHead
+#define        PyObject_HEAD   int _PyObjectHead
 #endif
 
 extern int mdfile(const char *fn, unsigned char *digest);
@@ -648,7 +649,7 @@ static PyMappingMethods hdrAsMapping = {
 /** \ingroup python
  */
 static PyTypeObject hdrType = {
-       PyObject_HEAD_INIT(&PyType_Type)
+       PyObject_HEAD_INIT(NULL)
        0,                              /* ob_size */
        "header",                       /* tp_name */
        sizeof(hdrObject),              /* tp_size */
@@ -746,7 +747,7 @@ static void rpmdbMIDealloc(rpmdbMIObject * s) {
 /** \ingroup python
  */
 static PyTypeObject rpmdbMIType = {
-       PyObject_HEAD_INIT(&PyType_Type)
+       PyObject_HEAD_INIT(NULL)
        0,                              /* ob_size */
        "rpmdbMatchIterator",           /* tp_name */
        sizeof(rpmdbMIObject),  /* tp_size */
@@ -1070,7 +1071,7 @@ static PyMappingMethods rpmdbAsMapping = {
 /**
  */
 static PyTypeObject rpmdbType = {
-       PyObject_HEAD_INIT(&PyType_Type)
+       PyObject_HEAD_INIT(NULL)
        0,                              /* ob_size */
        "rpmdb",                        /* tp_name */
        sizeof(rpmdbObject),            /* tp_size */
@@ -1511,7 +1512,7 @@ static int rpmtransSetAttr(rpmtransObject * o, char * name,
 /** \ingroup python
  */
 static PyTypeObject rpmtransType = {
-       PyObject_HEAD_INIT(&PyType_Type)
+       PyObject_HEAD_INIT(NULL)
        0,                              /* ob_size */
        "rpmtrans",                     /* tp_name */
        sizeof(rpmtransObject),         /* tp_size */
@@ -1641,6 +1642,9 @@ static void pkgSort(struct pkgSet * psp) {
     int i;
     char *name;
 
+    if (psp->numPackages <= 0)
+       return;
+
     qsort(psp->packages, psp->numPackages, sizeof(*psp->packages),
         (void *) pkgCompareVer);
 
@@ -2423,10 +2427,19 @@ void initrpm(void) {
     const struct headerSprintfExtension_s * extensions = rpmHeaderFormats;
     struct headerSprintfExtension_s * ext;
 
+    m = Py_InitModule("rpm", rpmModuleMethods);
+
+    hdrType.ob_type = &PyType_Type;
+    rpmdbMIType.ob_type = &PyType_Type;
+    rpmdbType.ob_type = &PyType_Type;
+    rpmtransType.ob_type = &PyType_Type;
+
+    if(!m)
+       return;
+
 /*      _rpmio_debug = -1; */
     rpmReadConfigFiles(NULL, NULL);
 
-    m = Py_InitModule("rpm", rpmModuleMethods);
     d = PyModule_GetDict(m);
 
     pyrpmError = PyString_FromString("rpm.error");
index 175b8b4..8f25557 100644 (file)
@@ -1,4 +1,5 @@
 %define        with_python_subpackage  @WITH_PYTHON_SUBPACKAGE@ %{nil}
+%define with_perl_subpackage   0
 %define        with_bzip2              @WITH_BZIP2@ %{nil}
 %define        with_apidocs            @WITH_APIDOCS@ %{nil}
 %define with_internal_db       @WITH_INTERNAL_DB@ %{nil}
@@ -37,6 +38,7 @@ Requires: glibc >= 2.1.92
 %endif
 %endif
 
+BuildRequires: zlib-devel
 # XXX Red Hat 5.2 has not bzip2 or python
 %if %{with_bzip2}
 BuildRequires: bzip2 >= 0.9.0c-2
@@ -44,6 +46,9 @@ BuildRequires: bzip2 >= 0.9.0c-2
 %if %{with_python_subpackage}
 BuildRequires: python-devel >= 1.5.2
 %endif
+%if %{with_perl_subpackage}
+BuildRequires: perl >= 0:5.00503
+%endif
 
 BuildRoot: %{_tmppath}/%{name}-root
 
@@ -79,6 +84,37 @@ Requires: rpm = %{version}
 This package contains scripts and executable programs that are used to
 build packages using RPM.
 
+%if %{with_perl_subpackage}
+%package perl
+Summary: Native bindings to the RPM API for Perl.
+Version: 0.32
+Group: Development/Languages
+URL: http://www.cpan.org
+Requires: rpm = %{version}
+Requires: perl >= 0:5.00503
+Requires: popt = 1.6.3
+Obsoletes: perl-Perl-RPM
+
+%description perl
+The Perl-RPM module is an attempt to provide Perl-level access to the
+complete application programming interface that is a part of the Red
+Hat Package Manager (RPM). Rather than have scripts rely on executing
+RPM commands and parse the resulting output, this module aims to give
+Perl programmers the ability to do anything that would otherwise have
+been done in C or C++.
+
+The interface is being designed and laid out as a collection of
+classes, at least some of which are also available as tied-hash
+implementations.
+
+At this time, the interface only provides access to the database of
+installed packages, and header data retrieval for RPM and SRPM files
+is not yet installed.  Error management and the export of most defined
+constants, through RPM::Error and RPM::Constants, respectively, are
+also available.
+
+%endif
+
 %if %{with_python_subpackage}
 %package python
 Summary: Python bindings for apps which will manipulate RPM packages.
@@ -132,6 +168,14 @@ CFLAGS="$RPM_OPT_FLAGS" ./configure --prefix=%{__prefix}
 
 make
 
+%if %{with_perl_subpackage}
+{ cd Perl-RPM
+  CFLAGS="$RPM_OPT_FLAGS" perl Makefile.PL
+  export SUBDIR="%{_builddir}/%{buildsubdir}"
+  make INC="-I. -I$SUBDIR/lib -I$SUBDIR/rpmio -I$SUBDIR/popt" %{?_smp_mflags}
+}
+%endif
+
 %install
 rm -rf $RPM_BUILD_ROOT
 
@@ -170,6 +214,18 @@ done
 gzip -9n apidocs/man/man*/* || :
 %endif
 
+%if %{with_perl_subpackage}
+{ cd Perl-RPM
+  eval `perl '-V:installsitearch'`
+  eval `perl '-V:installarchlib'`
+  mkdir -p $RPM_BUILD_ROOT/$installarchlib
+  make PREFIX=$RPM_BUILD_ROOT/usr install
+  rm -f $RPM_BUILD_ROOT/$installarchlib/perllocal.pod
+  rm -f $RPM_BUILD_ROOT/$installsitearch/auto/RPM/.packlist
+  cd ..
+}
+%endif
+
 %if %{strip_binaries}
 { cd $RPM_BUILD_ROOT
   strip ./bin/rpm
@@ -384,6 +440,15 @@ fi
 %{__prefix}/lib/python1.5/site-packages/poptmodule.so
 %endif
 
+%if %{with_perl_subpackage}
+%files perl
+%defattr(-,root,root)
+%rpmattr       %{__prefix}/bin/rpmprune
+%{perl_sitearch}/auto/*
+%{__prefix}%{__share}/man/man1/rpmprune.1*
+%{__prefix}%{__share}/man/man3/RPM*
+%endif
+
 %files devel
 %defattr(-,root,root)
 %if %{with_apidocs}
index a0c4d29..d01ea6b 100644 (file)
@@ -381,12 +381,21 @@ byteReverse(byte *buf, unsigned nbytes)
 {
     unsigned nlongs = nbytes / sizeof(uint32);
     uint32 t;
-    do {
-       t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
-           ((unsigned) buf[1] << 8 | buf[0]);
-       *(uint32 *) buf = t;
-       buf += 4;
-    } while (--nlongs);
+    if (IS_BIG_ENDIAN()) {
+       do {
+           t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+               ((unsigned) buf[1] << 8 | buf[0]);
+           *(uint32 *) buf = t;
+           buf += 4;
+       } while (--nlongs);
+    } else {
+       do {
+           t = (uint32) ((unsigned) buf[0] << 8 | buf[1]) << 16 |
+               ((unsigned) buf[2] << 8 | buf[3]);
+           *(uint32 *) buf = t;
+           buf += 4;
+       } while (--nlongs);
+    }
 }
 /*@=shadow@*/
 
@@ -405,6 +414,8 @@ rpmDigestInit(rpmDigestFlags flags)
        ctx->digest[1] = 0xefcdab89;
        ctx->digest[2] = 0x98badcfe;
        ctx->digest[3] = 0x10325476;
+       /* md5 sums are little endian (no swap) so big endian needs the swap. */
+       ctx->doByteReverse = (IS_BIG_ENDIAN()) ? 1 : 0;
     }
 
     if (flags & RPMDIGEST_SHA1) {
@@ -416,12 +427,12 @@ rpmDigestInit(rpmDigestFlags flags)
        ctx->digest[ 2 ] = 0x98badcfe;
        ctx->digest[ 3 ] = 0x10325476;
        ctx->digest[ 4 ] = 0xc3d2e1f0;
+       /* md5 sums are little endian (no swap) so big endian needs the swap. */
+       ctx->doByteReverse = (IS_BIG_ENDIAN()) ? 0 : 1;
     }
 
-    /* md5 sums are little endian (no swap) so big endian needs the swap. */
-    ctx->doByteReverse = (IS_BIG_ENDIAN()) ? 1 : 0;
-    if (flags & RPMDIGEST_NATIVE)
-       ctx->doByteReverse = 0;
+    if (flags & RPMDIGEST_REVERSE)
+       ctx->doByteReverse ^= 1;
 
     ctx->bits[0] = 0;
     ctx->bits[1] = 0;
@@ -507,16 +518,22 @@ rpmDigestFinal(/*@only@*/ DIGEST_CTX ctx, /*@out@*/ void ** datap,
     memset(p, 0, count - sizeof(ctx->bits));
     if (ctx->doByteReverse)
        byteReverse(ctx->in, ctx->datalen - sizeof(ctx->bits));
-    ((uint32 *) ctx->in)[14] = ctx->bits[0];
-    ((uint32 *) ctx->in)[15] = ctx->bits[1];
+
+    if (ctx->flags & (RPMDIGEST_MD5|RPMDIGEST_BCSWAP)) {
+       ((uint32 *) ctx->in)[14] = ctx->bits[0];
+       ((uint32 *) ctx->in)[15] = ctx->bits[1];
+    } else {
+       ((uint32 *) ctx->in)[14] = ctx->bits[1];
+       ((uint32 *) ctx->in)[15] = ctx->bits[0];
+    }
     /*@-moduncon@*/
     ctx->transform(ctx);
     /*@=moduncon@*/
 
-    /* Return final digest. */
     if (ctx->doByteReverse)
        byteReverse((byte *) ctx->digest, ctx->digestlen);
 
+    /* Return final digest. */
     if (!asAscii) {
        if (lenp) *lenp = ctx->digestlen;
        if (datap) {
index 05cae05..eae24d4 100644 (file)
@@ -54,7 +54,8 @@ typedef       /*@abstract@*/ struct {
 typedef enum rpmDigestFlags_e {
     RPMDIGEST_MD5      = (1 <<  0),    /*!< MD5 digest. */
     RPMDIGEST_SHA1     = (1 <<  1),    /*!< SHA1 digest. */
-    RPMDIGEST_NATIVE   = (1 << 16),    /*!< Should bytes be reversed? */
+    RPMDIGEST_REVERSE  = (1 << 16),    /*!< Should bytes be reversed? */
+    RPMDIGEST_BCSWAP   = (1 << 17),    /*!< Should bit count be reversed? */
 } rpmDigestFlags;
 
 typedef /*@abstract@*/ struct DIGEST_CTX_s * DIGEST_CTX;
@@ -417,7 +418,7 @@ FD_t c2f(/*@null@*/ void * cookie)
 void fdInitMD5(FD_t fd, int flags)
        /*@modifies fd @*/
 {
-    if (flags) flags = RPMDIGEST_NATIVE;
+    if (flags) flags = RPMDIGEST_REVERSE;
     flags |= RPMDIGEST_MD5;
     fd->digest = rpmDigestInit(flags);
 }
@@ -425,10 +426,12 @@ void fdInitMD5(FD_t fd, int flags)
 /** \ingroup rpmio
  */
 /*@unused@*/ static inline
-void fdInitSHA1(FD_t fd)
+void fdInitSHA1(FD_t fd, int flags)
        /*@modifies fd @*/
 {
-    fd->digest = rpmDigestInit(RPMDIGEST_SHA1);
+    if (flags) flags = RPMDIGEST_REVERSE;
+    flags |= RPMDIGEST_SHA1;
+    fd->digest = rpmDigestInit(flags);
 }
 
 /** \ingroup rpmio
index 59b19a1..9e8e65b 100644 (file)
@@ -6,14 +6,26 @@
 static rpmDigestFlags flags = RPMDIGEST_MD5;
 extern int _rpmio_debug;
 
+static int fips = 0;
+
+const char * adigest = "a9993e364706816aba3e25717850c26c9cd0d89d";
+const char * bdigest = "84983e441c3bd26ebaae4aa1f95129e5e54670f1";
+const char * cdigest = "34aa973cd4c4daa4f61eeb2bdbad27316534016f";
+
 static struct poptOption optionsTable[] = {
  { "md5", '\0', POPT_BIT_SET,  &flags, RPMDIGEST_MD5,  NULL, NULL },
  { "sha1",'\0', POPT_BIT_SET,  &flags, RPMDIGEST_SHA1, NULL, NULL },
- { "native",'\0', POPT_BIT_SET, &flags, RPMDIGEST_NATIVE,      NULL, NULL },
+ { "reverse",'\0', POPT_BIT_SET, &flags, RPMDIGEST_REVERSE,    NULL, NULL },
+ { "fipsa",'\0', POPT_BIT_SET, &fips, 1,       NULL, NULL },
+ { "fipsb",'\0', POPT_BIT_SET, &fips, 2,       NULL, NULL },
+ { "fipsc",'\0', POPT_BIT_SET, &fips, 3,       NULL, NULL },
  { "debug",'d', POPT_ARG_VAL, &_rpmio_debug, -1,       NULL, NULL },
   POPT_TABLEEND
 };
 
+#define        SHA1_CMD        "/usr/bin/sha1sum"
+#define        MD5_CMD         "/usr/bin/md5sum"
+
 int
 main(int argc, const char *argv[])
 {
@@ -21,24 +33,94 @@ main(int argc, const char *argv[])
     const char ** args;
     const char * ifn;
     const char * ofn = "/dev/null";
+    DIGEST_CTX ctx;
+    const char * idigest;
+    const char * odigest;
+    const char * sdigest;
+    const char * digest;
+    size_t digestlen;
+    int asAscii = 1;
+    int reverse;
     int rc;
+    char appendix;
+    int i;
 
     optCon = poptGetContext(argv[0], argc, argv, optionsTable, 0);
     while ((rc = poptGetNextOpt(optCon)) > 0)
        ;
 
+    reverse = (flags & RPMDIGEST_REVERSE);
+    if (fips) {
+       flags &= ~RPMDIGEST_MD5;
+       flags |= RPMDIGEST_SHA1;
+       ctx = rpmDigestInit(flags);
+       ifn = NULL;
+       appendix = ' ';
+       sdigest = NULL;
+       switch (fips) {
+       case 1:
+           ifn = "abc";
+           rpmDigestUpdate(ctx, ifn, strlen(ifn));
+           sdigest = adigest;
+           appendix = 'A';
+           break;
+       case 2:
+           ifn = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
+           rpmDigestUpdate(ctx, ifn, strlen(ifn));
+           sdigest = bdigest;
+           appendix = 'B';
+           break;
+       case 3:
+           ifn = "aaaaaaaaaaa ...";
+           for (i = 0; i < 1000000; i++)
+               rpmDigestUpdate(ctx, ifn, 1);
+           sdigest = cdigest;
+           appendix = 'C';
+           break;
+       }
+       if (ifn == NULL)
+           return 1;
+       rpmDigestFinal(ctx, (void **)&digest, &digestlen, asAscii);
+
+       if (digest) {
+           fprintf(stdout, "%s     %s\n", digest, ifn);
+           fflush(stdout);
+           free((void *)digest);
+       }
+       if (sdigest) {
+           fprintf(stdout, "%s     FIPS PUB 180-1 Appendix %c\n", sdigest,
+               appendix);
+           fflush(stdout);
+       }
+       return 0;
+    }
+
     args = poptGetArgs(optCon);
     rc = 0;
+    if (args)
     while ((ifn = *args++) != NULL) {
        FD_t ifd;
        FD_t ofd;
        unsigned char buf[BUFSIZ];
        ssize_t nb;
-       DIGEST_CTX ctx;
-       const char * idigest;
-       const char * odigest;
-       const char * digest;
-       size_t digestlen;
+
+       sdigest = NULL;
+       {   char *se;
+           FILE * sfp;
+
+           se = buf;
+           *se = '\0';
+           se = stpcpy(se, ((flags & RPMDIGEST_SHA1) ? SHA1_CMD : MD5_CMD));
+           *se++ = ' ';
+           se = stpcpy(se, ifn);
+           if ((sfp = popen(buf, "r")) != NULL) {
+               fgets(buf, sizeof(buf), sfp);
+               if ((se = strchr(buf, ' ')) != NULL)
+                   *se = '\0';
+               sdigest = xstrdup(buf);
+               pclose(sfp);
+           }
+       }
 
        ifd = Fopen(ifn, "r.ufdio");
        if (ifd == NULL || Ferror(ifd)) {
@@ -48,7 +130,7 @@ main(int argc, const char *argv[])
            continue;
        }
        idigest = NULL;
-       (flags & RPMDIGEST_SHA1) ? fdInitSHA1(ifd) : fdInitMD5(ifd, 0);
+       (flags & RPMDIGEST_SHA1) ? fdInitSHA1(ifd, reverse) : fdInitMD5(ifd, reverse);
 
        ofd = Fopen(ofn, "w.ufdio");
        if (ofd == NULL || Ferror(ofd)) {
@@ -59,7 +141,7 @@ main(int argc, const char *argv[])
            continue;
        }
        odigest = NULL;
-       (flags & RPMDIGEST_SHA1) ? fdInitSHA1(ofd) : fdInitMD5(ofd, 0);
+       (flags & RPMDIGEST_SHA1) ? fdInitSHA1(ofd, reverse) : fdInitMD5(ofd, reverse);
 
        ctx = rpmDigestInit(flags);
 
@@ -68,14 +150,18 @@ main(int argc, const char *argv[])
            (void) Fwrite(buf, 1, nb, ofd);
        }
 
-       fdFiniMD5(ifd, (void **)&idigest, NULL, 1);
+       (flags & RPMDIGEST_SHA1)
+           ? fdFiniSHA1(ifd, (void **)&idigest, NULL, asAscii)
+           : fdFiniMD5(ifd, (void **)&idigest, NULL, asAscii);
        Fclose(ifd);
 
        Fflush(ofd);
-       fdFiniMD5(ofd, (void **)&odigest, NULL, 1);
+       (flags & RPMDIGEST_SHA1)
+           ? fdFiniSHA1(ofd, (void **)&odigest, NULL, asAscii)
+           : fdFiniMD5(ofd, (void **)&odigest, NULL, asAscii);
        Fclose(ofd);
 
-       rpmDigestFinal(ctx, (void **)&digest, &digestlen, 1);
+       rpmDigestFinal(ctx, (void **)&digest, &digestlen, asAscii);
 
        if (digest) {
            fprintf(stdout, "%s     %s\n", digest, ifn);
@@ -92,6 +178,11 @@ main(int argc, const char *argv[])
            fflush(stdout);
            free((void *)odigest);
        }
+       if (sdigest) {
+           fprintf(stdout, "%s cmd %s\n", sdigest, ifn);
+           fflush(stdout);
+           free((void *)sdigest);
+       }
     }
     return rc;
 }