Argh. Realize we already have equivalents of initCli() and finishCli()
[platform/upstream/rpm.git] / rpmqv.c
1 #include "system.h"
2 const char *__progname;
3
4 #define _AUTOHELP
5
6 #include <rpm/rpmcli.h>
7 #include <rpm/rpmlib.h>                 /* RPMSIGTAG, rpmReadPackageFile .. */
8 #include <rpm/rpmbuild.h>
9 #include <rpm/rpmlog.h>
10 #include <rpm/rpmdb.h>
11 #include <rpm/rpmps.h>
12 #include <rpm/rpmts.h>
13
14 #if defined(IAM_RPMK)
15 #include "lib/signature.h"
16 #endif
17 #include "cliutils.h"
18
19 #include "debug.h"
20
21 enum modes {
22
23     MODE_QUERY          = (1 <<  0),
24     MODE_VERIFY         = (1 <<  3),
25 #define MODES_QV (MODE_QUERY | MODE_VERIFY)
26
27     MODE_INSTALL        = (1 <<  1),
28     MODE_ERASE          = (1 <<  2),
29 #define MODES_IE (MODE_INSTALL | MODE_ERASE)
30
31     MODE_CHECKSIG       = (1 <<  6),
32     MODE_RESIGN         = (1 <<  7),
33 #define MODES_K  (MODE_CHECKSIG | MODE_RESIGN)
34
35     MODE_INITDB         = (1 << 10),
36     MODE_REBUILDDB      = (1 << 12),
37     MODE_VERIFYDB       = (1 << 13),
38 #define MODES_DB (MODE_INITDB | MODE_REBUILDDB | MODE_VERIFYDB)
39
40
41     MODE_UNKNOWN        = 0
42 };
43
44 #define MODES_FOR_DBPATH        (MODES_IE | MODES_QV | MODES_DB)
45 #define MODES_FOR_NODEPS        (MODES_IE | MODE_VERIFY)
46 #define MODES_FOR_TEST          (MODES_IE)
47 #define MODES_FOR_ROOT          (MODES_IE | MODES_QV | MODES_DB | MODES_K)
48
49 static int quiet;
50
51 /* the structure describing the options we take and the defaults */
52 static struct poptOption optionsTable[] = {
53
54 #ifdef  IAM_RPMQV
55  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmQVSourcePoptTable, 0,
56         N_("Query/Verify package selection options:"),
57         NULL },
58  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmQueryPoptTable, 0,
59         N_("Query options (with -q or --query):"),
60         NULL },
61  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmVerifyPoptTable, 0,
62         N_("Verify options (with -V or --verify):"),
63         NULL },
64 #endif  /* IAM_RPMQV */
65
66 #ifdef  IAM_RPMK
67  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmSignPoptTable, 0,
68         N_("Signature options:"),
69         NULL },
70 #endif  /* IAM_RPMK */
71
72 #ifdef  IAM_RPMDB
73  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmDatabasePoptTable, 0,
74         N_("Database options:"),
75         NULL },
76 #endif  /* IAM_RPMDB */
77
78 #ifdef  IAM_RPMEIU
79  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmInstallPoptTable, 0,
80         N_("Install/Upgrade/Erase options:"),
81         NULL },
82 #endif  /* IAM_RPMEIU */
83
84  { "quiet", '\0', POPT_ARGFLAG_DOC_HIDDEN, &quiet, 0, NULL, NULL},
85
86  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmcliAllPoptTable, 0,
87         N_("Common options for all rpm modes and executables:"),
88         NULL },
89
90    POPT_AUTOALIAS
91    POPT_AUTOHELP
92    POPT_TABLEEND
93 };
94
95 int main(int argc, char *argv[])
96 {
97     rpmts ts = NULL;
98     enum modes bigMode = MODE_UNKNOWN;
99
100 #if defined(IAM_RPMQV)
101     QVA_t qva = &rpmQVKArgs;
102 #endif
103
104 #ifdef  IAM_RPMEIU
105    struct rpmInstallArguments_s * ia = &rpmIArgs;
106 #endif
107
108 #if defined(IAM_RPMDB)
109    struct rpmDatabaseArguments_s * da = &rpmDBArgs;
110 #endif
111
112 #if defined(IAM_RPMK)
113    QVA_t ka = &rpmQVKArgs;
114 #endif
115
116 #if defined(IAM_RPMK)
117     char * passPhrase = "";
118 #endif
119
120     poptContext optCon;
121     int ec = 0;
122 #ifdef  IAM_RPMEIU
123     int i;
124 #endif
125
126     optCon = rpmcliInit(argc, argv, optionsTable);
127
128     /* Set the major mode based on argv[0] */
129 #ifdef  IAM_RPMQV
130     if (rstreq(__progname, "rpmquery")) bigMode = MODE_QUERY;
131     if (rstreq(__progname, "rpmverify")) bigMode = MODE_VERIFY;
132 #endif
133
134 #if defined(IAM_RPMQV)
135     /* Jumpstart option from argv[0] if necessary. */
136     switch (bigMode) {
137     case MODE_QUERY:    qva->qva_mode = 'q';    break;
138     case MODE_VERIFY:   qva->qva_mode = 'V';    break;
139     case MODE_CHECKSIG: qva->qva_mode = 'K';    break;
140     case MODE_RESIGN:   qva->qva_mode = 'R';    break;
141     case MODE_INSTALL:
142     case MODE_ERASE:
143     case MODE_INITDB:
144     case MODE_REBUILDDB:
145     case MODE_VERIFYDB:
146     case MODE_UNKNOWN:
147     default:
148         break;
149     }
150 #endif
151
152 #ifdef  IAM_RPMDB
153   if (bigMode == MODE_UNKNOWN || (bigMode & MODES_DB)) {
154     if (da->init) {
155         if (bigMode != MODE_UNKNOWN) 
156             argerror(_("only one major mode may be specified"));
157         else
158             bigMode = MODE_INITDB;
159     } else
160     if (da->rebuild) {
161         if (bigMode != MODE_UNKNOWN) 
162             argerror(_("only one major mode may be specified"));
163         else
164             bigMode = MODE_REBUILDDB;
165     } else
166     if (da->verify) {
167         if (bigMode != MODE_UNKNOWN) 
168             argerror(_("only one major mode may be specified"));
169         else
170             bigMode = MODE_VERIFYDB;
171     }
172   }
173 #endif  /* IAM_RPMDB */
174
175 #ifdef  IAM_RPMQV
176   if (bigMode == MODE_UNKNOWN || (bigMode & MODES_QV)) {
177     switch (qva->qva_mode) {
178     case 'q':   bigMode = MODE_QUERY;           break;
179     case 'V':   bigMode = MODE_VERIFY;          break;
180     }
181
182     if (qva->qva_sourceCount) {
183         if (qva->qva_sourceCount > 2)
184             argerror(_("one type of query/verify may be performed at a "
185                         "time"));
186     }
187     if (qva->qva_flags && (bigMode & ~MODES_QV)) 
188         argerror(_("unexpected query flags"));
189
190     if (qva->qva_queryFormat && (bigMode & ~MODES_QV)) 
191         argerror(_("unexpected query format"));
192
193     if (qva->qva_source != RPMQV_PACKAGE && (bigMode & ~MODES_QV)) 
194         argerror(_("unexpected query source"));
195   }
196 #endif  /* IAM_RPMQV */
197
198 #ifdef  IAM_RPMEIU
199   if (bigMode == MODE_UNKNOWN || (bigMode & MODES_IE))
200     {   int iflags = (ia->installInterfaceFlags &
201                 (INSTALL_UPGRADE|INSTALL_FRESHEN|INSTALL_INSTALL));
202         int eflags = (ia->installInterfaceFlags & INSTALL_ERASE);
203
204         if (iflags & eflags)
205             argerror(_("only one major mode may be specified"));
206         else if (iflags)
207             bigMode = MODE_INSTALL;
208         else if (eflags)
209             bigMode = MODE_ERASE;
210     }
211 #endif  /* IAM_RPMEIU */
212
213 #ifdef  IAM_RPMK
214   if (bigMode == MODE_UNKNOWN || (bigMode & MODES_K)) {
215         switch (ka->qva_mode) {
216         case RPMSIGN_NONE:
217             ka->sign = 0;
218             break;
219         case RPMSIGN_IMPORT_PUBKEY:
220         case RPMSIGN_CHK_SIGNATURE:
221             bigMode = MODE_CHECKSIG;
222             ka->sign = 0;
223             break;
224         case RPMSIGN_ADD_SIGNATURE:
225         case RPMSIGN_NEW_SIGNATURE:
226         case RPMSIGN_DEL_SIGNATURE:
227             bigMode = MODE_RESIGN;
228             ka->sign = (ka->qva_mode != RPMSIGN_DEL_SIGNATURE);
229             break;
230         }
231   }
232 #endif  /* IAM_RPMK */
233
234 #if defined(IAM_RPMEIU)
235     if (!( bigMode == MODE_INSTALL ) &&
236 (ia->probFilter & (RPMPROB_FILTER_REPLACEPKG | RPMPROB_FILTER_OLDPACKAGE)))
237         argerror(_("only installation, upgrading, rmsource and rmspec may be forced"));
238     if (bigMode != MODE_INSTALL && (ia->probFilter & RPMPROB_FILTER_FORCERELOCATE))
239         argerror(_("files may only be relocated during package installation"));
240
241     if (ia->relocations && ia->prefix)
242         argerror(_("cannot use --prefix with --relocate or --excludepath"));
243
244     if (bigMode != MODE_INSTALL && ia->relocations)
245         argerror(_("--relocate and --excludepath may only be used when installing new packages"));
246
247     if (bigMode != MODE_INSTALL && ia->prefix)
248         argerror(_("--prefix may only be used when installing new packages"));
249
250     if (ia->prefix && ia->prefix[0] != '/') 
251         argerror(_("arguments to --prefix must begin with a /"));
252
253     if (bigMode != MODE_INSTALL && (ia->installInterfaceFlags & INSTALL_HASH))
254         argerror(_("--hash (-h) may only be specified during package "
255                         "installation"));
256
257     if (bigMode != MODE_INSTALL && (ia->installInterfaceFlags & INSTALL_PERCENT))
258         argerror(_("--percent may only be specified during package "
259                         "installation"));
260
261     if (bigMode != MODE_INSTALL && (ia->probFilter & RPMPROB_FILTER_REPLACEPKG))
262         argerror(_("--replacepkgs may only be specified during package "
263                         "installation"));
264
265     if (bigMode != MODE_INSTALL && (ia->transFlags & RPMTRANS_FLAG_NODOCS))
266         argerror(_("--excludedocs may only be specified during package "
267                    "installation"));
268
269     if (bigMode != MODE_INSTALL && ia->incldocs)
270         argerror(_("--includedocs may only be specified during package "
271                    "installation"));
272
273     if (ia->incldocs && (ia->transFlags & RPMTRANS_FLAG_NODOCS))
274         argerror(_("only one of --excludedocs and --includedocs may be "
275                  "specified"));
276   
277     if (bigMode != MODE_INSTALL && (ia->probFilter & RPMPROB_FILTER_IGNOREARCH))
278         argerror(_("--ignorearch may only be specified during package "
279                    "installation"));
280
281     if (bigMode != MODE_INSTALL && (ia->probFilter & RPMPROB_FILTER_IGNOREOS))
282         argerror(_("--ignoreos may only be specified during package "
283                    "installation"));
284
285     if (bigMode != MODE_INSTALL && bigMode != MODE_ERASE &&
286         (ia->probFilter & (RPMPROB_FILTER_DISKSPACE|RPMPROB_FILTER_DISKNODES)))
287         argerror(_("--ignoresize may only be specified during package "
288                    "installation"));
289
290     if ((ia->installInterfaceFlags & UNINSTALL_ALLMATCHES) && bigMode != MODE_ERASE)
291         argerror(_("--allmatches may only be specified during package "
292                    "erasure"));
293
294     if ((ia->transFlags & RPMTRANS_FLAG_ALLFILES) && bigMode != MODE_INSTALL)
295         argerror(_("--allfiles may only be specified during package "
296                    "installation"));
297
298     if ((ia->transFlags & RPMTRANS_FLAG_JUSTDB) &&
299         bigMode != MODE_INSTALL && bigMode != MODE_ERASE)
300         argerror(_("--justdb may only be specified during package "
301                    "installation and erasure"));
302
303     if (bigMode != MODE_INSTALL && bigMode != MODE_ERASE && bigMode != MODE_VERIFY &&
304         (ia->transFlags & (RPMTRANS_FLAG_NOSCRIPTS | _noTransScripts | _noTransTriggers)))
305         argerror(_("script disabling options may only be specified during "
306                    "package installation and erasure"));
307
308     if (bigMode != MODE_INSTALL && bigMode != MODE_ERASE && bigMode != MODE_VERIFY &&
309         (ia->transFlags & (RPMTRANS_FLAG_NOTRIGGERS | _noTransTriggers)))
310         argerror(_("trigger disabling options may only be specified during "
311                    "package installation and erasure"));
312
313     if (ia->noDeps & (bigMode & ~MODES_FOR_NODEPS))
314         argerror(_("--nodeps may only be specified during package "
315                    "building, rebuilding, recompilation, installation,"
316                    "erasure, and verification"));
317
318     if ((ia->transFlags & RPMTRANS_FLAG_TEST) && (bigMode & ~MODES_FOR_TEST))
319         argerror(_("--test may only be specified during package installation, "
320                  "erasure, and building"));
321 #endif  /* IAM_RPMEIU */
322
323     if (rpmcliRootDir && rpmcliRootDir[1] && (bigMode & ~MODES_FOR_ROOT))
324         argerror(_("--root (-r) may only be specified during "
325                  "installation, erasure, querying, and "
326                  "database rebuilds"));
327
328     if (rpmcliRootDir && rpmcliRootDir[0] != '/') {
329         argerror(_("arguments to --root (-r) must begin with a /"));
330     }
331
332     if (quiet)
333         rpmSetVerbosity(RPMLOG_WARNING);
334
335 #if defined(IAM_RPMK)
336     if (ka->sign) {
337         if (bigMode == MODE_RESIGN) {
338             const char ** av;
339             struct stat sb;
340             int errors = 0;
341
342             if ((av = poptGetArgs(optCon)) == NULL) {
343                 fprintf(stderr, _("no files to sign\n"));
344                 errors++;
345             } else
346             while (*av) {
347                 if (stat(*av, &sb)) {
348                     fprintf(stderr, _("cannot access file %s\n"), *av);
349                     errors++;
350                 }
351                 av++;
352             }
353
354             if (errors) {
355                 ec = errors;
356                 goto exit;
357             }
358
359             if (poptPeekArg(optCon)) {
360                 int sigTag = rpmLookupSignatureType(RPMLOOKUPSIG_QUERY);
361                 switch (sigTag) {
362                   case 0:
363                     break;
364                   case RPMSIGTAG_PGP:
365                   case RPMSIGTAG_GPG:
366                   case RPMSIGTAG_DSA:
367                   case RPMSIGTAG_RSA:
368                     passPhrase = rpmGetPassPhrase(_("Enter pass phrase: "), sigTag);
369                     if (passPhrase == NULL) {
370                         fprintf(stderr, _("Pass phrase check failed\n"));
371                         ec = EXIT_FAILURE;
372                         goto exit;
373                     }
374                     fprintf(stderr, _("Pass phrase is good.\n"));
375                     passPhrase = xstrdup(passPhrase);
376                     break;
377                   default:
378                     fprintf(stderr,
379                             _("Invalid %%_signature spec in macro file.\n"));
380                     ec = EXIT_FAILURE;
381                     goto exit;
382                     break;
383                 }
384             }
385         } else {
386             argerror(_("--sign may only be used during package building"));
387         }
388     } else {
389         /* Make rpmLookupSignatureType() return 0 ("none") from now on */
390         (void) rpmLookupSignatureType(RPMLOOKUPSIG_DISABLE);
391     }
392 #endif  /* IAM_RPMK */
393
394     if (rpmcliPipeOutput && initPipe())
395         exit(EXIT_FAILURE);
396         
397     ts = rpmtsCreate();
398     (void) rpmtsSetRootDir(ts, rpmcliRootDir);
399     switch (bigMode) {
400 #ifdef  IAM_RPMDB
401     case MODE_INITDB:
402         ec = rpmtsInitDB(ts, 0644);
403         break;
404
405     case MODE_REBUILDDB:
406     {   rpmVSFlags vsflags = rpmExpandNumeric("%{_vsflags_rebuilddb}");
407         rpmVSFlags ovsflags = rpmtsSetVSFlags(ts, vsflags);
408         ec = rpmtsRebuildDB(ts);
409         vsflags = rpmtsSetVSFlags(ts, ovsflags);
410     }   break;
411     case MODE_VERIFYDB:
412         ec = rpmtsVerifyDB(ts);
413         break;
414 #endif  /* IAM_RPMDB */
415
416 #ifdef  IAM_RPMEIU
417     case MODE_ERASE:
418         if (ia->noDeps) ia->installInterfaceFlags |= UNINSTALL_NODEPS;
419
420         if (!poptPeekArg(optCon)) {
421             argerror(_("no packages given for erase"));
422         } else {
423             ec += rpmErase(ts, ia, (ARGV_const_t) poptGetArgs(optCon));
424         }
425         break;
426
427     case MODE_INSTALL:
428
429         /* RPMTRANS_FLAG_KEEPOBSOLETE */
430
431         if (!ia->incldocs) {
432             if (ia->transFlags & RPMTRANS_FLAG_NODOCS) {
433                 ;
434             } else if (rpmExpandNumeric("%{_excludedocs}"))
435                 ia->transFlags |= RPMTRANS_FLAG_NODOCS;
436         }
437
438         if (ia->noDeps) ia->installInterfaceFlags |= INSTALL_NODEPS;
439
440         /* we've already ensured !(!ia->prefix && !ia->relocations) */
441         if (ia->prefix) {
442             ia->relocations = xmalloc(2 * sizeof(*ia->relocations));
443             ia->relocations[0].oldPath = NULL;   /* special case magic */
444             ia->relocations[0].newPath = ia->prefix;
445             ia->relocations[1].oldPath = NULL;
446             ia->relocations[1].newPath = NULL;
447         } else if (ia->relocations) {
448             ia->relocations = xrealloc(ia->relocations, 
449                         sizeof(*ia->relocations) * (ia->numRelocations + 1));
450             ia->relocations[ia->numRelocations].oldPath = NULL;
451             ia->relocations[ia->numRelocations].newPath = NULL;
452         }
453
454         if (!poptPeekArg(optCon)) {
455             argerror(_("no packages given for install"));
456         } else {
457             /* FIX: ia->relocations[0].newPath undefined */
458             ec += rpmInstall(ts, ia, (ARGV_t) poptGetArgs(optCon));
459         }
460         break;
461
462 #endif  /* IAM_RPMEIU */
463
464 #ifdef  IAM_RPMQV
465     case MODE_QUERY:
466         if (!poptPeekArg(optCon) && !(qva->qva_source == RPMQV_ALL))
467             argerror(_("no arguments given for query"));
468
469         qva->qva_specQuery = rpmspecQuery;
470         ec = rpmcliQuery(ts, qva, (ARGV_const_t) poptGetArgs(optCon));
471         qva->qva_specQuery = NULL;
472         break;
473
474     case MODE_VERIFY:
475     {   rpmVerifyFlags verifyFlags = VERIFY_ALL;
476
477         verifyFlags &= ~qva->qva_flags;
478         qva->qva_flags = (rpmQueryFlags) verifyFlags;
479
480         if (!poptPeekArg(optCon) && !(qva->qva_source == RPMQV_ALL))
481             argerror(_("no arguments given for verify"));
482         ec = rpmcliVerify(ts, qva, (ARGV_const_t) poptGetArgs(optCon));
483     }   break;
484 #endif  /* IAM_RPMQV */
485
486 #ifdef IAM_RPMK
487     case MODE_CHECKSIG:
488     {   rpmVerifyFlags verifyFlags =
489                 (VERIFY_FILEDIGEST|VERIFY_DIGEST|VERIFY_SIGNATURE);
490
491         verifyFlags &= ~ka->qva_flags;
492         ka->qva_flags = (rpmQueryFlags) verifyFlags;
493     }  
494     case MODE_RESIGN:
495         if (!poptPeekArg(optCon))
496             argerror(_("no arguments given"));
497         ka->passPhrase = passPhrase;
498         ec = rpmcliSign(ts, ka, (ARGV_const_t) poptGetArgs(optCon));
499         break;
500 #endif  /* IAM_RPMK */
501         
502 #if !defined(IAM_RPMQV)
503     case MODE_QUERY:
504     case MODE_VERIFY:
505 #endif
506 #if !defined(IAM_RPMK)
507     case MODE_CHECKSIG:
508     case MODE_RESIGN:
509 #endif
510 #if !defined(IAM_RPMDB)
511     case MODE_INITDB:
512     case MODE_REBUILDDB:
513     case MODE_VERIFYDB:
514 #endif
515 #if !defined(IAM_RPMEIU)
516     case MODE_INSTALL:
517     case MODE_ERASE:
518 #endif
519     case MODE_UNKNOWN:
520         if (poptPeekArg(optCon) != NULL || argc <= 1 || rpmIsVerbose()) {
521             printUsage(optCon, stderr, 0);
522             ec = argc;
523         }
524         break;
525     }
526
527 exit:
528     ts = rpmtsFree(ts);
529     finishPipe();
530
531 #ifdef  IAM_RPMQV
532     qva->qva_queryFormat = _free(qva->qva_queryFormat);
533 #endif
534
535 #ifdef  IAM_RPMEIU
536     if (ia->relocations != NULL)
537     for (i = 0; i < ia->numRelocations; i++)
538         ia->relocations[i].oldPath = _free(ia->relocations[i].oldPath);
539     ia->relocations = _free(ia->relocations);
540 #endif
541
542     rpmcliFini(optCon);
543
544     return RETVAL(ec);
545 }