- don't use error string after gzclose (Dmitry V. Levin).
[platform/upstream/rpm.git] / rpmqv.c
1 #include "system.h"
2
3 #define _AUTOHELP
4
5 #if defined(IAM_RPM) || defined(__LCLINT__)
6 #define IAM_RPMBT
7 #define IAM_RPMDB
8 #define IAM_RPMEIU
9 #define IAM_RPMQV
10 #define IAM_RPMK
11 #endif
12
13 #include <rpmcli.h>
14 #include <rpmbuild.h>
15
16 #include "rpmdb.h"
17 #include "rpmps.h"
18 #include "rpmts.h"
19
20 #ifdef  IAM_RPMBT
21 #include "build.h"
22 #define GETOPT_REBUILD          1003
23 #define GETOPT_RECOMPILE        1004
24 #endif
25
26 #if defined(IAM_RPMBT) || defined(IAM_RPMK)
27 #include "signature.h"
28 #endif
29
30 #include "debug.h"
31
32 enum modes {
33
34     MODE_QUERY          = (1 <<  0),
35     MODE_VERIFY         = (1 <<  3),
36 #define MODES_QV (MODE_QUERY | MODE_VERIFY)
37
38     MODE_INSTALL        = (1 <<  1),
39     MODE_ERASE          = (1 <<  2),
40 #define MODES_IE (MODE_INSTALL | MODE_ERASE)
41
42     MODE_BUILD          = (1 <<  4),
43     MODE_REBUILD        = (1 <<  5),
44     MODE_RECOMPILE      = (1 <<  8),
45     MODE_TARBUILD       = (1 << 11),
46 #define MODES_BT (MODE_BUILD | MODE_TARBUILD | MODE_REBUILD | MODE_RECOMPILE)
47
48     MODE_CHECKSIG       = (1 <<  6),
49     MODE_RESIGN         = (1 <<  7),
50 #define MODES_K  (MODE_CHECKSIG | MODE_RESIGN)
51
52     MODE_INITDB         = (1 << 10),
53     MODE_REBUILDDB      = (1 << 12),
54     MODE_VERIFYDB       = (1 << 13),
55 #define MODES_DB (MODE_INITDB | MODE_REBUILDDB | MODE_VERIFYDB)
56
57
58     MODE_UNKNOWN        = 0
59 };
60
61 #define MODES_FOR_DBPATH        (MODES_BT | MODES_IE | MODES_QV | MODES_DB)
62 #define MODES_FOR_NODEPS        (MODES_BT | MODES_IE | MODE_VERIFY)
63 #define MODES_FOR_TEST          (MODES_BT | MODES_IE)
64 #define MODES_FOR_ROOT          (MODES_BT | MODES_IE | MODES_QV | MODES_DB | MODES_K)
65
66 /* the structure describing the options we take and the defaults */
67 /*@unchecked@*/
68 static struct poptOption optionsTable[] = {
69
70 #ifdef  IAM_RPMQV
71  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmQueryPoptTable, 0,
72         N_("Query options (with -q or --query):"),
73         NULL },
74  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmVerifyPoptTable, 0,
75         N_("Verify options (with -V or --verify):"),
76         NULL },
77 #endif  /* IAM_RPMQV */
78
79 #ifdef  IAM_RPMK
80  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmSignPoptTable, 0,
81         N_("Signature options:"),
82         NULL },
83 #endif  /* IAM_RPMK */
84
85 #ifdef  IAM_RPMDB
86  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmDatabasePoptTable, 0,
87         N_("Database options:"),
88         NULL },
89 #endif  /* IAM_RPMDB */
90
91 #ifdef  IAM_RPMBT
92  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmBuildPoptTable, 0,
93         N_("Build options with [ <specfile> | <tarball> | <source package> ]:"),
94         NULL },
95 #endif  /* IAM_RPMBT */
96
97 #ifdef  IAM_RPMEIU
98  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmInstallPoptTable, 0,
99         N_("Install/Upgrade/Erase options:"),
100         NULL },
101 #endif  /* IAM_RPMEIU */
102
103  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmcliAllPoptTable, 0,
104         N_("Common options for all rpm modes:"),
105         NULL },
106
107    POPT_AUTOALIAS
108    POPT_AUTOHELP
109    POPT_TABLEEND
110 };
111
112 #ifdef __MINT__
113 /* MiNT cannot dynamically increase the stack.  */
114 long _stksize = 64 * 1024L;
115 #endif
116
117 /*@exits@*/ static void argerror(const char * desc)
118         /*@globals __assert_program_name, fileSystem @*/
119         /*@modifies fileSystem @*/
120 {
121     fprintf(stderr, _("%s: %s\n"), __progname, desc);
122     exit(EXIT_FAILURE);
123 }
124
125 static void printVersion(FILE * fp)
126         /*@globals rpmEVR, fileSystem @*/
127         /*@modifies *fp, fileSystem @*/
128 {
129     fprintf(fp, _("RPM version %s\n"), rpmEVR);
130 }
131
132 static void printBanner(FILE * fp)
133         /*@globals fileSystem @*/
134         /*@modifies *fp, fileSystem @*/
135 {
136     fprintf(fp, _("Copyright (C) 1998-2002 - Red Hat, Inc.\n"));
137     fprintf(fp, _("This program may be freely redistributed under the terms of the GNU GPL\n"));
138 }
139
140 static void printUsage(poptContext con, FILE * fp, int flags)
141         /*@globals rpmEVR, fileSystem, internalState @*/
142         /*@modifies *fp, fileSystem, internalState @*/
143 {
144     printVersion(fp);
145     printBanner(fp);
146     fprintf(fp, "\n");
147
148     if (rpmIsVerbose())
149         poptPrintHelp(con, fp, flags);
150     else
151         poptPrintUsage(con, fp, flags);
152 }
153
154 /*@-bounds@*/ /* LCL: segfault */
155 /*@-mods@*/ /* FIX: shrug */
156 #if !defined(__GLIBC__) && !defined(__LCLINT__)
157 int main(int argc, const char ** argv, /*@unused@*/ char ** envp)
158 #else
159 int main(int argc, const char ** argv)
160 #endif
161         /*@globals __assert_program_name, rpmEVR, RPMVERSION,
162                 rpmGlobalMacroContext, rpmCLIMacroContext,
163                 h_errno, fileSystem, internalState@*/
164         /*@modifies __assert_program_name,
165                 fileSystem, internalState@*/
166 {
167     rpmts ts = NULL;
168     enum modes bigMode = MODE_UNKNOWN;
169
170 #if defined(IAM_RPMQV)
171     QVA_t qva = &rpmQVKArgs;
172 #endif
173
174 #ifdef  IAM_RPMBT
175     BTA_t ba = &rpmBTArgs;
176 #endif
177
178 #ifdef  IAM_RPMEIU
179    struct rpmInstallArguments_s * ia = &rpmIArgs;
180 #endif
181
182 #if defined(IAM_RPMDB)
183    struct rpmDatabaseArguments_s * da = &rpmDBArgs;
184 #endif
185
186 #if defined(IAM_RPMK)
187    QVA_t ka = &rpmQVKArgs;
188 #endif
189
190 #if defined(IAM_RPMBT) || defined(IAM_RPMK)
191     char * passPhrase = "";
192 #endif
193
194     int arg;
195
196     const char * optArg;
197     pid_t pipeChild = 0;
198     poptContext optCon;
199     int ec = 0;
200     int status;
201     int p[2];
202 #ifdef  IAM_RPMEIU
203     int i;
204 #endif
205         
206 #if HAVE_MCHECK_H && HAVE_MTRACE
207     /*@-noeffect@*/
208     mtrace();   /* Trace malloc only if MALLOC_TRACE=mtrace-output-file. */
209     /*@=noeffect@*/
210 #endif
211     setprogname(argv[0]);       /* Retrofit glibc __progname */
212
213 #if !defined(__GLIBC__) && !defined(__LCLINT__)
214     environ = envp;
215 #endif  
216
217     /* XXX glibc churn sanity */
218     if (__progname == NULL) {
219         if ((__progname = strrchr(argv[0], '/')) != NULL) __progname++;
220         else __progname = argv[0];
221     }
222
223     /* Set the major mode based on argv[0] */
224     /*@-nullpass@*/
225 #ifdef  IAM_RPMBT
226     if (!strcmp(__progname, "rpmb"))    bigMode = MODE_BUILD;
227     if (!strcmp(__progname, "lt-rpmb")) bigMode = MODE_BUILD;
228     if (!strcmp(__progname, "rpmt"))    bigMode = MODE_TARBUILD;
229     if (!strcmp(__progname, "rpmbuild"))        bigMode = MODE_BUILD;
230 #endif
231 #ifdef  IAM_RPMQV
232     if (!strcmp(__progname, "rpmq"))    bigMode = MODE_QUERY;
233     if (!strcmp(__progname, "lt-rpmq")) bigMode = MODE_QUERY;
234     if (!strcmp(__progname, "rpmv"))    bigMode = MODE_VERIFY;
235     if (!strcmp(__progname, "rpmquery"))        bigMode = MODE_QUERY;
236     if (!strcmp(__progname, "rpmverify"))       bigMode = MODE_VERIFY;
237 #endif
238 #ifdef  RPMEIU
239     if (!strcmp(__progname, "rpme"))    bigMode = MODE_ERASE;
240     if (!strcmp(__progname, "rpmi"))    bigMode = MODE_INSTALL;
241     if (!strcmp(__progname, "lt-rpmi")) bigMode = MODE_INSTALL;
242     if (!strcmp(__progname, "rpmu"))    bigMode = MODE_INSTALL;
243 #endif
244     /*@=nullpass@*/
245
246 #if defined(IAM_RPMQV)
247     /* Jumpstart option from argv[0] if necessary. */
248     switch (bigMode) {
249     case MODE_QUERY:    qva->qva_mode = 'q';    break;
250     case MODE_VERIFY:   qva->qva_mode = 'V';    break;
251     case MODE_CHECKSIG: qva->qva_mode = 'K';    break;
252     case MODE_RESIGN:   qva->qva_mode = 'R';    break;
253     case MODE_INSTALL:
254     case MODE_ERASE:
255     case MODE_BUILD:
256     case MODE_REBUILD:
257     case MODE_RECOMPILE:
258     case MODE_TARBUILD:
259     case MODE_INITDB:
260     case MODE_REBUILDDB:
261     case MODE_VERIFYDB:
262     case MODE_UNKNOWN:
263     default:
264         break;
265     }
266 #endif
267
268 #if defined(ENABLE_NLS)
269     /* set up the correct locale */
270     (void) setlocale(LC_ALL, "" );
271
272 #ifdef  __LCLINT__
273 #define LOCALEDIR       "/usr/share/locale"
274 #endif
275     bindtextdomain(PACKAGE, LOCALEDIR);
276     textdomain(PACKAGE);
277 #endif
278
279     rpmSetVerbosity(RPMMESS_NORMAL);    /* XXX silly use by showrc */
280
281     /* Make a first pass through the arguments, looking for --rcfile */
282     /* We need to handle that before dealing with the rest of the arguments. */
283     /*@-nullpass -temptrans@*/
284     optCon = poptGetContext(__progname, argc, argv, optionsTable, 0);
285     /*@=nullpass =temptrans@*/
286     (void) poptReadConfigFile(optCon, LIBRPMALIAS_FILENAME);
287     (void) poptReadDefaultConfig(optCon, 1);
288     poptSetExecPath(optCon, RPMCONFIGDIR, 1);
289
290     while ((arg = poptGetNextOpt(optCon)) > 0) {
291         optArg = poptGetOptArg(optCon);
292
293         switch (arg) {
294         default:
295             fprintf(stderr, _("Internal error in argument processing (%d) :-(\n"), arg);
296             exit(EXIT_FAILURE);
297         }
298     }
299
300     if (arg < -1) {
301         fprintf(stderr, "%s: %s\n", 
302                 poptBadOption(optCon, POPT_BADOPTION_NOALIAS), 
303                 poptStrerror(arg));
304         exit(EXIT_FAILURE);
305     }
306
307     rpmcliConfigured();
308
309 #ifdef  IAM_RPMBT
310     switch (ba->buildMode) {
311     case 'b':   bigMode = MODE_BUILD;           break;
312     case 't':   bigMode = MODE_TARBUILD;        break;
313     case 'B':   bigMode = MODE_REBUILD;         break;
314     case 'C':   bigMode = MODE_RECOMPILE;       break;
315     }
316
317     if ((ba->buildAmount & RPMBUILD_RMSOURCE) && bigMode == MODE_UNKNOWN)
318         bigMode = MODE_BUILD;
319
320     if ((ba->buildAmount & RPMBUILD_RMSPEC) && bigMode == MODE_UNKNOWN)
321         bigMode = MODE_BUILD;
322
323     if (ba->buildRootOverride && bigMode != MODE_BUILD &&
324         bigMode != MODE_REBUILD && bigMode != MODE_TARBUILD) {
325         argerror("--buildroot may only be used during package builds");
326     }
327 #endif  /* IAM_RPMBT */
328     
329 #ifdef  IAM_RPMDB
330   if (bigMode == MODE_UNKNOWN || (bigMode & MODES_DB)) {
331     if (da->init) {
332         if (bigMode != MODE_UNKNOWN) 
333             argerror(_("only one major mode may be specified"));
334         else
335             bigMode = MODE_INITDB;
336     } else
337     if (da->rebuild) {
338         if (bigMode != MODE_UNKNOWN) 
339             argerror(_("only one major mode may be specified"));
340         else
341             bigMode = MODE_REBUILDDB;
342     } else
343     if (da->verify) {
344         if (bigMode != MODE_UNKNOWN) 
345             argerror(_("only one major mode may be specified"));
346         else
347             bigMode = MODE_VERIFYDB;
348     }
349   }
350 #endif  /* IAM_RPMDB */
351
352 #ifdef  IAM_RPMQV
353   if (bigMode == MODE_UNKNOWN || (bigMode & MODES_QV)) {
354     switch (qva->qva_mode) {
355     case 'q':   bigMode = MODE_QUERY;           break;
356     case 'V':   bigMode = MODE_VERIFY;          break;
357     }
358
359     if (qva->qva_sourceCount) {
360         if (qva->qva_sourceCount > 2)
361             argerror(_("one type of query/verify may be performed at a "
362                         "time"));
363     }
364     if (qva->qva_flags && (bigMode & ~MODES_QV)) 
365         argerror(_("unexpected query flags"));
366
367     if (qva->qva_queryFormat && (bigMode & ~MODES_QV)) 
368         argerror(_("unexpected query format"));
369
370     if (qva->qva_source != RPMQV_PACKAGE && (bigMode & ~MODES_QV)) 
371         argerror(_("unexpected query source"));
372   }
373 #endif  /* IAM_RPMQV */
374
375 #ifdef  IAM_RPMEIU
376   if (bigMode == MODE_UNKNOWN || (bigMode & MODES_IE))
377     {   int iflags = (ia->installInterfaceFlags &
378                 (INSTALL_UPGRADE|INSTALL_FRESHEN|INSTALL_INSTALL));
379         int eflags = (ia->installInterfaceFlags & INSTALL_ERASE);
380
381         if (iflags & eflags)
382             argerror(_("only one major mode may be specified"));
383         else if (iflags)
384             bigMode = MODE_INSTALL;
385         else if (eflags)
386             bigMode = MODE_ERASE;
387     }
388 #endif  /* IAM_RPMEIU */
389
390 #ifdef  IAM_RPMK
391   if (bigMode == MODE_UNKNOWN || (bigMode & MODES_K)) {
392         switch (ka->qva_mode) {
393         case RPMSIGN_NONE:
394             ka->sign = 0;
395             break;
396         case RPMSIGN_IMPORT_PUBKEY:
397         case RPMSIGN_CHK_SIGNATURE:
398             bigMode = MODE_CHECKSIG;
399             ka->sign = 0;
400             break;
401         case RPMSIGN_ADD_SIGNATURE:
402         case RPMSIGN_NEW_SIGNATURE:
403             bigMode = MODE_RESIGN;
404             ka->sign = 1;
405             break;
406         }
407   }
408 #endif  /* IAM_RPMK */
409
410 #if defined(IAM_RPMEIU)
411     if (!( bigMode == MODE_INSTALL ) &&
412 (ia->probFilter & (RPMPROB_FILTER_REPLACEPKG | RPMPROB_FILTER_REPLACEOLDFILES | RPMPROB_FILTER_REPLACENEWFILES | RPMPROB_FILTER_OLDPACKAGE)))
413         argerror(_("only installation, upgrading, rmsource and rmspec may be forced"));
414     if (bigMode != MODE_INSTALL && (ia->probFilter & RPMPROB_FILTER_FORCERELOCATE))
415         argerror(_("files may only be relocated during package installation"));
416
417     if (ia->relocations && ia->prefix)
418         argerror(_("cannot use --prefix with --relocate or --excludepath"));
419
420     if (bigMode != MODE_INSTALL && ia->relocations)
421         argerror(_("--relocate and --excludepath may only be used when installing new packages"));
422
423     if (bigMode != MODE_INSTALL && ia->prefix)
424         argerror(_("--prefix may only be used when installing new packages"));
425
426     if (ia->prefix && ia->prefix[0] != '/') 
427         argerror(_("arguments to --prefix must begin with a /"));
428
429     if (bigMode != MODE_INSTALL && (ia->installInterfaceFlags & INSTALL_HASH))
430         argerror(_("--hash (-h) may only be specified during package "
431                         "installation"));
432
433     if (bigMode != MODE_INSTALL && (ia->installInterfaceFlags & INSTALL_PERCENT))
434         argerror(_("--percent may only be specified during package "
435                         "installation"));
436
437     if (bigMode != MODE_INSTALL &&
438  (ia->probFilter & (RPMPROB_FILTER_REPLACEOLDFILES|RPMPROB_FILTER_REPLACENEWFILES)))
439         argerror(_("--replacefiles may only be specified during package "
440                         "installation"));
441
442     if (bigMode != MODE_INSTALL && (ia->probFilter & RPMPROB_FILTER_REPLACEPKG))
443         argerror(_("--replacepkgs may only be specified during package "
444                         "installation"));
445
446     if (bigMode != MODE_INSTALL && (ia->transFlags & RPMTRANS_FLAG_NODOCS))
447         argerror(_("--excludedocs may only be specified during package "
448                    "installation"));
449
450     if (bigMode != MODE_INSTALL && ia->incldocs)
451         argerror(_("--includedocs may only be specified during package "
452                    "installation"));
453
454     if (ia->incldocs && (ia->transFlags & RPMTRANS_FLAG_NODOCS))
455         argerror(_("only one of --excludedocs and --includedocs may be "
456                  "specified"));
457   
458     if (bigMode != MODE_INSTALL && (ia->probFilter & RPMPROB_FILTER_IGNOREARCH))
459         argerror(_("--ignorearch may only be specified during package "
460                    "installation"));
461
462     if (bigMode != MODE_INSTALL && (ia->probFilter & RPMPROB_FILTER_IGNOREOS))
463         argerror(_("--ignoreos may only be specified during package "
464                    "installation"));
465
466     if (bigMode != MODE_INSTALL &&
467         (ia->probFilter & (RPMPROB_FILTER_DISKSPACE|RPMPROB_FILTER_DISKNODES)))
468         argerror(_("--ignoresize may only be specified during package "
469                    "installation"));
470
471     if ((ia->eraseInterfaceFlags & UNINSTALL_ALLMATCHES) && bigMode != MODE_ERASE)
472         argerror(_("--allmatches may only be specified during package "
473                    "erasure"));
474
475     if ((ia->transFlags & RPMTRANS_FLAG_ALLFILES) && bigMode != MODE_INSTALL)
476         argerror(_("--allfiles may only be specified during package "
477                    "installation"));
478
479     if ((ia->transFlags & RPMTRANS_FLAG_JUSTDB) &&
480         bigMode != MODE_INSTALL && bigMode != MODE_ERASE)
481         argerror(_("--justdb may only be specified during package "
482                    "installation and erasure"));
483
484     if (bigMode != MODE_INSTALL && bigMode != MODE_ERASE &&
485         (ia->transFlags & (RPMTRANS_FLAG_NOSCRIPTS | _noTransScripts | _noTransTriggers)))
486         argerror(_("script disabling options may only be specified during "
487                    "package installation and erasure"));
488
489     if (bigMode != MODE_INSTALL && bigMode != MODE_ERASE &&
490         (ia->transFlags & (RPMTRANS_FLAG_NOTRIGGERS | _noTransTriggers)))
491         argerror(_("trigger disabling options may only be specified during "
492                    "package installation and erasure"));
493
494     if (ia->noDeps & (bigMode & ~MODES_FOR_NODEPS))
495         argerror(_("--nodeps may only be specified during package "
496                    "building, rebuilding, recompilation, installation,"
497                    "erasure, and verification"));
498
499     if ((ia->transFlags & RPMTRANS_FLAG_TEST) && (bigMode & ~MODES_FOR_TEST))
500         argerror(_("--test may only be specified during package installation, "
501                  "erasure, and building"));
502 #endif  /* IAM_RPMEIU */
503
504     if (rpmcliRootDir && rpmcliRootDir[1] && (bigMode & ~MODES_FOR_ROOT))
505         argerror(_("--root (-r) may only be specified during "
506                  "installation, erasure, querying, and "
507                  "database rebuilds"));
508
509     if (rpmcliRootDir) {
510         switch (urlIsURL(rpmcliRootDir)) {
511         default:
512             if (bigMode & MODES_FOR_ROOT)
513                 break;
514             /*@fallthrough@*/
515         case URL_IS_UNKNOWN:
516             if (rpmcliRootDir[0] != '/')
517                 argerror(_("arguments to --root (-r) must begin with a /"));
518             break;
519         }
520     }
521
522 #if defined(IAM_RPMBT) || defined(IAM_RPMK)
523     if (0
524 #if defined(IAM_RPMBT)
525     || ba->sign 
526 #endif
527 #if defined(IAM_RPMK)
528     || ka->sign
529 #endif
530     )
531     /*@-branchstate@*/
532     {
533         if (bigMode == MODE_REBUILD || bigMode == MODE_BUILD ||
534             bigMode == MODE_RESIGN || bigMode == MODE_TARBUILD)
535         {
536             const char ** av;
537             struct stat sb;
538             int errors = 0;
539
540             if ((av = poptGetArgs(optCon)) == NULL) {
541                 fprintf(stderr, _("no files to sign\n"));
542                 errors++;
543             } else
544             while (*av) {
545                 if (stat(*av, &sb)) {
546                     fprintf(stderr, _("cannot access file %s\n"), *av);
547                     errors++;
548                 }
549                 av++;
550             }
551
552             if (errors) {
553                 ec = errors;
554                 goto exit;
555             }
556
557             if (poptPeekArg(optCon)) {
558                 int sigTag;
559                 switch (sigTag = rpmLookupSignatureType(RPMLOOKUPSIG_QUERY)) {
560                   case 0:
561                     break;
562                   case RPMSIGTAG_PGP:
563                     if ((sigTag == RPMSIGTAG_PGP || sigTag == RPMSIGTAG_PGP5) &&
564                         !rpmDetectPGPVersion(NULL)) {
565                         fprintf(stderr, _("pgp not found: "));
566                         ec = EXIT_FAILURE;
567                         goto exit;
568                     }   /*@fallthrough@*/
569                   case RPMSIGTAG_GPG:
570                     passPhrase = rpmGetPassPhrase(_("Enter pass phrase: "), sigTag);
571                     if (passPhrase == NULL) {
572                         fprintf(stderr, _("Pass phrase check failed\n"));
573                         ec = EXIT_FAILURE;
574                         goto exit;
575                     }
576                     fprintf(stderr, _("Pass phrase is good.\n"));
577                     passPhrase = xstrdup(passPhrase);
578                     break;
579                   default:
580                     fprintf(stderr,
581                             _("Invalid %%_signature spec in macro file.\n"));
582                     ec = EXIT_FAILURE;
583                     goto exit;
584                     /*@notreached@*/ break;
585                 }
586             }
587         } else {
588             argerror(_("--sign may only be used during package building"));
589         }
590     } else {
591         /* Make rpmLookupSignatureType() return 0 ("none") from now on */
592         (void) rpmLookupSignatureType(RPMLOOKUPSIG_DISABLE);
593     }
594     /*@=branchstate@*/
595 #endif  /* IAM_RPMBT || IAM_RPMK */
596
597     if (rpmcliPipeOutput) {
598         (void) pipe(p);
599
600         if (!(pipeChild = fork())) {
601             (void) close(p[1]);
602             (void) dup2(p[0], STDIN_FILENO);
603             (void) close(p[0]);
604             (void) execl("/bin/sh", "/bin/sh", "-c", rpmcliPipeOutput, NULL);
605             fprintf(stderr, _("exec failed\n"));
606         }
607
608         (void) close(p[0]);
609         (void) dup2(p[1], STDOUT_FILENO);
610         (void) close(p[1]);
611     }
612         
613     ts = rpmtsCreate();
614     (void) rpmtsSetRootDir(ts, rpmcliRootDir);
615     switch (bigMode) {
616 #ifdef  IAM_RPMDB
617     case MODE_INITDB:
618         (void) rpmtsInitDB(ts, 0644);
619         break;
620
621     case MODE_REBUILDDB:
622     {   rpmVSFlags vsflags = rpmExpandNumeric("%{_vsflags_rebuilddb}");
623         rpmVSFlags ovsflags = rpmtsSetVSFlags(ts, vsflags);
624         ec = rpmtsRebuildDB(ts);
625         vsflags = rpmtsSetVSFlags(ts, ovsflags);
626     }   break;
627     case MODE_VERIFYDB:
628         ec = rpmtsVerifyDB(ts);
629         break;
630 #endif  /* IAM_RPMDB */
631
632 #ifdef  IAM_RPMBT
633     case MODE_REBUILD:
634     case MODE_RECOMPILE:
635     {   const char * pkg;
636
637         while (!rpmIsVerbose())
638             rpmIncreaseVerbosity();
639
640         if (!poptPeekArg(optCon))
641             argerror(_("no packages files given for rebuild"));
642
643         ba->buildAmount =
644             RPMBUILD_PREP | RPMBUILD_BUILD | RPMBUILD_INSTALL | RPMBUILD_CHECK;
645         if (bigMode == MODE_REBUILD) {
646             ba->buildAmount |= RPMBUILD_PACKAGEBINARY;
647             ba->buildAmount |= RPMBUILD_RMSOURCE;
648             ba->buildAmount |= RPMBUILD_RMSPEC;
649             ba->buildAmount |= RPMBUILD_CLEAN;
650             ba->buildAmount |= RPMBUILD_RMBUILD;
651         }
652
653         while ((pkg = poptGetArg(optCon))) {
654             const char * specFile = NULL;
655
656             ba->cookie = NULL;
657             ec = rpmInstallSource(ts, pkg, &specFile, &ba->cookie);
658             if (ec == 0) {
659                 ba->rootdir = rpmcliRootDir;
660                 ba->passPhrase = passPhrase;
661                 ec = build(ts, specFile, ba, rpmcliRcfile);
662             }
663             ba->cookie = _free(ba->cookie);
664             specFile = _free(specFile);
665
666             if (ec)
667                 /*@loopbreak@*/ break;
668         }
669
670     }   break;
671
672     case MODE_BUILD:
673     case MODE_TARBUILD:
674     {   const char * pkg;
675         while (!rpmIsVerbose())
676             rpmIncreaseVerbosity();
677        
678         switch (ba->buildChar) {
679         case 'a':
680             ba->buildAmount |= RPMBUILD_PACKAGESOURCE;
681             /*@fallthrough@*/
682         case 'b':
683             ba->buildAmount |= RPMBUILD_PACKAGEBINARY;
684             ba->buildAmount |= RPMBUILD_CLEAN;
685             /*@fallthrough@*/
686         case 'i':
687             ba->buildAmount |= RPMBUILD_INSTALL;
688             ba->buildAmount |= RPMBUILD_CHECK;
689             if ((ba->buildChar == 'i') && ba->shortCircuit)
690                 /*@innerbreak@*/ break;
691             /*@fallthrough@*/
692         case 'c':
693             ba->buildAmount |= RPMBUILD_BUILD;
694             if ((ba->buildChar == 'c') && ba->shortCircuit)
695                 /*@innerbreak@*/ break;
696             /*@fallthrough@*/
697         case 'p':
698             ba->buildAmount |= RPMBUILD_PREP;
699             /*@innerbreak@*/ break;
700             
701         case 'l':
702             ba->buildAmount |= RPMBUILD_FILECHECK;
703             /*@innerbreak@*/ break;
704         case 's':
705             ba->buildAmount |= RPMBUILD_PACKAGESOURCE;
706             /*@innerbreak@*/ break;
707         }
708
709         if (!poptPeekArg(optCon)) {
710             if (bigMode == MODE_BUILD)
711                 argerror(_("no spec files given for build"));
712             else
713                 argerror(_("no tar files given for build"));
714         }
715
716         while ((pkg = poptGetArg(optCon))) {
717             ba->rootdir = rpmcliRootDir;
718             ba->passPhrase = passPhrase;
719             ba->cookie = NULL;
720             ec = build(ts, pkg, ba, rpmcliRcfile);
721             if (ec)
722                 /*@loopbreak@*/ break;
723             rpmFreeMacros(NULL);
724             (void) rpmReadConfigFiles(rpmcliRcfile, NULL);
725         }
726     }   break;
727 #endif  /* IAM_RPMBT */
728
729 #ifdef  IAM_RPMEIU
730     case MODE_ERASE:
731         if (ia->noDeps) ia->eraseInterfaceFlags |= UNINSTALL_NODEPS;
732
733         if (!poptPeekArg(optCon)) {
734             if (ia->rbtid == 0)
735                 argerror(_("no packages given for erase"));
736 ia->transFlags |= RPMTRANS_FLAG_NOMD5;
737 ia->probFilter |= RPMPROB_FILTER_OLDPACKAGE;
738             ec += rpmRollback(ts, ia, NULL);
739         } else {
740             ec += rpmErase(ts, ia, (const char **) poptGetArgs(optCon));
741         }
742         break;
743
744     case MODE_INSTALL:
745
746         /* RPMTRANS_FLAG_KEEPOBSOLETE */
747
748         if (!ia->incldocs) {
749             if (ia->transFlags & RPMTRANS_FLAG_NODOCS) {
750                 ;
751             } else if (rpmExpandNumeric("%{_excludedocs}"))
752                 ia->transFlags |= RPMTRANS_FLAG_NODOCS;
753         }
754
755         if (ia->noDeps) ia->installInterfaceFlags |= INSTALL_NODEPS;
756
757         /* we've already ensured !(!ia->prefix && !ia->relocations) */
758         /*@-branchstate@*/
759         if (ia->prefix) {
760             ia->relocations = xmalloc(2 * sizeof(*ia->relocations));
761             ia->relocations[0].oldPath = NULL;   /* special case magic */
762             ia->relocations[0].newPath = ia->prefix;
763             ia->relocations[1].oldPath = NULL;
764             ia->relocations[1].newPath = NULL;
765         } else if (ia->relocations) {
766             ia->relocations = xrealloc(ia->relocations, 
767                         sizeof(*ia->relocations) * (ia->numRelocations + 1));
768             ia->relocations[ia->numRelocations].oldPath = NULL;
769             ia->relocations[ia->numRelocations].newPath = NULL;
770         }
771         /*@=branchstate@*/
772
773         if (!poptPeekArg(optCon)) {
774             if (ia->rbtid == 0)
775                 argerror(_("no packages given for install"));
776 ia->transFlags |= RPMTRANS_FLAG_NOMD5;
777 ia->probFilter |= RPMPROB_FILTER_OLDPACKAGE;
778 /*@i@*/     ec += rpmRollback(ts, ia, NULL);
779         } else {
780             /*@-compdef -compmempass@*/ /* FIX: ia->relocations[0].newPath undefined */
781             ec += rpmInstall(ts, ia, (const char **)poptGetArgs(optCon));
782             /*@=compdef =compmempass@*/
783         }
784         break;
785
786 #endif  /* IAM_RPMEIU */
787
788 #ifdef  IAM_RPMQV
789     case MODE_QUERY:
790         if (qva->qva_source != RPMQV_ALL && !poptPeekArg(optCon))
791             argerror(_("no arguments given for query"));
792
793         qva->qva_specQuery = rpmspecQuery;
794         ec = rpmcliQuery(ts, qva, (const char **) poptGetArgs(optCon));
795         qva->qva_specQuery = NULL;
796         break;
797
798     case MODE_VERIFY:
799     {   rpmVerifyFlags verifyFlags = VERIFY_ALL;
800
801         verifyFlags &= ~qva->qva_flags;
802         qva->qva_flags = (rpmQueryFlags) verifyFlags;
803
804         if (qva->qva_source != RPMQV_ALL && !poptPeekArg(optCon))
805             argerror(_("no arguments given for verify"));
806         ec = rpmcliVerify(ts, qva, (const char **) poptGetArgs(optCon));
807     }   break;
808 #endif  /* IAM_RPMQV */
809
810 #ifdef IAM_RPMK
811     case MODE_CHECKSIG:
812     {   rpmVerifyFlags verifyFlags =
813                 (VERIFY_MD5|VERIFY_DIGEST|VERIFY_SIGNATURE);
814
815         verifyFlags &= ~ka->qva_flags;
816         ka->qva_flags = (rpmQueryFlags) verifyFlags;
817     }   /*@fallthrough@*/
818     case MODE_RESIGN:
819         if (!poptPeekArg(optCon))
820             argerror(_("no arguments given"));
821         ka->passPhrase = passPhrase;
822         ec = rpmcliSign(ts, ka, (const char **)poptGetArgs(optCon));
823         break;
824 #endif  /* IAM_RPMK */
825         
826 #if !defined(IAM_RPMQV)
827     case MODE_QUERY:
828     case MODE_VERIFY:
829 #endif
830 #if !defined(IAM_RPMK)
831     case MODE_CHECKSIG:
832     case MODE_RESIGN:
833 #endif
834 #if !defined(IAM_RPMDB)
835     case MODE_INITDB:
836     case MODE_REBUILDDB:
837     case MODE_VERIFYDB:
838 #endif
839 #if !defined(IAM_RPMBT)
840     case MODE_BUILD:
841     case MODE_REBUILD:
842     case MODE_RECOMPILE:
843     case MODE_TARBUILD:
844 #endif
845 #if !defined(IAM_RPMEIU)
846     case MODE_INSTALL:
847     case MODE_ERASE:
848 #endif
849     case MODE_UNKNOWN:
850         if (poptPeekArg(optCon) != NULL || argc <= 1 || rpmIsVerbose()) {
851             printUsage(optCon, stdout, 0);
852             ec = argc;
853         }
854         break;
855     }
856
857 #if defined(IAM_RPMBT) || defined(IAM_RPMK)
858 exit:
859 #endif  /* IAM_RPMBT || IAM_RPMK */
860
861     ts = rpmtsFree(ts);
862
863     optCon = poptFreeContext(optCon);
864     rpmFreeMacros(NULL);
865 /*@i@*/ rpmFreeMacros(rpmCLIMacroContext);
866     rpmFreeRpmrc();
867
868     if (pipeChild) {
869         (void) fclose(stdout);
870         (void) waitpid(pipeChild, &status, 0);
871     }
872
873     /* keeps memory leak checkers quiet */
874     freeFilesystems();
875 /*@i@*/ urlFreeCache();
876     rpmlogClose();
877     dbiTags = _free(dbiTags);
878
879 #ifdef  IAM_RPMQV
880     qva->qva_queryFormat = _free(qva->qva_queryFormat);
881 #endif
882
883 #ifdef  IAM_RPMBT
884     freeNames();
885     ba->buildRootOverride = _free(ba->buildRootOverride);
886     ba->targets = _free(ba->targets);
887 #endif
888
889 #ifdef  IAM_RPMEIU
890     if (ia->relocations != NULL)
891     for (i = 0; i < ia->numRelocations; i++)
892         ia->relocations[i].oldPath = _free(ia->relocations[i].oldPath);
893     ia->relocations = _free(ia->relocations);
894 #endif
895
896 #if HAVE_MCHECK_H && HAVE_MTRACE
897     /*@-noeffect@*/
898     muntrace();   /* Trace malloc only if MALLOC_TRACE=mtrace-output-file. */
899     /*@=noeffect@*/
900 #endif
901
902     /* XXX don't overflow single byte exit status */
903     if (ec > 255) ec = 255;
904
905     /*@-globstate@*/
906     return ec;
907     /*@=globstate@*/
908 }
909 /*@=mods@*/
910 /*@=bounds@*/