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