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