- fix: scope multi-mode options like --nodeps correctly (#48825).
[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 #define POPT_NODEPS             1025
17 #define POPT_FORCE              1026
18 #define POPT_NOMD5              1027
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 #define GETOPT_DBPATH           1010
33 #define GETOPT_SHOWRC           1018
34 #define GETOPT_DEFINEMACRO      1020
35 #define GETOPT_EVALMACRO        1021
36 #ifdef  NOTYET
37 #define GETOPT_RCFILE           1022
38 #endif
39
40 enum modes {
41
42     MODE_QUERY          = (1 <<  0),
43     MODE_VERIFY         = (1 <<  3),
44     MODE_QUERYTAGS      = (1 <<  9),
45 #define MODES_QV (MODE_QUERY | MODE_VERIFY)
46
47     MODE_INSTALL        = (1 <<  1),
48     MODE_ERASE          = (1 <<  2),
49     MODE_ROLLBACK       = (1 << 14),
50 #define MODES_IE (MODE_INSTALL | MODE_ERASE | MODE_ROLLBACK)
51
52     MODE_BUILD          = (1 <<  4),
53     MODE_REBUILD        = (1 <<  5),
54     MODE_RECOMPILE      = (1 <<  8),
55     MODE_TARBUILD       = (1 << 11),
56 #define MODES_BT (MODE_BUILD | MODE_TARBUILD | MODE_REBUILD | MODE_RECOMPILE)
57
58     MODE_CHECKSIG       = (1 <<  6),
59     MODE_RESIGN         = (1 <<  7),
60 #define MODES_K  (MODE_CHECKSIG | MODE_RESIGN)
61
62     MODE_INITDB         = (1 << 10),
63     MODE_REBUILDDB      = (1 << 12),
64     MODE_VERIFYDB       = (1 << 13),
65 #define MODES_DB (MODE_INITDB | MODE_REBUILDDB | MODE_VERIFYDB)
66
67
68     MODE_UNKNOWN        = 0
69 };
70
71 #define MODES_FOR_DBPATH        (MODES_BT | MODES_IE | MODES_QV | MODES_DB)
72 #define MODES_FOR_NODEPS        (MODES_BT | MODES_IE | MODE_VERIFY)
73 #define MODES_FOR_TEST          (MODES_BT | MODES_IE)
74 #define MODES_FOR_ROOT          (MODES_BT | MODES_IE | MODES_QV | MODES_DB)
75
76 /*@-exportheadervar@*/
77 extern int _ftp_debug;
78 extern int noLibio;
79 extern int _rpmio_debug;
80 extern int _url_debug;
81
82 /*@-varuse@*/
83 /*@observer@*/ extern const char * rpmNAME;
84 /*@=varuse@*/
85 /*@observer@*/ extern const char * rpmEVR;
86 /*@-varuse@*/
87 extern int rpmFLAGS;
88 /*@=varuse@*/
89
90 extern struct MacroContext_s rpmCLIMacroContext;
91 /*@=exportheadervar@*/
92
93 /* options for all executables */
94
95 static int help = 0;
96 static int noUsageMsg = 0;
97 /*@observer@*/ /*@null@*/ static const char * pipeOutput = NULL;
98 static int quiet = 0;
99 /*@observer@*/ /*@null@*/ static const char * rcfile = NULL;
100 /*@observer@*/ /*@null@*/ static char * rootdir = "/";
101 static int showrc = 0;
102 static int showVersion = 0;
103
104 static struct poptOption rpmAllPoptTable[] = {
105  { "version", '\0', 0, &showVersion, 0,
106         N_("print the version of rpm being used"),
107         NULL },
108  { "quiet", '\0', 0, &quiet, 0,
109         N_("provide less detailed output"), NULL},
110  { "verbose", 'v', 0, 0, 'v',
111         N_("provide more detailed output"), NULL},
112  { "define", '\0', POPT_ARG_STRING, 0, GETOPT_DEFINEMACRO,
113         N_("define macro <name> with value <body>"),
114         N_("'<name> <body>'") },
115  { "eval", '\0', POPT_ARG_STRING, 0, GETOPT_EVALMACRO,
116         N_("print macro expansion of <expr>+"),
117         N_("<expr>+") },
118  { "pipe", '\0', POPT_ARG_STRING|POPT_ARGFLAG_DOC_HIDDEN, &pipeOutput, 0,
119         N_("send stdout to <cmd>"),
120         N_("<cmd>") },
121  { "root", 'r', POPT_ARG_STRING | POPT_ARGFLAG_SHOW_DEFAULT, &rootdir, 0,
122         N_("use <dir> as the top level directory"),
123         N_("<dir>") },
124  { "macros", '\0', POPT_ARG_STRING, &macrofiles, 0,
125         N_("read <file:...> instead of default macro file(s)"),
126         N_("<file:...>") },
127 #if !defined(GETOPT_RCFILE)
128  { "rcfile", '\0', POPT_ARG_STRING, &rcfile, 0,
129         N_("read <file:...> instead of default rpmrc file(s)"),
130         N_("<file:...>") },
131 #else
132  { "rcfile", '\0', 0, 0, GETOPT_RCFILE, 
133         N_("read <file:...> instead of default rpmrc file(s)"),
134         N_("<file:...>") },
135 #endif
136  { "showrc", '\0', 0, &showrc, GETOPT_SHOWRC,
137         N_("display final rpmrc and macro configuration"),
138         NULL },
139
140 #if HAVE_LIBIO_H && defined(_G_IO_IO_FILE_VERSION)
141  { "nolibio", '\0', POPT_ARG_VAL|POPT_ARGFLAG_DOC_HIDDEN, &noLibio, 1,
142         N_("disable use of libio(3) API"), NULL},
143 #endif
144  { "ftpdebug", '\0', POPT_ARG_VAL|POPT_ARGFLAG_DOC_HIDDEN, &_ftp_debug, -1,
145         N_("debug protocol data stream"), NULL},
146  { "rpmiodebug", '\0', POPT_ARG_VAL|POPT_ARGFLAG_DOC_HIDDEN, &_rpmio_debug, -1,
147         N_("debug rpmio I/O"), NULL},
148  { "urldebug", '\0', POPT_ARG_VAL|POPT_ARGFLAG_DOC_HIDDEN, &_url_debug, -1,
149         N_("debug URL cache handling"), NULL},
150
151    POPT_TABLEEND
152 };
153
154 /* the structure describing the options we take and the defaults */
155 static struct poptOption optionsTable[] = {
156
157  /* XXX colliding options */
158 #if defined(IAM_RPMQV) || defined(IAM_RPMEIU) || defined(IAM_RPMBT)
159  {  NULL, 'i', POPT_ARGFLAG_DOC_HIDDEN, 0, 'i',                 NULL, NULL},
160  {  "nodeps", 0, POPT_ARGFLAG_DOC_HIDDEN, 0, POPT_NODEPS,       NULL, NULL},
161  {  "nomd5", 0, POPT_ARGFLAG_DOC_HIDDEN, 0, POPT_NOMD5,         NULL, NULL},
162  {  "force", 0, POPT_ARGFLAG_DOC_HIDDEN, 0, POPT_FORCE,         NULL, NULL},
163 #endif
164
165 #ifdef  IAM_RPMQV
166  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmQueryPoptTable, 0,
167         N_("Query options (with -q or --query):"),
168         NULL },
169  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmVerifyPoptTable, 0,
170         N_("Verify options (with -V or --verify):"),
171         NULL },
172 #endif  /* IAM_RPMQV */
173
174 #ifdef  IAM_RPMK
175  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmSignPoptTable, 0,
176         N_("Signature options:"),
177         NULL },
178 #endif  /* IAM_RPMK */
179
180 #ifdef  IAM_RPMDB
181  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmDatabasePoptTable, 0,
182         N_("Database options:"),
183         NULL },
184 #endif  /* IAM_RPMDB */
185
186 #ifdef  IAM_RPMBT
187  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmBuildPoptTable, 0,
188         N_("Build options with [ <specfile> | <tarball> | <source package> ]:"),
189         NULL },
190 #endif  /* IAM_RPMBT */
191
192 #ifdef  IAM_RPMEIU
193  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmInstallPoptTable, 0,
194         N_("Install/Upgrade/Erase options:"),
195         NULL },
196 #endif  /* IAM_RPMEIU */
197
198  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmAllPoptTable, 0,
199         N_("Common options for all rpm modes:"),
200         NULL },
201
202    POPT_AUTOALIAS
203    POPT_AUTOHELP
204    POPT_TABLEEND
205 };
206
207 #ifdef __MINT__
208 /* MiNT cannot dynamically increase the stack.  */
209 long _stksize = 64 * 1024L;
210 #endif
211
212 /*@exits@*/ static void argerror(const char * desc)
213         /*@modifies fileSystem @*/
214 {
215     fprintf(stderr, _("%s: %s\n"), __progname, desc);
216     exit(EXIT_FAILURE);
217 }
218
219 static void printVersion(void)
220         /*@modifies fileSystem @*/
221 {
222     fprintf(stdout, _("RPM version %s\n"), rpmEVR);
223 }
224
225 static void printBanner(void)
226         /*@modifies fileSystem @*/
227 {
228     (void) puts(_("Copyright (C) 1998-2000 - Red Hat, Inc."));
229     (void) puts(_("This program may be freely redistributed under the terms of the GNU GPL"));
230 }
231
232 static void printUsage(void)
233         /*@modifies fileSystem @*/
234 {
235     FILE * fp = stdout;
236     printVersion();
237     printBanner();
238     (void) puts("");
239
240     fprintf(fp, _("Usage: %s {--help}\n"), __progname);
241     fprintf(fp,  ("       %s {--version}\n"), __progname);
242
243 #ifdef  IAM_RPMEIU
244 #ifdef  DYING
245 --dbpath        all
246 --ftpproxy etc  all
247 --force         alias for --replacepkgs --replacefiles
248 --includedocs   handle as option in table
249                 --erase forbids many options
250 #endif  /* DYING */
251 #endif  /* IAM_RPMEIU */
252
253 #ifdef  IAM_RPMQV
254 #ifdef  DYING   /* XXX popt glue needing --help doco. */
255 --dbpath        all
256 --ftpproxy etc  all
257 -i,--info       Q
258 -R,--requires   Q
259 -P,--provides   Q
260 --scripts       Q
261 --triggeredby   Q
262 --changelog     Q
263 --triggers      Q
264 --querytags     !V
265 --setperms      V
266 --setugids      V
267 #endif  /* DYING */
268 #endif  /* IAM_RPMQV */
269
270 }
271
272 int main(int argc, const char ** argv)
273 {
274     enum modes bigMode = MODE_UNKNOWN;
275
276 #ifdef  IAM_RPMQV
277     QVA_t qva = &rpmQVArgs;
278 #endif
279
280 #ifdef  IAM_RPMBT
281     BTA_t ba = &rpmBTArgs;
282 #endif
283
284 #ifdef  IAM_RPMEIU
285    struct rpmInstallArguments_s * ia = &rpmIArgs;
286 #endif
287
288 #if defined(IAM_RPMDB)
289    struct rpmDatabaseArguments_s * da = &rpmDBArgs;
290 #endif
291
292 #if defined(IAM_RPMK)
293    struct rpmSignArguments_s * ka = &rpmKArgs;
294 #endif
295
296 #if defined(IAM_RPMBT) || defined(IAM_RPMK)
297     char * passPhrase = "";
298 #endif
299
300     int arg;
301     int gotDbpath = 0;
302
303     const char * optArg;
304     pid_t pipeChild = 0;
305     poptContext optCon;
306     int ec = 0;
307     int status;
308     int p[2];
309         
310 #if HAVE_MCHECK_H && HAVE_MTRACE
311     mtrace();   /* Trace malloc only if MALLOC_TRACE=mtrace-output-file. */
312 #endif
313     setprogname(argv[0]);       /* Retrofit glibc __progname */
314
315     /* XXX glibc churn sanity */
316     if (__progname == NULL) {
317         if ((__progname = strrchr(argv[0], '/')) != NULL) __progname++;
318         else __progname = argv[0];
319     }
320
321     /* Set the major mode based on argv[0] */
322     /*@-nullpass@*/
323 #ifdef  IAM_RPMBT
324     if (!strcmp(__progname, "rpmb"))    bigMode = MODE_BUILD;
325     if (!strcmp(__progname, "rpmt"))    bigMode = MODE_TARBUILD;
326     if (!strcmp(__progname, "rpmbuild"))        bigMode = MODE_BUILD;
327 #endif
328 #ifdef  IAM_RPMQV
329     if (!strcmp(__progname, "rpmq"))    bigMode = MODE_QUERY;
330     if (!strcmp(__progname, "rpmv"))    bigMode = MODE_VERIFY;
331     if (!strcmp(__progname, "rpmquery"))        bigMode = MODE_QUERY;
332     if (!strcmp(__progname, "rpmverify"))       bigMode = MODE_VERIFY;
333 #endif
334 #ifdef  RPMEIU
335     if (!strcmp(__progname, "rpme"))    bigMode = MODE_ERASE;
336     if (!strcmp(__progname, "rpmi"))    bigMode = MODE_INSTALL;
337     if (!strcmp(__progname, "rpmu"))    bigMode = MODE_INSTALL;
338 #endif
339     /*@=nullpass@*/
340
341     /* set the defaults for the various command line options */
342     _ftp_debug = 0;
343
344 #if HAVE_LIBIO_H && defined(_G_IO_IO_FILE_VERSION)
345     noLibio = 0;
346 #else
347     noLibio = 1;
348 #endif
349     _rpmio_debug = 0;
350     _url_debug = 0;
351
352     /* XXX Eliminate query linkage loop */
353     specedit = 0;
354     parseSpecVec = parseSpec;
355     freeSpecVec = freeSpec;
356
357     /* set up the correct locale */
358     (void) setlocale(LC_ALL, "" );
359
360 #ifdef  __LCLINT__
361 #define LOCALEDIR       "/usr/share/locale"
362 #endif
363     bindtextdomain(PACKAGE, LOCALEDIR);
364     textdomain(PACKAGE);
365
366     rpmSetVerbosity(RPMMESS_NORMAL);    /* XXX silly use by showrc */
367
368     /* Make a first pass through the arguments, looking for --rcfile */
369     /* We need to handle that before dealing with the rest of the arguments. */
370     /*@-nullpass -temptrans@*/
371     optCon = poptGetContext(__progname, argc, argv, optionsTable, 0);
372     /*@=nullpass =temptrans@*/
373     (void) poptReadConfigFile(optCon, LIBRPMALIAS_FILENAME);
374     (void) poptReadDefaultConfig(optCon, 1);
375     poptSetExecPath(optCon, RPMCONFIGDIR, 1);
376
377     /* reading rcfile early makes it easy to override */
378     /* XXX only --rcfile (and --showrc) need this pre-parse */
379
380     while ((arg = poptGetNextOpt(optCon)) > 0) {
381         switch(arg) {
382         case 'v':
383             rpmIncreaseVerbosity();     /* XXX silly use by showrc */
384             break;
385         default:
386             break;
387       }
388     }
389
390     if (rpmReadConfigFiles(rcfile, NULL))  
391         exit(EXIT_FAILURE);
392
393     if (showrc) {
394         (void) rpmShowRC(stdout);
395         exit(EXIT_SUCCESS);
396     }
397
398     rpmSetVerbosity(RPMMESS_NORMAL);    /* XXX silly use by showrc */
399
400     poptResetContext(optCon);
401
402 #ifdef  IAM_RPMQV
403     qva->qva_queryFormat = _free(qva->qva_queryFormat);
404     memset(qva, 0, sizeof(*qva));
405     qva->qva_source = RPMQV_PACKAGE;
406     qva->qva_fflags = RPMFILE_ALL;
407     qva->qva_mode = ' ';
408     qva->qva_char = ' ';
409 #endif
410
411 #ifdef  IAM_RPMBT
412     ba->buildRootOverride = _free(ba->buildRootOverride);
413     ba->targets = _free(ba->targets);
414     memset(ba, 0, sizeof(*ba));
415     ba->buildMode = ' ';
416     ba->buildChar = ' ';
417 #endif
418
419 #ifdef  IAM_RPMDB
420     memset(da, 0, sizeof(*da));
421 #endif
422
423 #ifdef  IAM_RPMK
424     memset(ka, 0, sizeof(*ka));
425     ka->addSign = RESIGN_NONE;
426     ka->checksigFlags = CHECKSIG_ALL;
427 #endif
428
429 #ifdef  IAM_RPMEIU
430     ia->relocations = _free(ia->relocations);
431     memset(ia, 0, sizeof(*ia));
432     ia->transFlags = RPMTRANS_FLAG_NONE;
433     ia->probFilter = RPMPROB_FILTER_NONE;
434     ia->installInterfaceFlags = INSTALL_NONE;
435     ia->eraseInterfaceFlags = UNINSTALL_NONE;
436 #endif
437
438     while ((arg = poptGetNextOpt(optCon)) > 0) {
439         optArg = poptGetOptArg(optCon);
440
441         switch (arg) {
442             
443         case 'v':
444             rpmIncreaseVerbosity();
445             break;
446
447 /* XXX options used in multiple rpm modes */
448 #if defined(IAM_RPMQV) || defined(IAM_RPMK)
449         case POPT_NOMD5:
450 #ifdef  IAM_RPMQV
451             if (bigMode == MODE_VERIFY || qva->qva_mode == 'V')
452                 qva->qva_flags |= VERIFY_MD5;
453             else
454 #endif
455 #ifdef  IAM_RPMK
456             if (bigMode & MODES_K)
457                 ka->checksigFlags &= ~CHECKSIG_MD5;
458             else
459 #endif
460                 /*@-ifempty@*/ ;
461             break;
462 #endif  /* IAM_RPMQV || IAM_RPMK */
463
464 #if defined(IAM_RPMQV) || defined(IAM_RPMEIU) || defined(IAM_RPMBT)
465         case POPT_NODEPS:
466 #ifdef  IAM_RPMQV
467             if (bigMode == MODE_VERIFY || qva->qva_mode == 'V')
468                 qva->qva_flags |= VERIFY_DEPS;
469             else
470 #endif
471 #ifdef  IAM_RPMEIU
472             if ((bigMode & MODES_IE) ||
473                 (ia->installInterfaceFlags &
474             (INSTALL_UPGRADE|INSTALL_FRESHEN|INSTALL_INSTALL|INSTALL_ERASE)))
475                 ia->noDeps = 1;
476             else
477 #endif
478 #ifdef  IAM_RPMBT
479             if ((bigMode & MODES_BT) || ba->buildMode != ' ')
480                 ba->noDeps = 1;
481             else
482 #endif
483                 /*@-ifempty@*/ ;
484             break;
485
486         case POPT_FORCE:
487 #ifdef  IAM_RPMEIU
488             if ((bigMode & MODES_IE) ||
489                 (ia->installInterfaceFlags &
490             (INSTALL_UPGRADE|INSTALL_FRESHEN|INSTALL_INSTALL|INSTALL_ERASE)))
491                 ia->probFilter |=
492                         ( RPMPROB_FILTER_REPLACEPKG
493                         | RPMPROB_FILTER_REPLACEOLDFILES
494                         | RPMPROB_FILTER_REPLACENEWFILES
495                         | RPMPROB_FILTER_OLDPACKAGE);
496             else
497 #endif
498 #ifdef  IAM_RPMBT
499             if ((bigMode & MODES_BT) || ba->buildMode != ' ')
500                 ba->force = 1;
501             else
502 #endif
503                 /*@-ifempty@*/ ;
504             break;
505
506         case 'i':
507 #ifdef  IAM_RPMQV
508             if (bigMode == MODE_QUERY || qva->qva_mode == 'q') {
509                 /*@-nullassign -readonlytrans@*/
510                 const char * infoCommand[] = { "--info", NULL };
511                 /*@=nullassign =readonlytrans@*/
512                 (void) poptStuffArgs(optCon, infoCommand);
513             } else
514 #endif
515 #ifdef  IAM_RPMEIU
516             if (bigMode == MODE_INSTALL ||
517                 (ia->installInterfaceFlags &
518                     (INSTALL_UPGRADE|INSTALL_FRESHEN|INSTALL_INSTALL)))
519                 /*@-ifempty@*/ ;
520             else if (bigMode == MODE_UNKNOWN) {
521                 /*@-nullassign -readonlytrans@*/
522                 const char * installCommand[] = { "--install", NULL };
523                 /*@=nullassign =readonlytrans@*/
524                 (void) poptStuffArgs(optCon, installCommand);
525             } else
526 #endif
527                 /*@-ifempty@*/ ;
528             break;
529 #endif  /* IAM_RPMQV || IAM_RPMEIU || IAM_RPMBT */
530
531         case GETOPT_DEFINEMACRO:
532             if (optArg) {
533                 (void) rpmDefineMacro(NULL, optArg, RMIL_CMDLINE);
534                 (void) rpmDefineMacro(&rpmCLIMacroContext, optArg,RMIL_CMDLINE);
535             }
536             noUsageMsg = 1;
537             break;
538
539         case GETOPT_EVALMACRO:
540             if (optArg) {
541                 const char *val = rpmExpand(optArg, NULL);
542                 fprintf(stdout, "%s\n", val);
543                 val = _free(val);
544             }
545             noUsageMsg = 1;
546             break;
547
548 #if defined(GETOPT_RCFILE)
549         case GETOPT_RCFILE:
550             fprintf(stderr, _("The --rcfile option has been eliminated.\n"));
551             fprintf(stderr, _("Use \"--macros <file:...>\" instead.\n"));
552             exit(EXIT_FAILURE);
553             /*@notreached@*/ break;
554 #endif
555
556         default:
557             fprintf(stderr, _("Internal error in argument processing (%d) :-(\n"), arg);
558             exit(EXIT_FAILURE);
559         }
560     }
561
562     if (quiet)
563         rpmSetVerbosity(RPMMESS_QUIET);
564
565     if (showVersion) printVersion();
566
567     if (arg < -1) {
568         fprintf(stderr, "%s: %s\n", 
569                 poptBadOption(optCon, POPT_BADOPTION_NOALIAS), 
570                 poptStrerror(arg));
571         exit(EXIT_FAILURE);
572     }
573
574 #ifdef  IAM_RPMBT
575     switch (ba->buildMode) {
576     case 'b':   bigMode = MODE_BUILD;           break;
577     case 't':   bigMode = MODE_TARBUILD;        break;
578     case 'B':   bigMode = MODE_REBUILD;         break;
579     case 'C':   bigMode = MODE_RECOMPILE;       break;
580     }
581
582     if ((ba->buildAmount & RPMBUILD_RMSOURCE) && bigMode == MODE_UNKNOWN)
583         bigMode = MODE_BUILD;
584
585     if ((ba->buildAmount & RPMBUILD_RMSPEC) && bigMode == MODE_UNKNOWN)
586         bigMode = MODE_BUILD;
587
588     if (ba->buildRootOverride && bigMode != MODE_BUILD &&
589         bigMode != MODE_REBUILD && bigMode != MODE_TARBUILD) {
590         argerror("--buildroot may only be used during package builds");
591     }
592 #endif  /* IAM_RPMBT */
593     
594 #ifdef  IAM_RPMDB
595   if (bigMode == MODE_UNKNOWN) {
596     if (da->init) {
597         if (bigMode != MODE_UNKNOWN) 
598             argerror(_("only one major mode may be specified"));
599         else
600             bigMode = MODE_INITDB;
601     } else
602     if (da->rebuild) {
603         if (bigMode != MODE_UNKNOWN) 
604             argerror(_("only one major mode may be specified"));
605         else
606             bigMode = MODE_REBUILDDB;
607     } else
608     if (da->verify) {
609         if (bigMode != MODE_UNKNOWN) 
610             argerror(_("only one major mode may be specified"));
611         else
612             bigMode = MODE_VERIFYDB;
613     }
614   }
615 #endif  /* IAM_RPMDB */
616
617 #ifdef  IAM_RPMQV
618   if (bigMode == MODE_UNKNOWN) {
619     switch (qva->qva_mode) {
620     case 'q':   bigMode = MODE_QUERY;           break;
621     case 'V':   bigMode = MODE_VERIFY;          break;
622     case 'Q':   bigMode = MODE_QUERYTAGS;       break;
623     }
624
625     if (qva->qva_sourceCount) {
626         if (qva->qva_sourceCount > 2)
627             argerror(_("one type of query/verify may be performed at a "
628                         "time"));
629     }
630     if (qva->qva_flags && (bigMode & ~MODES_QV)) 
631         argerror(_("unexpected query flags"));
632
633     if (qva->qva_queryFormat && (bigMode & ~MODES_QV)) 
634         argerror(_("unexpected query format"));
635
636     if (qva->qva_source != RPMQV_PACKAGE && (bigMode & ~MODES_QV)) 
637         argerror(_("unexpected query source"));
638   }
639 #endif  /* IAM_RPMQV */
640
641 #ifdef  IAM_RPMEIU
642   if (bigMode == MODE_UNKNOWN)
643     {   int iflags = (ia->installInterfaceFlags &
644                 (INSTALL_UPGRADE|INSTALL_FRESHEN|INSTALL_INSTALL));
645         int eflags = (ia->installInterfaceFlags & INSTALL_ERASE);
646
647         if (iflags & eflags)
648             argerror(_("only one major mode may be specified"));
649         else if (iflags)
650             bigMode = MODE_INSTALL;
651         else if (eflags)
652             bigMode = MODE_ERASE;
653     }
654 #endif  /* IAM_RPMQV */
655
656 #ifdef  IAM_RPMK
657   if (bigMode == MODE_UNKNOWN) {
658         switch (ka->addSign) {
659         case RESIGN_NONE:
660             break;
661         case RESIGN_CHK_SIGNATURE:
662             bigMode = MODE_CHECKSIG;
663             break;
664         case RESIGN_ADD_SIGNATURE:
665         case RESIGN_NEW_SIGNATURE:
666             bigMode = MODE_RESIGN;
667             break;
668
669         }
670   }
671 #endif  /* IAM_RPMK */
672
673     /* XXX TODO: never happens. */
674     if (gotDbpath && (bigMode & ~MODES_FOR_DBPATH))
675         argerror(_("--dbpath given for operation that does not use a "
676                         "database"));
677
678 #if defined(IAM_RPMEIU)
679     if (!( bigMode == MODE_INSTALL ) &&
680 (ia->probFilter & (RPMPROB_FILTER_REPLACEPKG | RPMPROB_FILTER_REPLACEOLDFILES | RPMPROB_FILTER_REPLACENEWFILES | RPMPROB_FILTER_OLDPACKAGE)))
681         argerror(_("only installation, upgrading, rmsource and rmspec may be forced"));
682     if (bigMode != MODE_INSTALL && (ia->probFilter & RPMPROB_FILTER_FORCERELOCATE))
683         argerror(_("files may only be relocated during package installation"));
684
685     if (ia->relocations && ia->prefix)
686         argerror(_("only one of --prefix or --relocate may be used"));
687
688     if (bigMode != MODE_INSTALL && ia->relocations)
689         argerror(_("--relocate and --excludepath may only be used when installing new packages"));
690
691     if (bigMode != MODE_INSTALL && ia->prefix)
692         argerror(_("--prefix may only be used when installing new packages"));
693
694     if (ia->prefix && ia->prefix[0] != '/') 
695         argerror(_("arguments to --prefix must begin with a /"));
696
697     if (bigMode != MODE_INSTALL && (ia->installInterfaceFlags & INSTALL_HASH))
698         argerror(_("--hash (-h) may only be specified during package "
699                         "installation"));
700
701     if (bigMode != MODE_INSTALL && (ia->installInterfaceFlags & INSTALL_PERCENT))
702         argerror(_("--percent may only be specified during package "
703                         "installation"));
704
705     if (bigMode != MODE_INSTALL &&
706  (ia->probFilter & (RPMPROB_FILTER_REPLACEOLDFILES|RPMPROB_FILTER_REPLACENEWFILES)))
707         argerror(_("--replacefiles may only be specified during package "
708                         "installation"));
709
710     if (bigMode != MODE_INSTALL && (ia->probFilter & RPMPROB_FILTER_REPLACEPKG))
711         argerror(_("--replacepkgs may only be specified during package "
712                         "installation"));
713
714     if (bigMode != MODE_INSTALL && (ia->transFlags & RPMTRANS_FLAG_NODOCS))
715         argerror(_("--excludedocs may only be specified during package "
716                    "installation"));
717
718     if (bigMode != MODE_INSTALL && ia->incldocs)
719         argerror(_("--includedocs may only be specified during package "
720                    "installation"));
721
722     if (ia->incldocs && (ia->transFlags & RPMTRANS_FLAG_NODOCS))
723         argerror(_("only one of --excludedocs and --includedocs may be "
724                  "specified"));
725   
726     if (bigMode != MODE_INSTALL && (ia->probFilter & RPMPROB_FILTER_IGNOREARCH))
727         argerror(_("--ignorearch may only be specified during package "
728                    "installation"));
729
730     if (bigMode != MODE_INSTALL && (ia->probFilter & RPMPROB_FILTER_IGNOREOS))
731         argerror(_("--ignoreos may only be specified during package "
732                    "installation"));
733
734     if (bigMode != MODE_INSTALL &&
735         (ia->probFilter & (RPMPROB_FILTER_DISKSPACE|RPMPROB_FILTER_DISKNODES)))
736         argerror(_("--ignoresize may only be specified during package "
737                    "installation"));
738
739     if ((ia->eraseInterfaceFlags & UNINSTALL_ALLMATCHES) && bigMode != MODE_ERASE)
740         argerror(_("--allmatches may only be specified during package "
741                    "erasure"));
742
743     if ((ia->transFlags & RPMTRANS_FLAG_ALLFILES) && bigMode != MODE_INSTALL)
744         argerror(_("--allfiles may only be specified during package "
745                    "installation"));
746
747     if ((ia->transFlags & RPMTRANS_FLAG_JUSTDB) &&
748         bigMode != MODE_INSTALL && bigMode != MODE_ERASE)
749         argerror(_("--justdb may only be specified during package "
750                    "installation and erasure"));
751
752     if (bigMode != MODE_INSTALL && bigMode != MODE_ERASE &&
753         (ia->transFlags & (RPMTRANS_FLAG_NOSCRIPTS | _noTransScripts | _noTransTriggers)))
754         argerror(_("script disabling options may only be specified during "
755                    "package installation and erasure"));
756
757     if (bigMode != MODE_INSTALL && bigMode != MODE_ERASE &&
758         (ia->transFlags & (RPMTRANS_FLAG_NOTRIGGERS | _noTransTriggers)))
759         argerror(_("trigger disabling options may only be specified during "
760                    "package installation and erasure"));
761
762     if (ia->noDeps & (bigMode & ~MODES_FOR_NODEPS))
763         argerror(_("--nodeps may only be specified during package "
764                    "building, rebuilding, recompilation, installation,"
765                    "erasure, and verification"));
766
767     if ((ia->transFlags & RPMTRANS_FLAG_TEST) && (bigMode & ~MODES_FOR_TEST))
768         argerror(_("--test may only be specified during package installation, "
769                  "erasure, and building"));
770 #endif  /* IAM_RPMEIU */
771
772     if (rootdir && rootdir[1] && (bigMode & ~MODES_FOR_ROOT))
773         argerror(_("--root (-r) may only be specified during "
774                  "installation, erasure, querying, and "
775                  "database rebuilds"));
776
777     if (rootdir) {
778         switch (urlIsURL(rootdir)) {
779         default:
780             if (bigMode & MODES_FOR_ROOT)
781                 break;
782             /*@fallthrough@*/
783         case URL_IS_UNKNOWN:
784             if (rootdir[0] != '/')
785                 argerror(_("arguments to --root (-r) must begin with a /"));
786             break;
787         }
788     }
789
790 #if defined(IAM_RPMBT) || defined(IAM_RPMK)
791     if (0
792 #if defined(IAM_RPMBT)
793     || ba->sign 
794 #endif
795 #if defined(IAM_RPMK)
796     || ka->sign
797 #endif
798     ) {
799         if (bigMode == MODE_REBUILD || bigMode == MODE_BUILD ||
800             bigMode == MODE_RESIGN || bigMode == MODE_TARBUILD) {
801             const char ** av;
802             struct stat sb;
803             int errors = 0;
804
805             if ((av = poptGetArgs(optCon)) == NULL) {
806                 fprintf(stderr, _("no files to sign\n"));
807                 errors++;
808             } else
809             while (*av) {
810                 if (stat(*av, &sb)) {
811                     fprintf(stderr, _("cannot access file %s\n"), *av);
812                     errors++;
813                 }
814                 av++;
815             }
816
817             if (errors) {
818                 ec = errors;
819                 goto exit;
820             }
821
822             if (poptPeekArg(optCon)) {
823                 int sigTag;
824                 switch (sigTag = rpmLookupSignatureType(RPMLOOKUPSIG_QUERY)) {
825                   case 0:
826                     break;
827                   case RPMSIGTAG_PGP:
828                     if ((sigTag == RPMSIGTAG_PGP || sigTag == RPMSIGTAG_PGP5) &&
829                         !rpmDetectPGPVersion(NULL)) {
830                         fprintf(stderr, _("pgp not found: "));
831                         ec = EXIT_FAILURE;
832                         goto exit;
833                     }   /*@fallthrough@*/
834                   case RPMSIGTAG_GPG:
835                     passPhrase = rpmGetPassPhrase(_("Enter pass phrase: "), sigTag);
836                     if (passPhrase == NULL) {
837                         fprintf(stderr, _("Pass phrase check failed\n"));
838                         ec = EXIT_FAILURE;
839                         goto exit;
840                     }
841                     fprintf(stderr, _("Pass phrase is good.\n"));
842                     passPhrase = xstrdup(passPhrase);
843                     break;
844                   default:
845                     fprintf(stderr,
846                             _("Invalid %%_signature spec in macro file.\n"));
847                     ec = EXIT_FAILURE;
848                     goto exit;
849                     /*@notreached@*/ break;
850                 }
851             }
852         } else {
853             argerror(_("--sign may only be used during package building"));
854         }
855     } else {
856         /* Make rpmLookupSignatureType() return 0 ("none") from now on */
857         (void) rpmLookupSignatureType(RPMLOOKUPSIG_DISABLE);
858     }
859 #endif  /* IAM_RPMBT || IAM_RPMK */
860
861     if (pipeOutput) {
862         (void) pipe(p);
863
864         if (!(pipeChild = fork())) {
865             (void) close(p[1]);
866             (void) dup2(p[0], STDIN_FILENO);
867             (void) close(p[0]);
868             (void) execl("/bin/sh", "/bin/sh", "-c", pipeOutput, NULL);
869             fprintf(stderr, _("exec failed\n"));
870         }
871
872         (void) close(p[0]);
873         (void) dup2(p[1], STDOUT_FILENO);
874         (void) close(p[1]);
875     }
876         
877     switch (bigMode) {
878 #ifdef  IAM_RPMDB
879     case MODE_INITDB:
880         (void) rpmdbInit(rootdir, 0644);
881         break;
882
883     case MODE_REBUILDDB:
884         ec = rpmdbRebuild(rootdir);
885         break;
886     case MODE_VERIFYDB:
887         ec = rpmdbVerify(rootdir);
888         break;
889 #endif  /* IAM_RPMDB */
890
891 #ifdef  IAM_RPMBT
892     case MODE_REBUILD:
893     case MODE_RECOMPILE:
894       { const char * pkg;
895         while (!rpmIsVerbose())
896             rpmIncreaseVerbosity();
897
898         if (!poptPeekArg(optCon))
899             argerror(_("no packages files given for rebuild"));
900
901         ba->buildAmount = RPMBUILD_PREP | RPMBUILD_BUILD | RPMBUILD_INSTALL;
902         if (bigMode == MODE_REBUILD) {
903             ba->buildAmount |= RPMBUILD_PACKAGEBINARY;
904             ba->buildAmount |= RPMBUILD_RMSOURCE;
905             ba->buildAmount |= RPMBUILD_RMSPEC;
906             ba->buildAmount |= RPMBUILD_CLEAN;
907             ba->buildAmount |= RPMBUILD_RMBUILD;
908         }
909
910         while ((pkg = poptGetArg(optCon))) {
911             const char * specFile = NULL;
912             char * cookie = NULL;
913
914             ec = rpmInstallSource("", pkg, &specFile, &cookie);
915             if (ec)
916                 /*@loopbreak@*/ break;
917
918             ba->rootdir = rootdir;
919             ec = build(specFile, ba, passPhrase, cookie, rcfile);
920             free(cookie);
921             cookie = NULL;
922             free((void *)specFile);
923             specFile = NULL;
924
925             if (ec)
926                 /*@loopbreak@*/ break;
927         }
928       } break;
929
930       case MODE_BUILD:
931       case MODE_TARBUILD:
932       { const char * pkg;
933         while (!rpmIsVerbose())
934             rpmIncreaseVerbosity();
935        
936         switch (ba->buildChar) {
937         case 'a':
938             ba->buildAmount |= RPMBUILD_PACKAGESOURCE;
939             /*@fallthrough@*/
940         case 'b':
941             ba->buildAmount |= RPMBUILD_PACKAGEBINARY;
942             ba->buildAmount |= RPMBUILD_CLEAN;
943             /*@fallthrough@*/
944         case 'i':
945             ba->buildAmount |= RPMBUILD_INSTALL;
946             if ((ba->buildChar == 'i') && ba->shortCircuit)
947                 break;
948             /*@fallthrough@*/
949         case 'c':
950             ba->buildAmount |= RPMBUILD_BUILD;
951             if ((ba->buildChar == 'c') && ba->shortCircuit)
952                 break;
953             /*@fallthrough@*/
954         case 'p':
955             ba->buildAmount |= RPMBUILD_PREP;
956             break;
957             
958         case 'l':
959             ba->buildAmount |= RPMBUILD_FILECHECK;
960             break;
961         case 's':
962             ba->buildAmount |= RPMBUILD_PACKAGESOURCE;
963             break;
964         }
965
966         if (!poptPeekArg(optCon)) {
967             if (bigMode == MODE_BUILD)
968                 argerror(_("no spec files given for build"));
969             else
970                 argerror(_("no tar files given for build"));
971         }
972
973         while ((pkg = poptGetArg(optCon))) {
974             ba->rootdir = rootdir;
975             ec = build(pkg, ba, passPhrase, NULL, rcfile);
976             if (ec)
977                 /*@loopbreak@*/ break;
978             rpmFreeMacros(NULL);
979             (void) rpmReadConfigFiles(rcfile, NULL);
980         }
981       } break;
982 #endif  /* IAM_RPMBT */
983
984 #ifdef  IAM_RPMEIU
985     case MODE_ERASE:
986         if (!poptPeekArg(optCon))
987             argerror(_("no packages given for uninstall"));
988
989         if (ia->noDeps) ia->eraseInterfaceFlags |= UNINSTALL_NODEPS;
990
991         ec = rpmErase(rootdir, (const char **)poptGetArgs(optCon), 
992                          ia->transFlags, ia->eraseInterfaceFlags);
993         break;
994
995     case MODE_INSTALL:
996
997         if (!poptPeekArg(optCon))
998             argerror(_("no packages given for install"));
999
1000         /* RPMTRANS_FLAG_BUILD_PROBS */
1001         /* RPMTRANS_FLAG_KEEPOBSOLETE */
1002
1003         if (!ia->incldocs) {
1004             if (ia->transFlags & RPMTRANS_FLAG_NODOCS)
1005                 ;
1006             else if (rpmExpandNumeric("%{_excludedocs}"))
1007                 ia->transFlags |= RPMTRANS_FLAG_NODOCS;
1008         }
1009
1010         if (ia->noDeps) ia->installInterfaceFlags |= INSTALL_NODEPS;
1011
1012         /* we've already ensured !(!ia->prefix && !ia->relocations) */
1013         if (ia->prefix) {
1014             ia->relocations = xmalloc(2 * sizeof(*ia->relocations));
1015             ia->relocations[0].oldPath = NULL;   /* special case magic */
1016             ia->relocations[0].newPath = ia->prefix;
1017             ia->relocations[1].oldPath = ia->relocations[1].newPath = NULL;
1018         } else if (ia->relocations) {
1019             ia->relocations = xrealloc(ia->relocations, 
1020                         sizeof(*ia->relocations) * (ia->numRelocations + 1));
1021             ia->relocations[ia->numRelocations].oldPath = NULL;
1022             ia->relocations[ia->numRelocations].newPath = NULL;
1023         }
1024
1025         ec += rpmInstall(rootdir, (const char **)poptGetArgs(optCon), 
1026                         ia->transFlags, ia->installInterfaceFlags, ia->probFilter,
1027                         ia->relocations);
1028         break;
1029
1030     case MODE_ROLLBACK:
1031         ia->rootdir = rootdir;
1032         ec += rpmRollback(ia, (const char **)poptGetArgs(optCon));
1033         break;
1034
1035 #endif  /* IAM_RPMEIU */
1036
1037 #ifdef  IAM_RPMQV
1038     case MODE_QUERY:
1039       { const char * pkg;
1040
1041         qva->qva_prefix = rootdir;
1042         if (qva->qva_source == RPMQV_ALL) {
1043 #ifdef  DYING
1044             if (poptPeekArg(optCon))
1045                 argerror(_("extra arguments given for query of all packages"));
1046 #else
1047             const char ** av = poptGetArgs(optCon);
1048 #endif
1049             /*@-nullpass@*/     /* FIX: av can be NULL */
1050             ec = rpmQuery(qva, RPMQV_ALL, (const char *) av);
1051             /*@=nullpass@*/
1052         } else {
1053             if (!poptPeekArg(optCon))
1054                 argerror(_("no arguments given for query"));
1055             while ((pkg = poptGetArg(optCon)))
1056                 ec += rpmQuery(qva, qva->qva_source, pkg);
1057         }
1058       } break;
1059
1060     case MODE_VERIFY:
1061       { const char * pkg;
1062         rpmVerifyFlags verifyFlags = VERIFY_ALL;
1063
1064         verifyFlags &= ~qva->qva_flags;
1065         qva->qva_flags = (rpmQueryFlags) verifyFlags;
1066         qva->qva_prefix = rootdir;
1067
1068         if (qva->qva_source == RPMQV_ALL) {
1069             if (poptPeekArg(optCon))
1070                 argerror(_("extra arguments given for verify of all packages"));
1071             ec = rpmVerify(qva, RPMQV_ALL, NULL);
1072         } else {
1073             if (!poptPeekArg(optCon))
1074                 argerror(_("no arguments given for verify"));
1075             while ((pkg = poptGetArg(optCon)))
1076                 ec += rpmVerify(qva, qva->qva_source, pkg);
1077         }
1078       } break;
1079
1080     case MODE_QUERYTAGS:
1081         if (argc != 2)
1082             argerror(_("unexpected arguments to --querytags "));
1083
1084         rpmDisplayQueryTags(stdout);
1085         break;
1086 #endif  /* IAM_RPMQV */
1087
1088 #ifdef IAM_RPMK
1089     case MODE_CHECKSIG:
1090         if (!poptPeekArg(optCon))
1091             argerror(_("no packages given for signature check"));
1092         ec = rpmCheckSig(ka->checksigFlags,
1093                         (const char **)poptGetArgs(optCon));
1094         /* XXX don't overflow single byte exit status */
1095         if (ec > 255) ec = 255;
1096         break;
1097
1098     case MODE_RESIGN:
1099         if (!poptPeekArg(optCon))
1100             argerror(_("no packages given for signing"));
1101         ec = rpmReSign(ka->addSign, passPhrase,
1102                         (const char **)poptGetArgs(optCon));
1103         /* XXX don't overflow single byte exit status */
1104         if (ec > 255) ec = 255;
1105         break;
1106 #endif  /* IAM_RPMK */
1107         
1108 #if !defined(IAM_RPMQV)
1109     case MODE_QUERY:
1110     case MODE_VERIFY:
1111     case MODE_QUERYTAGS:
1112 #endif
1113 #if !defined(IAM_RPMK)
1114     case MODE_CHECKSIG:
1115     case MODE_RESIGN:
1116 #endif
1117 #if !defined(IAM_RPMDB)
1118     case MODE_INITDB:
1119     case MODE_REBUILDDB:
1120     case MODE_VERIFYDB:
1121 #endif
1122 #if !defined(IAM_RPMBT)
1123     case MODE_BUILD:
1124     case MODE_REBUILD:
1125     case MODE_RECOMPILE:
1126     case MODE_TARBUILD:
1127 #endif
1128 #if !defined(IAM_RPMEIU)
1129     case MODE_INSTALL:
1130     case MODE_ERASE:
1131     case MODE_ROLLBACK:
1132 #endif
1133     case MODE_UNKNOWN:
1134         if (!showVersion && !help && !noUsageMsg) printUsage();
1135         break;
1136     }
1137
1138 #if defined(IAM_RPMBT) || defined(IAM_RPMK)
1139 exit:
1140 #endif  /* IAM_RPMBT || IAM_RPMK */
1141     optCon = poptFreeContext(optCon);
1142     rpmFreeMacros(NULL);
1143     rpmFreeMacros(&rpmCLIMacroContext);
1144     rpmFreeRpmrc();
1145
1146     if (pipeChild) {
1147         (void) fclose(stdout);
1148         (void) waitpid(pipeChild, &status, 0);
1149     }
1150
1151     /* keeps memory leak checkers quiet */
1152     freeNames();
1153     freeFilesystems();
1154     urlFreeCache();
1155
1156 #ifdef  IAM_RPMQV
1157     qva->qva_queryFormat = _free(qva->qva_queryFormat);
1158 #endif
1159
1160 #ifdef  IAM_RPMBT
1161     ba->buildRootOverride = _free(ba->buildRootOverride);
1162     ba->targets = _free(ba->targets);
1163 #endif
1164
1165 #ifdef  IAM_RPMEIU
1166     ia->relocations = _free(ia->relocations);
1167 #endif
1168
1169 #if HAVE_MCHECK_H && HAVE_MTRACE
1170     muntrace();   /* Trace malloc only if MALLOC_TRACE=mtrace-output-file. */
1171 #endif
1172     /*@-globstate@*/
1173     return ec;
1174     /*@=globstate@*/
1175 }