3337f08a848de53a58a1587b7f59abccbd6651cc
[platform/upstream/rpm.git] / lib / query.c
1 /** \ingroup rpmcli
2  * \file lib/query.c
3  * Display tag values from package metadata.
4  */
5
6 #include "system.h"
7
8 #include <inttypes.h>
9
10 #include <rpm/rpmcli.h>
11 #include <rpm/header.h>
12 #include <rpm/rpmdb.h>
13 #include <rpm/rpmfi.h>
14 #include <rpm/rpmgi.h>
15 #include <rpm/rpmts.h>
16 #include <rpm/rpmlog.h>
17 #include <rpm/rpmfileutil.h>    /* rpmCleanPath */
18
19 #include "lib/manifest.h"
20
21 #include "debug.h"
22
23
24 /**
25  */
26 static void printFileInfo(const char * name,
27                           rpm_loff_t size, unsigned short mode,
28                           unsigned int mtime,
29                           unsigned short rdev, unsigned int nlink,
30                           const char * owner, const char * group,
31                           const char * linkto)
32 {
33     char sizefield[21];
34     char ownerfield[8+1], groupfield[8+1];
35     char timefield[100];
36     time_t when = mtime;  /* important if sizeof(int32_t) ! sizeof(time_t) */
37     struct tm * tm;
38     static time_t now;
39     static struct tm nowtm;
40     char * perms = rpmPermsString(mode);
41     char *link = NULL;
42
43     /* On first call, grab snapshot of now */
44     if (now == 0) {
45         now = time(NULL);
46         tm = localtime(&now);
47         if (tm) nowtm = *tm;    /* structure assignment */
48     }
49
50     rstrlcpy(ownerfield, owner, sizeof(ownerfield));
51     rstrlcpy(groupfield, group, sizeof(groupfield));
52
53     /* this is normally right */
54     snprintf(sizefield, sizeof(sizefield), "%20" PRIu64, size);
55
56     /* this knows too much about dev_t */
57
58     if (S_ISLNK(mode)) {
59         rasprintf(&link, "%s -> %s", name, linkto);
60     } else if (S_ISCHR(mode)) {
61         perms[0] = 'c';
62         snprintf(sizefield, sizeof(sizefield), "%3u, %3u", ((unsigned)(rdev >> 8) & 0xff),
63                         ((unsigned)rdev & 0xff));
64     } else if (S_ISBLK(mode)) {
65         perms[0] = 'b';
66         snprintf(sizefield, sizeof(sizefield), "%3u, %3u", ((unsigned)(rdev >> 8) & 0xff),
67                         ((unsigned)rdev & 0xff));
68     }
69
70     /* Convert file mtime to display format */
71     tm = localtime(&when);
72     timefield[0] = '\0';
73     if (tm != NULL)
74     {   const char *fmt;
75         if (now > when + 6L * 30L * 24L * 60L * 60L ||  /* Old. */
76             now < when - 60L * 60L)                     /* In the future.  */
77         {
78         /* The file is fairly old or in the future.
79          * POSIX says the cutoff is 6 months old;
80          * approximate this by 6*30 days.
81          * Allow a 1 hour slop factor for what is considered "the future",
82          * to allow for NFS server/client clock disagreement.
83          * Show the year instead of the time of day.
84          */        
85             fmt = "%b %e  %Y";
86         } else {
87             fmt = "%b %e %H:%M";
88         }
89         (void)strftime(timefield, sizeof(timefield) - 1, fmt, tm);
90     }
91
92     rpmlog(RPMLOG_NOTICE, "%s %4d %-8s%-8s %10s %s %s\n", perms,
93         (int)nlink, ownerfield, groupfield, sizefield, timefield, 
94         link ? link : name);
95     free(perms);
96     free(link);
97 }
98
99 int showQueryPackage(QVA_t qva, rpmts ts, Header h)
100 {
101     rpmfi fi = NULL;
102     rpmfiFlags fiflags =  (RPMFI_NOHEADER | RPMFI_FLAGS_QUERY);
103     int rc = 0;         /* XXX FIXME: need real return code */
104
105     if (qva->qva_queryFormat != NULL) {
106         const char *errstr;
107         char *str = headerFormat(h, qva->qva_queryFormat, &errstr);
108
109         if ( str != NULL ) {
110             rpmlog(RPMLOG_NOTICE, "%s", str);
111             free(str);
112         } else {
113             rpmlog(RPMLOG_ERR, _("incorrect format: %s\n"), errstr);
114         }
115     }
116
117     if (!(qva->qva_flags & QUERY_FOR_LIST))
118         goto exit;
119
120     if (!(qva->qva_flags & QUERY_FOR_DUMPFILES))
121         fiflags |= RPMFI_NOFILEDIGESTS;
122
123     fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, fiflags);
124     if (rpmfiFC(fi) <= 0) {
125         rpmlog(RPMLOG_NOTICE, _("(contains no files)\n"));
126         goto exit;
127     }
128
129     fi = rpmfiInit(fi, 0);
130     while (rpmfiNext(fi) >= 0) {
131         rpmfileAttrs fflags = rpmfiFFlags(fi);
132         rpm_mode_t fmode = rpmfiFMode(fi);
133         rpm_rdev_t frdev = rpmfiFRdev(fi);
134         rpm_time_t fmtime = rpmfiFMtime(fi);
135         rpmfileState fstate = rpmfiFState(fi);
136         rpm_loff_t fsize = rpmfiFSize(fi);
137         const char *fn = rpmfiFN(fi);
138         const char *fuser = rpmfiFUser(fi);
139         const char *fgroup = rpmfiFGroup(fi);
140         const char *flink = rpmfiFLink(fi);
141         uint32_t fnlink = rpmfiFNlink(fi);
142         char *buf = NULL;
143
144         /* If querying only docs, skip non-doc files. */
145         if ((qva->qva_flags & QUERY_FOR_DOCS) && !(fflags & RPMFILE_DOC))
146             continue;
147
148         /* If querying only configs, skip non-config files. */
149         if ((qva->qva_flags & QUERY_FOR_CONFIG) && !(fflags & RPMFILE_CONFIG))
150             continue;
151
152         /* If not querying %ghost, skip ghost files. */
153         if ((qva->qva_fflags & RPMFILE_GHOST) && (fflags & RPMFILE_GHOST))
154             continue;
155
156         if (qva->qva_flags & QUERY_FOR_STATE) {
157             switch (fstate) {
158             case RPMFILE_STATE_NORMAL:
159                 rstrcat(&buf, _("normal        "));
160                 break;
161             case RPMFILE_STATE_REPLACED:
162                 rstrcat(&buf, _("replaced      "));
163                 break;
164             case RPMFILE_STATE_NOTINSTALLED:
165                 rstrcat(&buf, _("not installed "));
166                 break;
167             case RPMFILE_STATE_NETSHARED:
168                 rstrcat(&buf, _("net shared    "));
169                 break;
170             case RPMFILE_STATE_WRONGCOLOR:
171                 rstrcat(&buf, _("wrong color   "));
172                 break;
173             case RPMFILE_STATE_MISSING:
174                 rstrcat(&buf, _("(no state)    "));
175                 break;
176             default:
177                 rasprintf(&buf, _("(unknown %3d) "), fstate);
178                 break;
179             }
180         }
181
182         if (qva->qva_flags & QUERY_FOR_DUMPFILES) {
183             char *add, *fdigest;
184             fdigest = rpmfiFDigestHex(fi, NULL);
185             rasprintf(&add, "%s %" PRIu64 " %d %s 0%o ", 
186                       fn, fsize, fmtime, fdigest ? fdigest : "", fmode);
187             rstrcat(&buf, add);
188             free(add);
189             free(fdigest);
190
191             if (fuser && fgroup) {
192                 rasprintf(&add, "%s %s", fuser, fgroup);
193                 rstrcat(&buf, add);
194                 free(add);
195             } else {
196                 rpmlog(RPMLOG_ERR,
197                         _("package has not file owner/group lists\n"));
198             }
199
200             rasprintf(&add, " %s %s %u %s",
201                                  fflags & RPMFILE_CONFIG ? "1" : "0",
202                                  fflags & RPMFILE_DOC ? "1" : "0",
203                                  frdev,
204                                  (flink && *flink ? flink : "X"));
205             rpmlog(RPMLOG_NOTICE, "%s%s\n", buf, add);
206             free(add);
207         } else
208         if (!rpmIsVerbose()) {
209             rpmlog(RPMLOG_NOTICE, "%s%s\n", buf ? buf : "", fn);
210         }
211         else {
212
213             /* XXX Adjust directory link count and size for display output. */
214             if (S_ISDIR(fmode)) {
215                 fnlink++;
216                 fsize = 0;
217             }
218
219             if (fuser && fgroup) {
220                 if (buf) {
221                     rpmlog(RPMLOG_NOTICE, "%s", buf);
222                 }
223                 printFileInfo(fn, fsize, fmode, fmtime, frdev, fnlink,
224                                         fuser, fgroup, flink);
225             } else {
226                 rpmlog(RPMLOG_ERR,
227                         _("package has neither file owner or id lists\n"));
228             }
229         }
230         free(buf);
231     }
232
233     rc = 0;
234
235 exit:
236     fi = rpmfiFree(fi);
237     return rc;
238 }
239
240 void rpmDisplayQueryTags(FILE * fp)
241 {
242     static const char * const tagTypeNames[] = {
243         "", "char", "int8", "int16", "int32", "int64",
244         "string", "blob", "argv", "i18nstring"
245     };
246     const char *tname, *sname;
247     rpmtd names = rpmtdNew();
248     (void) rpmTagGetNames(names, 1);
249
250     while ((tname = rpmtdNextString(names))) {
251         sname = tname + strlen("RPMTAG_");
252         if (rpmIsVerbose()) {
253             rpmTag tag = rpmTagGetValue(sname);
254             rpmTagType type = rpmTagGetType(tag) & RPM_MASK_TYPE;
255             fprintf(fp, "%-20s %6d", sname, tag);
256             if (type > RPM_NULL_TYPE && type <= RPM_MAX_TYPE)
257                 fprintf(fp, " %s", tagTypeNames[type]);
258         } else {
259             fprintf(fp, "%s", sname);
260         }
261         fprintf(fp, "\n");
262     }
263     rpmtdFreeData(names);
264     rpmtdFree(names);
265 }
266
267 static int rpmgiShowMatches(QVA_t qva, rpmts ts)
268 {
269     rpmgi gi = qva->qva_gi;
270     int ec = 0;
271
272     while (rpmgiNext(gi) == RPMRC_OK) {
273         Header h;
274         int rc;
275
276         rpmdbCheckSignals();
277         h = rpmgiHeader(gi);
278         if (h == NULL)          /* XXX perhaps stricter break instead? */
279             continue;
280         if ((rc = qva->qva_showPackage(qva, ts, h)) != 0)
281             ec = rc;
282         if (qva->qva_source == RPMQV_DBOFFSET)
283             break;
284     }
285     return ec + rpmgiNumErrors(gi);
286 }
287
288 int rpmcliShowMatches(QVA_t qva, rpmts ts)
289 {
290     Header h;
291     int ec = 0;
292
293     while ((h = rpmdbNextIterator(qva->qva_mi)) != NULL) {
294         int rc;
295         rpmdbCheckSignals();
296         if ((rc = qva->qva_showPackage(qva, ts, h)) != 0)
297             ec = rc;
298         if (qva->qva_source == RPMQV_DBOFFSET)
299             break;
300     }
301     qva->qva_mi = rpmdbFreeIterator(qva->qva_mi);
302     return ec;
303 }
304
305 int rpmQueryVerify(QVA_t qva, rpmts ts, const char * arg)
306 {
307     int res = 0;
308     const char * s;
309     int i;
310     int provides_checked = 0;
311
312     (void) rpmdbCheckSignals();
313
314     if (qva->qva_showPackage == NULL)
315         return 1;
316
317     switch (qva->qva_source) {
318     case RPMQV_RPM:
319     case RPMQV_ALL:
320     case RPMQV_HDLIST:
321     case RPMQV_FTSWALK:
322         res = rpmgiShowMatches(qva, ts);
323         break;
324
325     case RPMQV_SPECFILE:
326         res = ((qva->qva_specQuery != NULL)
327                 ? qva->qva_specQuery(ts, qva, arg) : 1);
328         break;
329
330     case RPMQV_GROUP:
331         qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_GROUP, arg, 0);
332         if (qva->qva_mi == NULL) {
333             rpmlog(RPMLOG_NOTICE,
334                 _("group %s does not contain any packages\n"), arg);
335             res = 1;
336         } else
337             res = rpmcliShowMatches(qva, ts);
338         break;
339
340     case RPMQV_TRIGGEREDBY:
341         qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_TRIGGERNAME, arg, 0);
342         if (qva->qva_mi == NULL) {
343             rpmlog(RPMLOG_NOTICE, _("no package triggers %s\n"), arg);
344             res = 1;
345         } else
346             res = rpmcliShowMatches(qva, ts);
347         break;
348
349     case RPMQV_PKGID:
350     {   unsigned char MD5[16];
351         unsigned char * t;
352
353         for (i = 0, s = arg; *s && isxdigit(*s); s++, i++)
354             {};
355         if (i != 32) {
356             rpmlog(RPMLOG_ERR, _("malformed %s: %s\n"), "pkgid", arg);
357             return 1;
358         }
359
360         MD5[0] = '\0';
361         for (i = 0, t = MD5, s = arg; i < 16; i++, t++, s += 2)
362             *t = (rnibble(s[0]) << 4) | rnibble(s[1]);
363         
364         qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_SIGMD5, MD5, sizeof(MD5));
365         if (qva->qva_mi == NULL) {
366             rpmlog(RPMLOG_NOTICE, _("no package matches %s: %s\n"),
367                         "pkgid", arg);
368             res = 1;
369         } else
370             res = rpmcliShowMatches(qva, ts);
371     }   break;
372
373     case RPMQV_HDRID:
374         for (i = 0, s = arg; *s && isxdigit(*s); s++, i++)
375             {};
376         if (i != 40) {
377             rpmlog(RPMLOG_ERR, _("malformed %s: %s\n"), "hdrid", arg);
378             return 1;
379         }
380
381         qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_SHA1HEADER, arg, 0);
382         if (qva->qva_mi == NULL) {
383             rpmlog(RPMLOG_NOTICE, _("no package matches %s: %s\n"),
384                         "hdrid", arg);
385             res = 1;
386         } else
387             res = rpmcliShowMatches(qva, ts);
388         break;
389
390     case RPMQV_FILEID:
391     {   unsigned char *digest, *t;
392         size_t diglen;
393
394         for (i = 0, s = arg; *s && isxdigit(*s); s++, i++)
395             {};
396         /* XXX dunno the algorithm yet, just check we're in the ballpark */
397         if (i % 32 != 0 || i < 32 || i > 512) {
398             rpmlog(RPMLOG_ERR, _("malformed %s: %s\n"), "fileid", arg);
399             return 1;
400         }
401
402         diglen = i / 2;
403         digest = t = xcalloc(diglen, sizeof(*digest));
404         for (i = 0, s = arg; i < diglen; i++, t++, s += 2)
405             *t = (rnibble(s[0]) << 4) | rnibble(s[1]);
406
407         qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_FILEDIGESTS, digest, diglen);
408         if (qva->qva_mi == NULL) {
409             rpmlog(RPMLOG_NOTICE, _("no package matches %s: %s\n"),
410                         "fileid", arg);
411             res = 1;
412         } else
413             res = rpmcliShowMatches(qva, ts);
414
415         free(digest);
416     }   break;
417
418     case RPMQV_TID:
419     {   int mybase = 10;
420         const char * myarg = arg;
421         char * end = NULL;
422         unsigned long iid;
423
424         /* XXX should be in strtoul */
425         if (*myarg == '0') {
426             myarg++;
427             mybase = 8;
428             if (*myarg == 'x') {
429                 myarg++;
430                 mybase = 16;
431             }
432         }
433         iid = strtoul(myarg, &end, mybase);
434         if ((*end) || (end == arg) || (iid == ULONG_MAX)) {
435             rpmlog(RPMLOG_ERR, _("malformed %s: %s\n"), "tid", arg);
436             return 1;
437         }
438         qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_INSTALLTID, &iid, sizeof(iid));
439         if (qva->qva_mi == NULL) {
440             rpmlog(RPMLOG_NOTICE, _("no package matches %s: %s\n"),
441                         "tid", arg);
442             res = 1;
443         } else
444             res = rpmcliShowMatches(qva, ts);
445     }   break;
446
447     case RPMQV_WHATREQUIRES:
448         qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_REQUIRENAME, arg, 0);
449         if (qva->qva_mi == NULL) {
450             rpmlog(RPMLOG_NOTICE, _("no package requires %s\n"), arg);
451             res = 1;
452         } else
453             res = rpmcliShowMatches(qva, ts);
454         break;
455
456     case RPMQV_WHATPROVIDES:
457         if (arg[0] != '/') {
458             provides_checked = 1;
459             qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, arg, 0);
460             if (qva->qva_mi == NULL) {
461                 rpmlog(RPMLOG_NOTICE, _("no package provides %s\n"), arg);
462                 res = 1;
463             } else
464                 res = rpmcliShowMatches(qva, ts);
465             break;
466         }
467     case RPMQV_PATH:
468     {   char * fn;
469
470         for (s = arg; *s != '\0'; s++)
471             if (!(*s == '.' || *s == '/'))
472                 break;
473
474         if (*s == '\0') {
475             char fnbuf[PATH_MAX];
476             fn = realpath(arg, fnbuf);
477             fn = xstrdup( (fn != NULL ? fn : arg) );
478         } else if (*arg != '/') {
479             char *curDir = rpmGetCwd();
480             fn = (char *) rpmGetPath(curDir, "/", arg, NULL);
481             curDir = _free(curDir);
482         } else
483             fn = xstrdup(arg);
484         (void) rpmCleanPath(fn);
485
486         qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_BASENAMES, fn, 0);
487         if (qva->qva_mi == NULL && !provides_checked)
488             qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, fn, 0);
489
490         if (qva->qva_mi == NULL) {
491             struct stat sb;
492             if (lstat(fn, &sb) != 0)
493                 rpmlog(RPMLOG_ERR, _("file %s: %s\n"), fn, strerror(errno));
494             else
495                 rpmlog(RPMLOG_NOTICE,
496                         _("file %s is not owned by any package\n"), fn);
497             res = 1;
498         } else
499             res = rpmcliShowMatches(qva, ts);
500
501         fn = _free(fn);
502     }   break;
503
504     case RPMQV_DBOFFSET:
505     {   int mybase = 10;
506         const char * myarg = arg;
507         char * end = NULL;
508         unsigned long recOffset;
509
510         /* XXX should be in strtoul */
511         if (*myarg == '0') {
512             myarg++;
513             mybase = 8;
514             if (*myarg == 'x') {
515                 myarg++;
516                 mybase = 16;
517             }
518         }
519         recOffset = strtoul(myarg, &end, mybase);
520         if ((*end) || (end == arg) || (recOffset == ULONG_MAX)) {
521             rpmlog(RPMLOG_ERR, _("invalid package number: %s\n"), arg);
522             return 1;
523         }
524         rpmlog(RPMLOG_DEBUG, "package record number: %lu\n", recOffset);
525         /* RPMDBI_PACKAGES */
526         qva->qva_mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES, &recOffset, sizeof(recOffset));
527         if (qva->qva_mi == NULL) {
528             rpmlog(RPMLOG_ERR,
529                 _("record %lu could not be read\n"), recOffset);
530             res = 1;
531         } else
532             res = rpmcliShowMatches(qva, ts);
533     }   break;
534
535     case RPMQV_PACKAGE:
536     {
537         int matches = 0;
538         rpmdbMatchIterator mi;
539         mi = rpmtsInitIterator(ts, RPMDBI_LABEL, arg, 0);
540         while (rpmdbNextIterator(mi) != NULL) {
541             matches++;
542         }
543         rpmdbFreeIterator(mi);
544         if (! matches) {
545             rpmlog(RPMLOG_NOTICE, _("package %s is not installed\n"), arg);
546             res = 1;
547         } else {
548             qva->qva_mi = rpmtsInitIterator(ts, RPMDBI_LABEL, arg, 0);
549             res = rpmcliShowMatches(qva, ts);
550         }
551         break;
552     }
553     
554     }
555    
556     return res;
557 }
558
559 static int rpmcliArgIterHelper(rpmts ts, QVA_t qva, rpmTag tag, ARGV_const_t argv, rpmgiFlags gFlgs)
560 {
561     rpmRC rpmrc = RPMRC_NOTFOUND;
562     int ec = 0;
563
564     qva->qva_gi = rpmgiNew(ts, tag, NULL, 0);
565     qva->qva_rc = rpmgiSetArgs(qva->qva_gi, argv, ftsOpts, gFlgs);
566     
567     if (qva->qva_gi != NULL && (rpmgiGetFlags(qva->qva_gi) & RPMGI_TSADD))      /* Load the ts with headers. */
568         while ((rpmrc = rpmgiNext(qva->qva_gi)) == RPMRC_OK)
569             {};
570     if (rpmrc != RPMRC_NOTFOUND) {
571         qva->qva_gi = rpmgiFree(qva->qva_gi);
572         return 1;       /* XXX should be no. of failures. */
573     }
574     /* FIX: argv can be NULL, cast to pass argv array */
575     ec = rpmQueryVerify(qva, ts, (tag == RPMDBI_PACKAGES)? (const char *) argv : NULL);
576     rpmtsEmpty(ts);
577     qva->qva_gi = rpmgiFree(qva->qva_gi);
578     return ec;
579 }
580
581 int rpmcliArgIter(rpmts ts, QVA_t qva, ARGV_const_t argv)
582 {
583     int ec = 0;
584
585     switch (qva->qva_source) {
586     case RPMQV_ALL:
587         ec = rpmcliArgIterHelper(ts, qva, RPMDBI_PACKAGES, argv, RPMGI_NONE);
588         break;
589     case RPMQV_RPM:
590         ec = rpmcliArgIterHelper(ts, qva, RPMDBI_ARGLIST, argv, giFlags);
591         break;
592     case RPMQV_HDLIST:
593         ec = rpmcliArgIterHelper(ts, qva, RPMDBI_HDLIST, argv, giFlags);
594         break;
595     case RPMQV_FTSWALK:
596         if (ftsOpts == 0)
597             ftsOpts = (RPMGI_COMFOLLOW | RPMGI_LOGICAL | RPMGI_NOSTAT);
598         ec = rpmcliArgIterHelper(ts, qva, RPMDBI_FTSWALK, argv, giFlags);
599         break;
600     default:
601         qva->qva_gi = rpmgiNew(ts, RPMDBI_ARGLIST, NULL, 0);
602         qva->qva_rc = rpmgiSetArgs(qva->qva_gi, argv, ftsOpts,
603                 (giFlags | (RPMGI_NOGLOB|RPMGI_NOHEADER)));
604         while (rpmgiNext(qva->qva_gi) == RPMRC_OK) {
605             ec += rpmQueryVerify(qva, ts, rpmgiHdrPath(qva->qva_gi));
606             rpmtsEmpty(ts);
607         }
608         qva->qva_gi = rpmgiFree(qva->qva_gi);
609         break;
610     }
611
612     return ec;
613 }
614
615 int rpmcliQuery(rpmts ts, QVA_t qva, char * const * argv)
616 {
617     rpmVSFlags vsflags, ovsflags;
618     int ec = 0;
619
620     if (qva->qva_showPackage == NULL)
621         qva->qva_showPackage = showQueryPackage;
622
623     /* If --queryformat unspecified, then set default now. */
624     if (!(qva->qva_flags & _QUERY_FOR_BITS) && qva->qva_queryFormat == NULL) {
625         char * fmt = rpmExpand("%{?_query_all_fmt}\n", NULL);
626         if (fmt == NULL || strlen(fmt) <= 1) {
627             fmt = _free(fmt);
628             fmt = xstrdup("%{nvra}\n");
629         }
630         qva->qva_queryFormat = fmt;
631     }
632
633     vsflags = rpmExpandNumeric("%{?_vsflags_query}");
634     if (qva->qva_flags & VERIFY_DIGEST)
635         vsflags |= _RPMVSF_NODIGESTS;
636     if (qva->qva_flags & VERIFY_SIGNATURE)
637         vsflags |= _RPMVSF_NOSIGNATURES;
638     if (qva->qva_flags & VERIFY_HDRCHK)
639         vsflags |= RPMVSF_NOHDRCHK;
640
641     ovsflags = rpmtsSetVSFlags(ts, vsflags);
642     ec = rpmcliArgIter(ts, qva, argv);
643     vsflags = rpmtsSetVSFlags(ts, ovsflags);
644
645     if (qva->qva_showPackage == showQueryPackage)
646         qva->qva_showPackage = NULL;
647
648     return ec;
649 }