Move key size fixups from rpmdbAdd & Remove to td2key()
[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, *fmd5;
198             fmd5 = pgpHexStr(rpmfiMD5(fi), rpmDigestLength(PGPHASHALGO_MD5));
199         
200             rasprintf(&add, "%s %d %d %s 0%o ", fn, (int)fsize, fmtime, fmd5, fmode);
201             rstrcat(&buf, add);
202             free(add);
203             free(fmd5);
204
205             if (fuser && fgroup) {
206                 rasprintf(&add, "%s %s", fuser, fgroup);
207                 rstrcat(&buf, add);
208                 free(add);
209             } else {
210                 rpmlog(RPMLOG_ERR,
211                         _("package has not file owner/group lists\n"));
212             }
213
214             rasprintf(&add, " %s %s %u %s",
215                                  fflags & RPMFILE_CONFIG ? "1" : "0",
216                                  fflags & RPMFILE_DOC ? "1" : "0",
217                                  frdev,
218                                  (flink && *flink ? flink : "X"));
219             rpmlog(RPMLOG_NOTICE, "%s%s\n", buf, add);
220             free(add);
221         } else
222         if (!rpmIsVerbose()) {
223             rpmlog(RPMLOG_NOTICE, "%s%s\n", buf ? buf : "", fn);
224         }
225         else {
226
227             /* XXX Adjust directory link count and size for display output. */
228             if (S_ISDIR(fmode)) {
229                 fnlink++;
230                 fsize = 0;
231             }
232
233             if (fuser && fgroup) {
234                 if (buf) {
235                     rpmlog(RPMLOG_NOTICE, "%s", buf);
236                 }
237                 printFileInfo(fn, fsize, fmode, fmtime, frdev, fnlink,
238                                         fuser, fgroup, flink);
239             } else {
240                 rpmlog(RPMLOG_ERR,
241                         _("package has neither file owner or id lists\n"));
242             }
243         }
244         free(buf);
245     }
246
247     rc = 0;
248
249 exit:
250     fi = rpmfiFree(fi);
251     return rc;
252 }
253
254 void rpmDisplayQueryTags(FILE * fp)
255 {
256     static const char * const tagTypeNames[] = {
257         "", "char", "int8", "int16", "int32", "int64",
258         "string", "blob", "argv", "i18nstring"
259     };
260     const char *tname, *sname;
261     rpmtd names = rpmTagGetNames(1);
262
263     while ((tname = rpmtdNextString(names))) {
264         sname = tname + strlen("RPMTAG_");
265         if (rpmIsVerbose()) {
266             rpmTag tag = rpmTagGetValue(sname);
267             rpmTagType type = rpmTagGetType(tag) & RPM_MASK_TYPE;
268             fprintf(fp, "%-20s %6d", sname, tag);
269             if (type > RPM_NULL_TYPE && type <= RPM_MAX_TYPE)
270                 fprintf(fp, " %s", tagTypeNames[type]);
271         } else {
272             fprintf(fp, "%s", sname);
273         }
274         fprintf(fp, "\n");
275     }
276     rpmtdFreeData(names);
277     rpmtdFree(names);
278 }
279
280 static int rpmgiShowMatches(QVA_t qva, rpmts ts)
281 {
282     rpmgi gi = qva->qva_gi;
283     int ec = 0;
284
285     while (rpmgiNext(gi) == RPMRC_OK) {
286         Header h;
287         int rc;
288
289         h = rpmgiHeader(gi);
290         if (h == NULL)          /* XXX perhaps stricter break instead? */
291             continue;
292         if ((rc = qva->qva_showPackage(qva, ts, h)) != 0)
293             ec = rc;
294         if (qva->qva_source == RPMQV_DBOFFSET)
295             break;
296     }
297     return rpmgiNumErrors(gi);
298 }
299
300 int rpmcliShowMatches(QVA_t qva, rpmts ts)
301 {
302     Header h;
303     int ec = 0;
304
305     while ((h = rpmdbNextIterator(qva->qva_mi)) != NULL) {
306         int rc;
307         if ((rc = qva->qva_showPackage(qva, ts, h)) != 0)
308             ec = rc;
309         if (qva->qva_source == RPMQV_DBOFFSET)
310             break;
311     }
312     qva->qva_mi = rpmdbFreeIterator(qva->qva_mi);
313     return ec;
314 }
315
316 /* LCL: segfault (realpath annotation?) */
317 int rpmQueryVerify(QVA_t qva, rpmts ts, const char * arg)
318 {
319     int res = 0;
320     const char * s;
321     int i;
322     int provides_checked = 0;
323
324     (void) rpmdbCheckSignals();
325
326     if (qva->qva_showPackage == NULL)
327         return 1;
328
329     switch (qva->qva_source) {
330     case RPMQV_RPM:
331         res = rpmgiShowMatches(qva, ts);
332         break;
333
334     case RPMQV_ALL:
335         res = rpmgiShowMatches(qva, ts);
336         break;
337
338     case RPMQV_HDLIST:
339         res = rpmgiShowMatches(qva, ts);
340         break;
341
342     case RPMQV_FTSWALK:
343         res = rpmgiShowMatches(qva, ts);
344         break;
345
346     case RPMQV_SPECFILE:
347         res = ((qva->qva_specQuery != NULL)
348                 ? qva->qva_specQuery(ts, qva, arg) : 1);
349         break;
350
351     case RPMQV_GROUP:
352         qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_GROUP, arg, 0);
353         if (qva->qva_mi == NULL) {
354             rpmlog(RPMLOG_NOTICE,
355                 _("group %s does not contain any packages\n"), arg);
356             res = 1;
357         } else
358             res = rpmcliShowMatches(qva, ts);
359         break;
360
361     case RPMQV_TRIGGEREDBY:
362         qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_TRIGGERNAME, arg, 0);
363         if (qva->qva_mi == NULL) {
364             rpmlog(RPMLOG_NOTICE, _("no package triggers %s\n"), arg);
365             res = 1;
366         } else
367             res = rpmcliShowMatches(qva, ts);
368         break;
369
370     case RPMQV_PKGID:
371     {   unsigned char MD5[16];
372         unsigned char * t;
373
374         for (i = 0, s = arg; *s && isxdigit(*s); s++, i++)
375             {};
376         if (i != 32) {
377             rpmlog(RPMLOG_NOTICE, _("malformed %s: %s\n"), "pkgid", arg);
378             return 1;
379         }
380
381         MD5[0] = '\0';
382         for (i = 0, t = MD5, s = arg; i < 16; i++, t++, s += 2)
383             *t = (rnibble(s[0]) << 4) | rnibble(s[1]);
384         
385         qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_SIGMD5, MD5, sizeof(MD5));
386         if (qva->qva_mi == NULL) {
387             rpmlog(RPMLOG_NOTICE, _("no package matches %s: %s\n"),
388                         "pkgid", arg);
389             res = 1;
390         } else
391             res = rpmcliShowMatches(qva, ts);
392     }   break;
393
394     case RPMQV_HDRID:
395         for (i = 0, s = arg; *s && isxdigit(*s); s++, i++)
396             {};
397         if (i != 40) {
398             rpmlog(RPMLOG_NOTICE, _("malformed %s: %s\n"), "hdrid", arg);
399             return 1;
400         }
401
402         qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_SHA1HEADER, arg, 0);
403         if (qva->qva_mi == NULL) {
404             rpmlog(RPMLOG_NOTICE, _("no package matches %s: %s\n"),
405                         "hdrid", arg);
406             res = 1;
407         } else
408             res = rpmcliShowMatches(qva, ts);
409         break;
410
411     case RPMQV_FILEID:
412     {   unsigned char MD5[16];
413         unsigned char * t;
414
415         for (i = 0, s = arg; *s && isxdigit(*s); s++, i++)
416             {};
417         if (i != 32) {
418             rpmlog(RPMLOG_ERR, _("malformed %s: %s\n"), "fileid", arg);
419             return 1;
420         }
421
422         MD5[0] = '\0';
423         for (i = 0, t = MD5, s = arg; i < 16; i++, t++, s += 2)
424             *t = (rnibble(s[0]) << 4) | rnibble(s[1]);
425
426         qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_FILEMD5S, MD5, sizeof(MD5));
427         if (qva->qva_mi == NULL) {
428             rpmlog(RPMLOG_NOTICE, _("no package matches %s: %s\n"),
429                         "fileid", arg);
430             res = 1;
431         } else
432             res = rpmcliShowMatches(qva, ts);
433     }   break;
434
435     case RPMQV_TID:
436     {   int mybase = 10;
437         const char * myarg = arg;
438         char * end = NULL;
439         unsigned long iid;
440
441         /* XXX should be in strtoul */
442         if (*myarg == '0') {
443             myarg++;
444             mybase = 8;
445             if (*myarg == 'x') {
446                 myarg++;
447                 mybase = 16;
448             }
449         }
450         iid = strtoul(myarg, &end, mybase);
451         if ((*end) || (end == arg) || (iid == ULONG_MAX)) {
452             rpmlog(RPMLOG_ERR, _("malformed %s: %s\n"), "tid", arg);
453             return 1;
454         }
455         qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_INSTALLTID, &iid, sizeof(iid));
456         if (qva->qva_mi == NULL) {
457             rpmlog(RPMLOG_NOTICE, _("no package matches %s: %s\n"),
458                         "tid", arg);
459             res = 1;
460         } else
461             res = rpmcliShowMatches(qva, ts);
462     }   break;
463
464     case RPMQV_WHATREQUIRES:
465         qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_REQUIRENAME, arg, 0);
466         if (qva->qva_mi == NULL) {
467             rpmlog(RPMLOG_NOTICE, _("no package requires %s\n"), arg);
468             res = 1;
469         } else
470             res = rpmcliShowMatches(qva, ts);
471         break;
472
473     case RPMQV_WHATPROVIDES:
474         if (arg[0] != '/') {
475             provides_checked = 1;
476             qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, arg, 0);
477             if (qva->qva_mi == NULL) {
478                 rpmlog(RPMLOG_NOTICE, _("no package provides %s\n"), arg);
479                 res = 1;
480             } else
481                 res = rpmcliShowMatches(qva, ts);
482             break;
483         }
484     case RPMQV_PATH:
485     {   char * fn;
486
487         for (s = arg; *s != '\0'; s++)
488             if (!(*s == '.' || *s == '/'))
489                 break;
490
491         if (*s == '\0') {
492             char fnbuf[PATH_MAX];
493             fn = realpath(arg, fnbuf);
494             fn = xstrdup( (fn != NULL ? fn : arg) );
495         } else if (*arg != '/') {
496             char *curDir = rpmGetCwd();
497             fn = (char *) rpmGetPath(curDir, "/", arg, NULL);
498             curDir = _free(curDir);
499         } else
500             fn = xstrdup(arg);
501         (void) rpmCleanPath(fn);
502
503         qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_BASENAMES, fn, 0);
504         if (qva->qva_mi == NULL && !provides_checked)
505             qva->qva_mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, fn, 0);
506
507         if (qva->qva_mi == NULL) {
508             struct stat sb;
509             if (lstat(fn, &sb) != 0)
510                 rpmlog(RPMLOG_ERR, _("file %s: %s\n"), fn, strerror(errno));
511             else
512                 rpmlog(RPMLOG_NOTICE,
513                         _("file %s is not owned by any package\n"), fn);
514             res = 1;
515         } else
516             res = rpmcliShowMatches(qva, ts);
517
518         fn = _free(fn);
519     }   break;
520
521     case RPMQV_DBOFFSET:
522     {   int mybase = 10;
523         const char * myarg = arg;
524         char * end = NULL;
525         unsigned long recOffset;
526
527         /* XXX should be in strtoul */
528         if (*myarg == '0') {
529             myarg++;
530             mybase = 8;
531             if (*myarg == 'x') {
532                 myarg++;
533                 mybase = 16;
534             }
535         }
536         recOffset = strtoul(myarg, &end, mybase);
537         if ((*end) || (end == arg) || (recOffset == ULONG_MAX)) {
538             rpmlog(RPMLOG_NOTICE, _("invalid package number: %s\n"), arg);
539             return 1;
540         }
541         rpmlog(RPMLOG_DEBUG, "package record number: %lu\n", recOffset);
542         /* RPMDBI_PACKAGES */
543         qva->qva_mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES, &recOffset, sizeof(recOffset));
544         if (qva->qva_mi == NULL) {
545             rpmlog(RPMLOG_NOTICE,
546                 _("record %lu could not be read\n"), recOffset);
547             res = 1;
548         } else
549             res = rpmcliShowMatches(qva, ts);
550     }   break;
551
552     case RPMQV_PACKAGE:
553     {
554         int matches = 0;
555         rpmdbMatchIterator mi;
556         mi = rpmtsInitIterator(ts, RPMDBI_LABEL, arg, 0);
557         while (rpmdbNextIterator(mi) != NULL) {
558             matches++;
559         }
560         rpmdbFreeIterator(mi);
561         if (! matches) {
562             rpmlog(RPMLOG_NOTICE, _("package %s is not installed\n"), arg);
563             res = 1;
564         } else {
565             qva->qva_mi = rpmtsInitIterator(ts, RPMDBI_LABEL, arg, 0);
566             res = rpmcliShowMatches(qva, ts);
567         }
568         break;
569     }
570     
571     }
572    
573     return res;
574 }
575
576 int rpmcliArgIter(rpmts ts, QVA_t qva, ARGV_const_t argv)
577 {
578     rpmRC rpmrc = RPMRC_NOTFOUND;
579     int ec = 0;
580
581     switch (qva->qva_source) {
582     case RPMQV_ALL:
583         qva->qva_gi = rpmgiNew(ts, RPMDBI_PACKAGES, NULL, 0);
584         qva->qva_rc = rpmgiSetArgs(qva->qva_gi, argv, ftsOpts, RPMGI_NONE);
585
586         if (qva->qva_gi != NULL && (rpmgiGetFlags(qva->qva_gi) & RPMGI_TSADD))  /* Load the ts with headers. */
587         while ((rpmrc = rpmgiNext(qva->qva_gi)) == RPMRC_OK)
588             {};
589         if (rpmrc != RPMRC_NOTFOUND)
590             return 1;   /* XXX should be no. of failures. */
591         
592         /* FIX: argv can be NULL, cast to pass argv array */
593         ec = rpmQueryVerify(qva, ts, (const char *) argv);
594         rpmtsEmpty(ts);
595         break;
596     case RPMQV_RPM:
597         qva->qva_gi = rpmgiNew(ts, RPMDBI_ARGLIST, NULL, 0);
598         qva->qva_rc = rpmgiSetArgs(qva->qva_gi, argv, ftsOpts, giFlags);
599
600         if (qva->qva_gi != NULL && (rpmgiGetFlags(qva->qva_gi) & RPMGI_TSADD))  /* Load the ts with headers. */
601         while ((rpmrc = rpmgiNext(qva->qva_gi)) == RPMRC_OK)
602             {};
603         if (rpmrc != RPMRC_NOTFOUND)
604             return 1;   /* XXX should be no. of failures. */
605         
606         /* FIX: argv can be NULL, cast to pass argv array */
607         ec = rpmQueryVerify(qva, ts, NULL);
608         rpmtsEmpty(ts);
609         break;
610     case RPMQV_HDLIST:
611         qva->qva_gi = rpmgiNew(ts, RPMDBI_HDLIST, NULL, 0);
612         qva->qva_rc = rpmgiSetArgs(qva->qva_gi, argv, ftsOpts, giFlags);
613
614         if (qva->qva_gi != NULL && (rpmgiGetFlags(qva->qva_gi) & RPMGI_TSADD))  /* Load the ts with headers. */
615         while ((rpmrc = rpmgiNext(qva->qva_gi)) == RPMRC_OK)
616             {};
617         if (rpmrc != RPMRC_NOTFOUND)
618             return 1;   /* XXX should be no. of failures. */
619         
620         /* FIX: argv can be NULL, cast to pass argv array */
621         ec = rpmQueryVerify(qva, ts, NULL);
622         rpmtsEmpty(ts);
623         break;
624     case RPMQV_FTSWALK:
625         if (ftsOpts == 0)
626             ftsOpts = (RPMGI_COMFOLLOW | RPMGI_LOGICAL | RPMGI_NOSTAT);
627         qva->qva_gi = rpmgiNew(ts, RPMDBI_FTSWALK, NULL, 0);
628         qva->qva_rc = rpmgiSetArgs(qva->qva_gi, argv, ftsOpts, giFlags);
629
630         if (qva->qva_gi != NULL && (rpmgiGetFlags(qva->qva_gi) & RPMGI_TSADD))  /* Load the ts with headers. */
631         while ((rpmrc = rpmgiNext(qva->qva_gi)) == RPMRC_OK)
632             {};
633         if (rpmrc != RPMRC_NOTFOUND)
634             return 1;   /* XXX should be no. of failures. */
635         
636         /* FIX: argv can be NULL, cast to pass argv array */
637         ec = rpmQueryVerify(qva, ts, NULL);
638         rpmtsEmpty(ts);
639         break;
640     default:
641         qva->qva_gi = rpmgiNew(ts, RPMDBI_ARGLIST, NULL, 0);
642         qva->qva_rc = rpmgiSetArgs(qva->qva_gi, argv, ftsOpts,
643                 (giFlags | (RPMGI_NOGLOB|RPMGI_NOHEADER)));
644         while (rpmgiNext(qva->qva_gi) == RPMRC_OK) {
645             ec += rpmQueryVerify(qva, ts, rpmgiHdrPath(qva->qva_gi));
646             rpmtsEmpty(ts);
647         }
648         break;
649     }
650
651     qva->qva_gi = rpmgiFree(qva->qva_gi);
652
653     return ec;
654 }
655
656 int rpmcliQuery(rpmts ts, QVA_t qva, char * const * argv)
657 {
658     rpmVSFlags vsflags, ovsflags;
659     int ec = 0;
660
661     if (qva->qva_showPackage == NULL)
662         qva->qva_showPackage = showQueryPackage;
663
664     /* If --queryformat unspecified, then set default now. */
665     if (!(qva->qva_flags & _QUERY_FOR_BITS) && qva->qva_queryFormat == NULL) {
666         char * fmt = rpmExpand("%{?_query_all_fmt}\n", NULL);
667         if (fmt == NULL || strlen(fmt) <= 1) {
668             fmt = _free(fmt);
669             fmt = xstrdup("%{name}-%{version}-%{release}.%{arch}\n");
670         }
671         qva->qva_queryFormat = fmt;
672     }
673
674     vsflags = rpmExpandNumeric("%{?_vsflags_query}");
675     if (qva->qva_flags & VERIFY_DIGEST)
676         vsflags |= _RPMVSF_NODIGESTS;
677     if (qva->qva_flags & VERIFY_SIGNATURE)
678         vsflags |= _RPMVSF_NOSIGNATURES;
679     if (qva->qva_flags & VERIFY_HDRCHK)
680         vsflags |= RPMVSF_NOHDRCHK;
681
682     ovsflags = rpmtsSetVSFlags(ts, vsflags);
683     ec = rpmcliArgIter(ts, qva, argv);
684     vsflags = rpmtsSetVSFlags(ts, ovsflags);
685
686     if (qva->qva_showPackage == showQueryPackage)
687         qva->qva_showPackage = NULL;
688
689     return ec;
690 }