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