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