Add macro %isu_package to generate ISU Package
[platform/upstream/rpm.git] / rpmbuild.c
index 3b0b8ce..893a559 100644 (file)
@@ -1,12 +1,8 @@
 #include "system.h"
-const char *__progname;
-
-#define        _AUTOHELP
 
 #include <errno.h>
 #include <libgen.h>
 #include <ctype.h>
-#include <sys/wait.h>
 
 #include <rpm/rpmcli.h>
 #include <rpm/rpmlib.h>                        /* RPMSIGTAG, rpmReadPackageFile .. */
@@ -21,6 +17,235 @@ const char *__progname;
 
 #include "debug.h"
 
+static struct rpmBuildArguments_s rpmBTArgs;
+
+#define        POPT_NOLANG             -1012
+#define        POPT_RMSOURCE           -1013
+#define        POPT_RMBUILD            -1014
+#define        POPT_BUILDROOT          -1015
+#define        POPT_TARGETPLATFORM     -1016
+#define        POPT_NOBUILD            -1017
+#define        POPT_RMSPEC             -1019
+#define POPT_NODIRTOKENS       -1020
+#define POPT_BUILDINPLACE      -1021
+
+#define        POPT_REBUILD            0x4262 /* Bb */
+#define        POPT_RECOMPILE          0x4369 /* Ci */
+#define        POPT_BA                 0x6261
+#define        POPT_BB                 0x6262
+#define        POPT_BC                 0x6263
+#define        POPT_BI                 0x6269
+#define        POPT_BL                 0x626c
+#define        POPT_BP                 0x6270
+#define        POPT_BS                 0x6273
+#define        POPT_RA                 0x4261
+#define        POPT_RB                 0x4262
+#define        POPT_RC                 0x4263
+#define        POPT_RI                 0x4269
+#define        POPT_RL                 0x426c
+#define        POPT_RP                 0x4270
+#define        POPT_RS                 0x4273
+#define        POPT_TA                 0x7461
+#define        POPT_TB                 0x7462
+#define        POPT_TC                 0x7463
+#define        POPT_TI                 0x7469
+#define        POPT_TL                 0x746c
+#define        POPT_TP                 0x7470
+#define        POPT_TS                 0x7473
+
+extern int _fsm_debug;
+
+static rpmSpecFlags spec_flags = 0;    /*!< Bit(s) to control spec parsing. */
+static int noDeps = 0;                 /*!< from --nodeps */
+static int shortCircuit = 0;           /*!< from --short-circuit */
+static char buildMode = 0;             /*!< Build mode (one of "btBC") */
+static char buildChar = 0;             /*!< Build stage (one of "abcilps ") */
+static rpmBuildFlags nobuildAmount = 0;        /*!< Build stage disablers */
+static ARGV_t build_targets = NULL;    /*!< Target platform(s) */
+static int buildInPlace = 0;           /*!< from --build-in-place */
+
+static void buildArgCallback( poptContext con,
+       enum poptCallbackReason reason,
+       const struct poptOption * opt, const char * arg,
+       const void * data)
+{
+    BTA_t rba = &rpmBTArgs;
+
+    switch (opt->val) {
+    case POPT_REBUILD:
+    case POPT_RECOMPILE:
+    case POPT_BA:
+    case POPT_BB:
+    case POPT_BC:
+    case POPT_BI:
+    case POPT_BL:
+    case POPT_BP:
+    case POPT_BS:
+    case POPT_RA:
+    /* case POPT_RB: same value as POPT_REBUILD */
+    case POPT_RC:
+    case POPT_RI:
+    case POPT_RL:
+    case POPT_RP:
+    case POPT_RS:
+    case POPT_TA:
+    case POPT_TB:
+    case POPT_TC:
+    case POPT_TI:
+    case POPT_TL:
+    case POPT_TP:
+    case POPT_TS:
+       if (opt->val == POPT_BS || opt->val == POPT_TS)
+           noDeps = 1;
+       if (buildMode == '\0' && buildChar == '\0') {
+           buildMode = (((unsigned)opt->val) >> 8) & 0xff;
+           buildChar = (opt->val     ) & 0xff;
+       }
+       break;
+
+    case POPT_NODIRTOKENS: rba->pkgFlags |= RPMBUILD_PKG_NODIRTOKENS; break;
+    case POPT_NOBUILD: rba->buildAmount |= RPMBUILD_NOBUILD; break;
+    case POPT_NOLANG: spec_flags |= RPMSPEC_NOLANG; break;
+    case POPT_RMSOURCE: rba->buildAmount |= RPMBUILD_RMSOURCE; break;
+    case POPT_RMSPEC: rba->buildAmount |= RPMBUILD_RMSPEC; break;
+    case POPT_RMBUILD: rba->buildAmount |= RPMBUILD_RMBUILD; break;
+    case POPT_BUILDROOT:
+       if (rba->buildRootOverride) {
+           rpmlog(RPMLOG_ERR, _("buildroot already specified, ignoring %s\n"), arg);
+           break;
+       }
+       rba->buildRootOverride = xstrdup(arg);
+       break;
+    case POPT_TARGETPLATFORM:
+       argvSplit(&build_targets, arg, ",");
+       break;
+
+    case RPMCLI_POPT_FORCE:
+       spec_flags |= RPMSPEC_FORCE;
+       break;
+
+    case POPT_BUILDINPLACE:
+       rpmDefineMacro(NULL, "_build_in_place 1", 0);
+       buildInPlace = 1;
+       break;
+    }
+}
+
+static struct poptOption rpmBuildPoptTable[] = {
+ { NULL, '\0', POPT_ARG_CALLBACK | POPT_CBFLAG_INC_DATA | POPT_CBFLAG_CONTINUE,
+       buildArgCallback, 0, NULL, NULL },
+
+ { "bp", 0, POPT_ARGFLAG_ONEDASH, 0, POPT_BP,
+       N_("build through %prep (unpack sources and apply patches) from <specfile>"),
+       N_("<specfile>") },
+ { "bc", 0, POPT_ARGFLAG_ONEDASH, 0, POPT_BC,
+       N_("build through %build (%prep, then compile) from <specfile>"),
+       N_("<specfile>") },
+ { "bi", 0, POPT_ARGFLAG_ONEDASH, 0, POPT_BI,
+       N_("build through %install (%prep, %build, then install) from <specfile>"),
+       N_("<specfile>") },
+ { "bl", 0, POPT_ARGFLAG_ONEDASH, 0, POPT_BL,
+       N_("verify %files section from <specfile>"),
+       N_("<specfile>") },
+ { "ba", 0, POPT_ARGFLAG_ONEDASH, 0, POPT_BA,
+       N_("build source and binary packages from <specfile>"),
+       N_("<specfile>") },
+ { "bb", 0, POPT_ARGFLAG_ONEDASH, 0, POPT_BB,
+       N_("build binary package only from <specfile>"),
+       N_("<specfile>") },
+ { "bs", 0, POPT_ARGFLAG_ONEDASH, 0, POPT_BS,
+       N_("build source package only from <specfile>"),
+       N_("<specfile>") },
+
+ { "rp", 0, POPT_ARGFLAG_ONEDASH, 0, POPT_RP,
+       N_("build through %prep (unpack sources and apply patches) from <source package>"),
+       N_("<source package>") },
+ { "rc", 0, POPT_ARGFLAG_ONEDASH, 0, POPT_RC,
+       N_("build through %build (%prep, then compile) from <source package>"),
+       N_("<source package>") },
+ { "ri", 0, POPT_ARGFLAG_ONEDASH, 0, POPT_RI,
+       N_("build through %install (%prep, %build, then install) from <source package>"),
+       N_("<source package>") },
+ { "rl", 0, POPT_ARGFLAG_ONEDASH, 0, POPT_RL,
+       N_("verify %files section from <source package>"),
+       N_("<source package>") },
+ { "ra", 0, POPT_ARGFLAG_ONEDASH, 0, POPT_RA,
+       N_("build source and binary packages from <source package>"),
+       N_("<source package>") },
+ { "rb", 0, POPT_ARGFLAG_ONEDASH, 0, POPT_RB,
+       N_("build binary package only from <source package>"),
+       N_("<source package>") },
+ { "rs", 0, POPT_ARGFLAG_ONEDASH, 0, POPT_RS,
+       N_("build source package only from <source package>"),
+       N_("<source package>") },
+
+ { "tp", 0, POPT_ARGFLAG_ONEDASH, 0, POPT_TP,
+       N_("build through %prep (unpack sources and apply patches) from <tarball>"),
+       N_("<tarball>") },
+ { "tc", 0, POPT_ARGFLAG_ONEDASH, 0, POPT_TC,
+       N_("build through %build (%prep, then compile) from <tarball>"),
+       N_("<tarball>") },
+ { "ti", 0, POPT_ARGFLAG_ONEDASH, 0, POPT_TI,
+       N_("build through %install (%prep, %build, then install) from <tarball>"),
+       N_("<tarball>") },
+ { "tl", 0, POPT_ARGFLAG_ONEDASH|POPT_ARGFLAG_DOC_HIDDEN, 0, POPT_TL,
+       N_("verify %files section from <tarball>"),
+       N_("<tarball>") },
+ { "ta", 0, POPT_ARGFLAG_ONEDASH, 0, POPT_TA,
+       N_("build source and binary packages from <tarball>"),
+       N_("<tarball>") },
+ { "tb", 0, POPT_ARGFLAG_ONEDASH, 0, POPT_TB,
+       N_("build binary package only from <tarball>"),
+       N_("<tarball>") },
+ { "ts", 0, POPT_ARGFLAG_ONEDASH, 0, POPT_TS,
+       N_("build source package only from <tarball>"),
+       N_("<tarball>") },
+
+ { "rebuild", '\0', 0, 0, POPT_REBUILD,
+       N_("build binary package from <source package>"),
+       N_("<source package>") },
+ { "recompile", '\0', 0, 0, POPT_RECOMPILE,
+       N_("build through %install (%prep, %build, then install) from <source package>"),
+       N_("<source package>") },
+
+ { "buildroot", '\0', POPT_ARG_STRING, 0,  POPT_BUILDROOT,
+       N_("override build root"), "DIRECTORY" },
+ { "build-in-place", '\0', 0, 0, POPT_BUILDINPLACE,
+       N_("run build in current directory"), NULL },
+ { "clean", '\0', 0, 0, POPT_RMBUILD,
+       N_("remove build tree when done"), NULL},
+ { "force", '\0', POPT_ARGFLAG_DOC_HIDDEN, 0, RPMCLI_POPT_FORCE,
+        N_("ignore ExcludeArch: directives from spec file"), NULL},
+ { "fsmdebug", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_DOC_HIDDEN), &_fsm_debug, -1,
+       N_("debug file state machine"), NULL},
+ { "nobuild", '\0', 0, 0,  POPT_NOBUILD,
+       N_("do not execute any stages of the build"), NULL },
+ { "nodeps", '\0', POPT_ARG_VAL, &noDeps, 1,
+       N_("do not verify build dependencies"), NULL },
+ { "nodirtokens", '\0', 0, 0, POPT_NODIRTOKENS,
+       N_("generate package header(s) compatible with (legacy) rpm v3 packaging"),
+       NULL},
+
+ { "noclean", '\0', POPT_BIT_SET, &nobuildAmount, RPMBUILD_CLEAN,
+       N_("do not execute %clean stage of the build"), NULL },
+ { "noprep", '\0', POPT_BIT_SET, &nobuildAmount, RPMBUILD_PREP,
+       N_("do not execute %prep stage of the build"), NULL },
+ { "nocheck", '\0', POPT_BIT_SET, &nobuildAmount, RPMBUILD_CHECK,
+       N_("do not execute %check stage of the build"), NULL },
+
+ { "nolang", '\0', POPT_ARGFLAG_DOC_HIDDEN, 0, POPT_NOLANG,
+       N_("do not accept i18N msgstr's from specfile"), NULL},
+ { "rmsource", '\0', 0, 0, POPT_RMSOURCE,
+       N_("remove sources when done"), NULL},
+ { "rmspec", '\0', 0, 0, POPT_RMSPEC,
+       N_("remove specfile when done"), NULL},
+ { "short-circuit", '\0', POPT_ARG_VAL, &shortCircuit,  1,
+       N_("skip straight to specified stage (only for c,i)"), NULL },
+ { "target", '\0', POPT_ARG_STRING, 0,  POPT_TARGETPLATFORM,
+       N_("override target platform"), "CPU-VENDOR-OS" },
+   POPT_TABLEEND
+};
+
 enum modes {
     MODE_BUILD         = (1 <<  4),
     MODE_REBUILD       = (1 <<  5),
@@ -37,7 +262,7 @@ static struct poptOption optionsTable[] = {
        N_("Build options with [ <specfile> | <tarball> | <source package> ]:"),
        NULL },
 
- { "quiet", '\0', 0, &quiet, 0,                        NULL, NULL},
+ { "quiet", '\0', POPT_ARGFLAG_DOC_HIDDEN, &quiet, 0, NULL, NULL},
 
  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmcliAllPoptTable, 0,
        N_("Common options for all rpm modes and executables:"),
@@ -48,30 +273,17 @@ static struct poptOption optionsTable[] = {
    POPT_TABLEEND
 };
 
-static int checkSpec(rpmts ts, Header h)
+static int checkSpec(rpmts ts, rpmSpec spec)
 {
-    rpmps ps;
     int rc;
+    rpmps ps = rpmSpecCheckDeps(ts, spec);
 
-    if (!headerIsEntry(h, RPMTAG_REQUIRENAME)
-     && !headerIsEntry(h, RPMTAG_CONFLICTNAME))
-       return 0;
-
-    rc = rpmtsAddInstallElement(ts, h, NULL, 0, NULL);
-
-    rc = rpmtsCheck(ts);
-
-    ps = rpmtsProblems(ts);
-    if (rc == 0 && rpmpsNumProblems(ps) > 0) {
+    if (ps) {
        rpmlog(RPMLOG_ERR, _("Failed build dependencies:\n"));
        rpmpsPrint(NULL, ps);
-       rc = 1;
     }
-    ps = rpmpsFree(ps);
-
-    /* XXX nuke the added package. */
-    rpmtsClean(ts);
-
+    rc = (ps != NULL);
+    rpmpsFree(ps);
     return rc;
 }
 
@@ -84,7 +296,7 @@ static int isSpecFile(const char * specfile)
     int checking;
 
     f = fopen(specfile, "r");
-    if (f == NULL || ferror(f)) {
+    if (f == NULL) {
        rpmlog(RPMLOG_ERR, _("Unable to open spec file %s: %s\n"),
                specfile, strerror(errno));
        return 0;
@@ -128,7 +340,7 @@ static char * getTarSpec(const char *arg)
     char *specDir;
     char *specBase;
     char *tmpSpecFile;
-    const char **try;
+    const char **spec;
     char tarbuf[BUFSIZ];
     int gotspec = 0, res;
     static const char *tryspec[] = { "Specfile", "\\*.spec", NULL };
@@ -138,12 +350,13 @@ static char * getTarSpec(const char *arg)
 
     (void) close(mkstemp(tmpSpecFile));
 
-    for (try = tryspec; *try != NULL; try++) {
+    for (spec = tryspec; *spec != NULL; spec++) {
        FILE *fp;
        char *cmd;
+       int specfiles = 0;
 
        cmd = rpmExpand("%{uncompress: ", arg, "} | ",
-                       "%{__tar} xOvf - --wildcards ", *try,
+                       "%{__tar} xOvof - --wildcards ", *spec,
                        " 2>&1 > ", tmpSpecFile, NULL);
 
        if (!(fp = popen(cmd, "r"))) {
@@ -152,12 +365,19 @@ static char * getTarSpec(const char *arg)
            char *fok;
            for (;;) {
                fok = fgets(tarbuf, sizeof(tarbuf) - 1, fp);
+               if (!fok) break;
                /* tar sometimes prints "tar: Record size = 16" messages */
-               if (!fok || strncmp(fok, "tar: ", 5) != 0)
-                   break;
+               if (strstr(fok, "tar: ")) {
+                   continue;
+               }
+               specfiles++;
            }
            pclose(fp);
-           gotspec = (fok != NULL) && isSpecFile(tmpSpecFile);
+           gotspec = (specfiles == 1) && isSpecFile(tmpSpecFile);
+           if (specfiles > 1) {
+               rpmlog(RPMLOG_ERR, _("Found more than one spec file in %s\n"), arg);
+               goto exit;
+           }
        }
 
        if (!gotspec) 
@@ -198,17 +418,20 @@ exit:
 
 static int buildForTarget(rpmts ts, const char * arg, BTA_t ba)
 {
-    const char * passPhrase = ba->passPhrase;
-    const char * cookie = ba->cookie;
     int buildAmount = ba->buildAmount;
     char * buildRootURL = NULL;
     char * specFile = NULL;
     rpmSpec spec = NULL;
     int rc = 1; /* assume failure */
+    int justRm = ((buildAmount & ~(RPMBUILD_RMSOURCE|RPMBUILD_RMSPEC)) == 0);
+    rpmSpecFlags specFlags = spec_flags;
 
-#ifndef        DYING
-    rpmSetTables(RPM_MACHTABLE_BUILDARCH, RPM_MACHTABLE_BUILDOS);
-#endif
+    /* Override default BUILD value for _builddir */
+    if (buildInPlace) {
+       char *cwd = rpmGetCwd();
+       rpmPushMacro(NULL, "_builddir", NULL, cwd, 0);
+       free(cwd);
+    }
 
     if (ba->buildRootOverride)
        buildRootURL = rpmGenPath(NULL, ba->buildRootOverride, NULL);
@@ -220,7 +443,7 @@ static int buildForTarget(rpmts ts, const char * arg, BTA_t ba)
        goto exit;
     }
 
-    if (ba->buildMode == 't') {
+    if (buildMode == 't') {
        char *srcdir = NULL, *dir;
 
        specFile = getTarSpec(arg);
@@ -236,7 +459,7 @@ static int buildForTarget(rpmts ts, const char * arg, BTA_t ba)
            dir = xstrdup(arg);
        }
        srcdir = dirname(dir);
-       addMacro(NULL, "_sourcedir", NULL, srcdir, RMIL_TARBALL);
+       rpmPushMacro(NULL, "_sourcedir", NULL, srcdir, RMIL_TARBALL);
        free(dir);
     } else {
        specFile = xstrdup(arg);
@@ -245,7 +468,7 @@ static int buildForTarget(rpmts ts, const char * arg, BTA_t ba)
     if (*specFile != '/') {
        char *cwd = rpmGetCwd();
        char *s = NULL;
-       rasprintf(&s, "%s/%s", cwd, arg);
+       rasprintf(&s, "%s/%s", cwd, specFile);
        free(cwd);
        free(specFile);
        specFile = s;
@@ -277,65 +500,53 @@ static int buildForTarget(rpmts ts, const char * arg, BTA_t ba)
     /* Parse the spec file */
 #define        _anyarch(_f)    \
 (((_f)&(RPMBUILD_PREP|RPMBUILD_BUILD|RPMBUILD_INSTALL|RPMBUILD_PACKAGEBINARY)) == 0)
-    if (parseSpec(ts, specFile, ba->rootdir, buildRootURL, 0, passPhrase,
-               cookie, _anyarch(buildAmount), ba->force))
-    {
-       goto exit;
-    }
+    if (_anyarch(buildAmount))
+       specFlags |= RPMSPEC_ANYARCH;
 #undef _anyarch
-    if ((spec = rpmtsSetSpec(ts, NULL)) == NULL) {
-       goto exit;
-    }
-
-    if ( ba->buildAmount&RPMBUILD_RMSOURCE && !(ba->buildAmount&~(RPMBUILD_RMSOURCE|RPMBUILD_RMSPEC)) ) {
-       rc = doRmSource(spec);
-       if ( rc == RPMRC_OK && ba->buildAmount&RPMBUILD_RMSPEC )
-           rc = unlink(specFile);
+    
+    spec = rpmSpecParse(specFile, specFlags, buildRootURL);
+    if (spec == NULL) {
        goto exit;
     }
 
-    /* Assemble source header from parsed components */
-    initSourceHeader(spec);
-
-    /* Check build prerequisites */
-    if (!ba->noDeps && checkSpec(ts, spec->sourceHeader)) {
+    /* Check build prerequisites if necessary, unless disabled */
+    if (!justRm && !noDeps && checkSpec(ts, spec)) {
        goto exit;
     }
 
-    if (buildSpec(ts, spec, buildAmount, ba->noBuild)) {
+    if (rpmSpecBuild(spec, ba)) {
        goto exit;
     }
     
-    if (ba->buildMode == 't')
+    if (buildMode == 't')
        (void) unlink(specFile);
     rc = 0;
 
 exit:
     free(specFile);
-    freeSpec(spec);
+    rpmSpecFree(spec);
     free(buildRootURL);
     return rc;
 }
 
 static int build(rpmts ts, const char * arg, BTA_t ba, const char * rcfile)
 {
-    char *t, *te;
     int rc = 0;
-    char * targets = ba->targets;
+    char * targets = argvJoin(build_targets, ",");
 #define        buildCleanMask  (RPMBUILD_RMSOURCE|RPMBUILD_RMSPEC)
     int cleanFlags = ba->buildAmount & buildCleanMask;
     rpmVSFlags vsflags, ovsflags;
 
     vsflags = rpmExpandNumeric("%{_vsflags_build}");
-    if (ba->qva_flags & VERIFY_DIGEST)
+    if (rpmcliQueryFlags & VERIFY_DIGEST)
        vsflags |= _RPMVSF_NODIGESTS;
-    if (ba->qva_flags & VERIFY_SIGNATURE)
+    if (rpmcliQueryFlags & VERIFY_SIGNATURE)
        vsflags |= _RPMVSF_NOSIGNATURES;
-    if (ba->qva_flags & VERIFY_HDRCHK)
+    if (rpmcliQueryFlags & VERIFY_HDRCHK)
        vsflags |= RPMVSF_NOHDRCHK;
     ovsflags = rpmtsSetVSFlags(ts, vsflags);
 
-    if (targets == NULL) {
+    if (build_targets == NULL) {
        rc =  buildForTarget(ts, arg, ba);
        goto exit;
     }
@@ -345,36 +556,33 @@ static int build(rpmts ts, const char * arg, BTA_t ba, const char * rcfile)
     printf(_("Building target platforms: %s\n"), targets);
 
     ba->buildAmount &= ~buildCleanMask;
-    for (t = targets; *t != '\0'; t = te) {
-       char *target;
-       if ((te = strchr(t, ',')) == NULL)
-           te = t + strlen(t);
-       target = xmalloc(te-t+1);
-       strncpy(target, t, (te-t));
-       target[te-t] = '\0';
-       if (*te != '\0')
-           te++;
-       else    /* XXX Perform clean-up after last target build. */
+    for (ARGV_const_t target = build_targets; target && *target; target++) {
+       /* Perform clean-up after last target build. */
+       if (*(target + 1) == NULL)
            ba->buildAmount |= cleanFlags;
 
-       printf(_("Building for target %s\n"), target);
+       printf(_("Building for target %s\n"), *target);
 
        /* Read in configuration for target. */
        rpmFreeMacros(NULL);
+       if (buildInPlace) {
+               /* Need to redefine this after freeing all the macros */
+               rpmDefineMacro(NULL, "_build_in_place 1", 0);
+       }
        rpmFreeRpmrc();
-       (void) rpmReadConfigFiles(rcfile, target);
-       free(target);
+       (void) rpmReadConfigFiles(rcfile, *target);
        rc = buildForTarget(ts, arg, ba);
        if (rc)
            break;
     }
 
 exit:
-    vsflags = rpmtsSetVSFlags(ts, ovsflags);
+    rpmtsSetVSFlags(ts, ovsflags);
     /* Restore original configuration. */
     rpmFreeMacros(NULL);
     rpmFreeRpmrc();
     (void) rpmReadConfigFiles(rcfile, NULL);
+    free(targets);
 
     return rc;
 }
@@ -384,31 +592,23 @@ int main(int argc, char *argv[])
     rpmts ts = NULL;
     enum modes bigMode = MODE_BUILD;
     BTA_t ba = &rpmBTArgs;
-    char * passPhrase = "";
 
     const char *pkg = NULL;
-    pid_t pipeChild = 0;
-    poptContext optCon;
     int ec = 0;
-    int status;
-    int p[2];
-       
-    setprogname(argv[0]);      /* Retrofit glibc __progname */
 
-    /* XXX glibc churn sanity */
-    if (__progname == NULL) {
-       if ((__progname = strrchr(argv[0], '/')) != NULL) __progname++;
-       else __progname = argv[0];
-    }
+    poptContext optCon = NULL;
+
+    xsetprogname(argv[0]); /* Portability call -- see system.h */
 
-    optCon = initCli("rpmbuild", optionsTable, argc, argv);
+    optCon = rpmcliInit(argc, argv, optionsTable);
 
-    if (argc <= 1 || poptPeekArg(optCon) == NULL) {
+    /* Args required only when building, let lone --eval etc through */
+    if (ba->buildAmount && poptPeekArg(optCon) == NULL) {
        printUsage(optCon, stderr, 0);
        exit(EXIT_FAILURE);
     }
 
-    switch (ba->buildMode) {
+    switch (buildMode) {
     case 'b':  bigMode = MODE_BUILD;           break;
     case 't':  bigMode = MODE_TARBUILD;        break;
     case 'B':  bigMode = MODE_REBUILD;         break;
@@ -419,72 +619,62 @@ int main(int argc, char *argv[])
        argerror(_("arguments to --root (-r) must begin with a /"));
     }
 
-    if (ba->sign) {
-       int sigTag = rpmLookupSignatureType(RPMLOOKUPSIG_QUERY);
-       switch (sigTag) {
-       case 0:
-           break;
-       case RPMSIGTAG_PGP:
-       case RPMSIGTAG_GPG:
-       case RPMSIGTAG_DSA:
-       case RPMSIGTAG_RSA:
-           passPhrase = rpmGetPassPhrase(_("Enter pass phrase: "), sigTag);
-           if (passPhrase == NULL) {
-               fprintf(stderr, _("Pass phrase check failed\n"));
-               ec = EXIT_FAILURE;
-               goto exit;
-           }
-           fprintf(stderr, _("Pass phrase is good.\n"));
-           passPhrase = xstrdup(passPhrase);
-           break;
-       default:
-           fprintf(stderr, _("Invalid %%_signature spec in macro file.\n"));
-           ec = EXIT_FAILURE;
-           goto exit;
-           break;
-       }
-    } else {
-       /* Make rpmLookupSignatureType() return 0 ("none") from now on */
-        (void) rpmLookupSignatureType(RPMLOOKUPSIG_DISABLE);
-    }
-
-    /* rpmbuild is rather chatty by default */
-    rpmSetVerbosity(quiet ? RPMLOG_WARNING : RPMLOG_INFO);
-
-    if (rpmcliPipeOutput) {
-       if (pipe(p) < 0) {
-           fprintf(stderr, _("creating a pipe for --pipe failed: %m\n"));
-           goto exit;
-       }
+    /* rpmbuild runs in verbose mode by default */
+    if (rpmlogSetMask(0) < RPMLOG_MASK(RPMLOG_INFO))
+       rpmSetVerbosity(RPMLOG_INFO);
 
-       if (!(pipeChild = fork())) {
-           (void) signal(SIGPIPE, SIG_DFL);
-           (void) close(p[1]);
-           (void) dup2(p[0], STDIN_FILENO);
-           (void) close(p[0]);
-           (void) execl("/bin/sh", "/bin/sh", "-c", rpmcliPipeOutput, NULL);
-           fprintf(stderr, _("exec failed\n"));
-       }
+    if (quiet)
+       rpmSetVerbosity(RPMLOG_WARNING);
 
-       (void) close(p[0]);
-       (void) dup2(p[1], STDOUT_FILENO);
-       (void) close(p[1]);
-    }
+    if (rpmcliPipeOutput && initPipe())
+       exit(EXIT_FAILURE);
        
     ts = rpmtsCreate();
     (void) rpmtsSetRootDir(ts, rpmcliRootDir);
+    rpmtsSetFlags(ts, rpmtsFlags(ts) | RPMTRANS_FLAG_NOPLUGINS);
+
+    switch (buildChar) {
+    case 'a':
+       ba->buildAmount |= RPMBUILD_PACKAGESOURCE;
+    case 'b':
+       ba->buildAmount |= RPMBUILD_PACKAGEBINARY;
+       ba->buildAmount |= RPMBUILD_CLEAN;
+       if ((buildChar == 'b') && shortCircuit)
+           break;
+    case 'i':
+       ba->buildAmount |= RPMBUILD_INSTALL;
+       ba->buildAmount |= RPMBUILD_CHECK;
+       if ((buildChar == 'i') && shortCircuit)
+           break;
+    case 'c':
+       ba->buildAmount |= RPMBUILD_BUILD;
+       if ((buildChar == 'c') && shortCircuit)
+           break;
+    case 'p':
+       ba->buildAmount |= RPMBUILD_PREP;
+       break;
+    case 'l':
+       ba->buildAmount |= RPMBUILD_FILECHECK;
+       break;
+    case 's':
+       ba->buildAmount |= RPMBUILD_PACKAGESOURCE;
+       break;
+    }
+    ba->buildAmount &= ~(nobuildAmount);
+
     switch (bigMode) {
     case MODE_REBUILD:
     case MODE_RECOMPILE:
-       ba->buildAmount =
-           RPMBUILD_PREP | RPMBUILD_BUILD | RPMBUILD_INSTALL | RPMBUILD_CHECK;
-       if (bigMode == MODE_REBUILD) {
-           ba->buildAmount |= RPMBUILD_PACKAGEBINARY;
+       if (bigMode == MODE_REBUILD &&
+           buildChar != 'p' &&
+           buildChar != 'c' &&
+           buildChar != 'i' &&
+           buildChar != 'l') {
            ba->buildAmount |= RPMBUILD_RMSOURCE;
            ba->buildAmount |= RPMBUILD_RMSPEC;
-           ba->buildAmount |= RPMBUILD_CLEAN;
            ba->buildAmount |= RPMBUILD_RMBUILD;
        }
+       ba->buildAmount &= ~(nobuildAmount);
 
        while ((pkg = poptGetArg(optCon))) {
            char * specFile = NULL;
@@ -493,7 +683,6 @@ int main(int argc, char *argv[])
            ec = rpmInstallSource(ts, pkg, &specFile, &ba->cookie);
            if (ec == 0) {
                ba->rootdir = rpmcliRootDir;
-               ba->passPhrase = passPhrase;
                ec = build(ts, specFile, ba, rpmcliRcfile);
            }
            ba->cookie = _free(ba->cookie);
@@ -505,38 +694,9 @@ int main(int argc, char *argv[])
        break;
     case MODE_BUILD:
     case MODE_TARBUILD:
-       switch (ba->buildChar) {
-       case 'a':
-           ba->buildAmount |= RPMBUILD_PACKAGESOURCE;
-       case 'b':
-           ba->buildAmount |= RPMBUILD_PACKAGEBINARY;
-           ba->buildAmount |= RPMBUILD_CLEAN;
-           if ((ba->buildChar == 'b') && ba->shortCircuit)
-               break;
-       case 'i':
-           ba->buildAmount |= RPMBUILD_INSTALL;
-           ba->buildAmount |= RPMBUILD_CHECK;
-           if ((ba->buildChar == 'i') && ba->shortCircuit)
-               break;
-       case 'c':
-           ba->buildAmount |= RPMBUILD_BUILD;
-           if ((ba->buildChar == 'c') && ba->shortCircuit)
-               break;
-       case 'p':
-           ba->buildAmount |= RPMBUILD_PREP;
-           break;
-           
-       case 'l':
-           ba->buildAmount |= RPMBUILD_FILECHECK;
-           break;
-       case 's':
-           ba->buildAmount |= RPMBUILD_PACKAGESOURCE;
-           break;
-       }
 
        while ((pkg = poptGetArg(optCon))) {
            ba->rootdir = rpmcliRootDir;
-           ba->passPhrase = passPhrase;
            ba->cookie = NULL;
            ec = build(ts, pkg, ba, rpmcliRcfile);
            if (ec)
@@ -547,18 +707,13 @@ int main(int argc, char *argv[])
        break;
     }
 
-exit:
-
-    ts = rpmtsFree(ts);
-
-    if (pipeChild) {
-       (void) fclose(stdout);
-       (void) waitpid(pipeChild, &status, 0);
-    }
+    rpmtsFree(ts);
+    if (finishPipe())
+       ec = EXIT_FAILURE;
+    free(ba->buildRootOverride);
+    argvFree(build_targets);
 
-    freeNames();
-    ba->buildRootOverride = _free(ba->buildRootOverride);
-    ba->targets = _free(ba->targets);
+    rpmcliFini(optCon);
 
-    return finishCli(optCon, ec);
+    return RETVAL(ec);
 }