permit --whatprovides to lookup file dependencies.
[tools/librpm-tizen.git] / lib / query.c
1 #include "system.h"
2
3 #ifndef PATH_MAX
4 # define PATH_MAX 255
5 #endif
6
7 #include "rpmbuild.h"
8 #include <rpmurl.h>
9
10 /* ======================================================================== */
11 static char * permsString(int mode)
12 {
13     char *perms = xstrdup("----------");
14    
15     if (S_ISDIR(mode)) 
16         perms[0] = 'd';
17     else if (S_ISLNK(mode))
18         perms[0] = 'l';
19     else if (S_ISFIFO(mode)) 
20         perms[0] = 'p';
21     else if (S_ISSOCK(mode)) 
22         perms[0] = 's';
23     else if (S_ISCHR(mode))
24         perms[0] = 'c';
25     else if (S_ISBLK(mode))
26         perms[0] = 'b';
27
28     if (mode & S_IRUSR) perms[1] = 'r';
29     if (mode & S_IWUSR) perms[2] = 'w';
30     if (mode & S_IXUSR) perms[3] = 'x';
31  
32     if (mode & S_IRGRP) perms[4] = 'r';
33     if (mode & S_IWGRP) perms[5] = 'w';
34     if (mode & S_IXGRP) perms[6] = 'x';
35
36     if (mode & S_IROTH) perms[7] = 'r';
37     if (mode & S_IWOTH) perms[8] = 'w';
38     if (mode & S_IXOTH) perms[9] = 'x';
39
40     if (mode & S_ISUID)
41         perms[3] = ((mode & S_IXUSR) ? 's' : 'S'); 
42
43     if (mode & S_ISGID)
44         perms[6] = ((mode & S_IXGRP) ? 's' : 'S'); 
45
46     if (mode & S_ISVTX)
47         perms[9] = ((mode & S_IXOTH) ? 't' : 'T');
48
49     return perms;
50 }
51
52 static void printFileInfo(FILE *fp, const char * name,
53                           unsigned int size, unsigned short mode,
54                           unsigned int mtime, unsigned short rdev,
55                           const char * owner, const char * group,
56                           int uid, int gid, const char * linkto)
57 {
58     char sizefield[15];
59     char ownerfield[9], groupfield[9];
60     char timefield[100] = "";
61     time_t when = mtime;  /* important if sizeof(int_32) ! sizeof(time_t) */
62     struct tm * tm;
63     static time_t now;
64     static struct tm nowtm;
65     const char * namefield = name;
66     char * perms;
67
68     /* On first call, grab snapshot of now */
69     if (now == 0) {
70         now = time(NULL);
71         tm = localtime(&now);
72         nowtm = *tm;    /* structure assignment */
73     }
74
75     perms = permsString(mode);
76
77     if (owner) 
78         strncpy(ownerfield, owner, 8);
79     else
80         sprintf(ownerfield, "%-8d", uid);
81     ownerfield[8] = '\0';
82
83     if (group) 
84         strncpy(groupfield, group, 8);
85     else 
86         sprintf(groupfield, "%-8d", gid);
87     groupfield[8] = '\0';
88
89     /* this is normally right */
90     sprintf(sizefield, "%12u", size);
91
92     /* this knows too much about dev_t */
93
94     if (S_ISLNK(mode)) {
95         char *nf = alloca(strlen(name) + sizeof(" -> ") + strlen(linkto));
96         sprintf(nf, "%s -> %s", name, linkto);
97         namefield = nf;
98     } else if (S_ISCHR(mode)) {
99         perms[0] = 'c';
100         sprintf(sizefield, "%3u, %3u", (rdev >> 8) & 0xff, rdev & 0xFF);
101     } else if (S_ISBLK(mode)) {
102         perms[0] = 'b';
103         sprintf(sizefield, "%3u, %3u", (rdev >> 8) & 0xff, rdev & 0xFF);
104     }
105
106     /* Convert file mtime to display format */
107     tm = localtime(&when);
108     {   const char *fmt;
109         if (now > when + 6L * 30L * 24L * 60L * 60L ||  /* Old. */
110             now < when - 60L * 60L)                     /* In the future.  */
111         {
112         /* The file is fairly old or in the future.
113          * POSIX says the cutoff is 6 months old;
114          * approximate this by 6*30 days.
115          * Allow a 1 hour slop factor for what is considered "the future",
116          * to allow for NFS server/client clock disagreement.
117          * Show the year instead of the time of day.
118          */        
119             fmt = "%b %e  %Y";
120         } else {
121             fmt = "%b %e %H:%M";
122         }
123         (void)strftime(timefield, sizeof(timefield) - 1, fmt, tm);
124     }
125
126     fprintf(fp, "%s %8s %8s %10s %s %s\n", perms, ownerfield, groupfield, 
127                 sizefield, timefield, namefield);
128     if (perms) free(perms);
129 }
130
131 static int queryHeader(FILE *fp, Header h, const char * chptr)
132 {
133     char * str;
134     const char * error;
135
136     str = headerSprintf(h, chptr, rpmTagTable, rpmHeaderFormats, &error);
137     if (!str) {
138         fprintf(stderr, _("error in format: %s\n"), error);
139         return 1;
140     }
141
142     fputs(str, fp);
143
144     return 0;
145 }
146
147 int showQueryPackage(QVA_t *qva, /*@unused@*/rpmdb db, Header h)
148 {
149     FILE *fp = stdout;  /* XXX FIXME: pass as arg */
150     int queryFlags = qva->qva_flags;
151     const char *queryFormat = qva->qva_queryFormat;
152
153     const char * name, * version, * release;
154     int_32 count, type;
155     char * prefix = NULL;
156     const char ** dirNames, ** baseNames;
157     const char ** fileMD5List;
158     const char * fileStatesList;
159     const char ** fileOwnerList = NULL;
160     const char ** fileGroupList = NULL;
161     const char ** fileLinktoList;
162     int_32 * fileFlagsList, * fileMTimeList, * fileSizeList;
163     int_32 * fileUIDList = NULL;
164     int_32 * fileGIDList = NULL;
165     uint_16 * fileModeList;
166     uint_16 * fileRdevList;
167     int_32 * dirIndexes;
168     int i;
169
170     headerNVR(h, &name, &version, &release);
171
172     if (!queryFormat && !queryFlags) {
173         fprintf(fp, "%s-%s-%s\n", name, version, release);
174     } else {
175         if (queryFormat)
176             queryHeader(fp, h, queryFormat);
177
178         if (queryFlags & QUERY_FOR_LIST) {
179             if (!headerGetEntry(h, RPMTAG_COMPFILELIST, &type, 
180                                 (void **) &baseNames, &count)) {
181                 fputs(_("(contains no files)"), fp);
182                 fputs("\n", fp);
183             } else {
184                 if (!headerGetEntry(h, RPMTAG_FILESTATES, &type, 
185                          (void **) &fileStatesList, &count)) {
186                     fileStatesList = NULL;
187                 }
188                 headerGetEntry(h, RPMTAG_COMPDIRLIST, NULL,
189                          (void **) &dirNames, NULL);
190                 headerGetEntry(h, RPMTAG_COMPFILEDIRS, NULL, 
191                          (void **) &dirIndexes, NULL);
192                 headerGetEntry(h, RPMTAG_FILEFLAGS, &type, 
193                          (void **) &fileFlagsList, &count);
194                 headerGetEntry(h, RPMTAG_FILESIZES, &type, 
195                          (void **) &fileSizeList, &count);
196                 headerGetEntry(h, RPMTAG_FILEMODES, &type, 
197                          (void **) &fileModeList, &count);
198                 headerGetEntry(h, RPMTAG_FILEMTIMES, &type, 
199                          (void **) &fileMTimeList, &count);
200                 headerGetEntry(h, RPMTAG_FILERDEVS, &type, 
201                          (void **) &fileRdevList, &count);
202                 headerGetEntry(h, RPMTAG_FILELINKTOS, &type, 
203                          (void **) &fileLinktoList, &count);
204                 headerGetEntry(h, RPMTAG_FILEMD5S, &type, 
205                          (void **) &fileMD5List, &count);
206
207                 if (!headerGetEntry(h, RPMTAG_FILEUIDS, &type, 
208                          (void **) &fileUIDList, &count)) {
209                     fileUIDList = NULL;
210                 } else if (!headerGetEntry(h, RPMTAG_FILEGIDS, &type, 
211                              (void **) &fileGIDList, &count)) {
212                     fileGIDList = NULL;
213                 }
214
215                 if (!headerGetEntry(h, RPMTAG_FILEUSERNAME, &type, 
216                          (void **) &fileOwnerList, &count)) {
217                     fileOwnerList = NULL;
218                 } else if (!headerGetEntry(h, RPMTAG_FILEGROUPNAME, &type, 
219                              (void **) &fileGroupList, &count)) {
220                     fileGroupList = NULL;
221                 }
222
223                 for (i = 0; i < count; i++) {
224                     if (!((queryFlags & QUERY_FOR_DOCS) || 
225                           (queryFlags & QUERY_FOR_CONFIG)) 
226                         || ((queryFlags & QUERY_FOR_DOCS) && 
227                             (fileFlagsList[i] & RPMFILE_DOC))
228                         || ((queryFlags & QUERY_FOR_CONFIG) && 
229                             (fileFlagsList[i] & RPMFILE_CONFIG))) {
230
231                         if (!rpmIsVerbose())
232                             prefix ? fputs(prefix, fp) : 0;
233
234                         if (queryFlags & QUERY_FOR_STATE) {
235                             if (fileStatesList) {
236                                 switch (fileStatesList[i]) {
237                                   case RPMFILE_STATE_NORMAL:
238                                     fputs(_("normal        "), fp); break;
239                                   case RPMFILE_STATE_REPLACED:
240                                     fputs(_("replaced      "), fp); break;
241                                   case RPMFILE_STATE_NOTINSTALLED:
242                                     fputs(_("not installed "), fp); break;
243                                   case RPMFILE_STATE_NETSHARED:
244                                     fputs(_("net shared    "), fp); break;
245                                   default:
246                                     fprintf(fp, _("(unknown %3d) "), 
247                                           (int)fileStatesList[i]);
248                                 }
249                             } else {
250                                 fputs(    _("(no state)    "), fp);
251                             }
252                         }
253
254                         if (queryFlags & QUERY_FOR_DUMPFILES) {
255                             fprintf(fp, "%s%s %d %d %s 0%o ", 
256                                    dirNames[dirIndexes[i]], baseNames[i],
257                                    fileSizeList[i], fileMTimeList[i],
258                                    fileMD5List[i], fileModeList[i]);
259
260                             if (fileOwnerList && fileGroupList)
261                                 fprintf(fp, "%s %s", fileOwnerList[i], 
262                                                 fileGroupList[i]);
263                             else if (fileUIDList && fileGIDList)
264                                 fprintf(fp, "%d %d", fileUIDList[i], 
265                                                 fileGIDList[i]);
266                             else {
267                                 rpmError(RPMERR_INTERNAL, _("package has "
268                                         "neither file owner or id lists"));
269                             }
270
271                             fprintf(fp, " %s %s %u ", 
272                                  fileFlagsList[i] & RPMFILE_CONFIG ? "1" : "0",
273                                  fileFlagsList[i] & RPMFILE_DOC ? "1" : "0",
274                                  (unsigned)fileRdevList[i]);
275
276                             if (strlen(fileLinktoList[i]))
277                                 fprintf(fp, "%s\n", fileLinktoList[i]);
278                             else
279                                 fprintf(fp, "X\n");
280
281                         } else if (!rpmIsVerbose()) {
282                             fputs(dirNames[dirIndexes[i]], fp);
283                             fputs(baseNames[i], fp);
284                             fputs("\n", fp);
285                         } else {
286                             char * filespec;
287
288                             filespec = xmalloc(strlen(dirNames[dirIndexes[i]])
289                                               + strlen(baseNames[i]) + 1);
290                             strcpy(filespec, dirNames[dirIndexes[i]]);
291                             strcat(filespec, baseNames[i]);
292                                         
293                             if (fileOwnerList && fileGroupList) {
294                                 printFileInfo(fp, filespec, fileSizeList[i],
295                                               fileModeList[i], fileMTimeList[i],
296                                               fileRdevList[i], 
297                                               fileOwnerList[i], 
298                                               fileGroupList[i], -1, 
299                                               -1, fileLinktoList[i]);
300                             } else if (fileUIDList && fileGIDList) {
301                                 printFileInfo(fp, filespec, fileSizeList[i],
302                                               fileModeList[i], fileMTimeList[i],
303                                               fileRdevList[i], NULL, 
304                                               NULL, fileUIDList[i], 
305                                               fileGIDList[i], 
306                                               fileLinktoList[i]);
307                             } else {
308                                 rpmError(RPMERR_INTERNAL, _("package has "
309                                         "neither file owner or id lists"));
310                             }
311
312                             free(filespec);
313                         }
314                     }
315                 }
316             
317                 free(dirNames);
318                 free(baseNames);
319                 free(fileLinktoList);
320                 free(fileMD5List);
321                 if (fileOwnerList) free(fileOwnerList);
322                 if (fileGroupList) free(fileGroupList);
323             }
324         }
325     }
326     return 0;   /* XXX FIXME: need real return code */
327 }
328
329 static void
330 printNewSpecfile(Spec spec)
331 {
332     struct speclines *sl = spec->sl;
333     struct spectags *st = spec->st;
334     char buf[8192];
335     int i, j;
336
337     if (sl == NULL || st == NULL)
338         return;
339
340     for (i = 0; i < st->st_ntags; i++) {
341         char *msgstr;
342         struct spectag *t;
343         t = st->st_t + i;
344
345         /* XXX Summary tag often precedes name, so build msgid now. */
346         if (t->t_msgid == NULL) {
347             char *n;
348             headerGetEntry(spec->packages->header, RPMTAG_NAME, NULL,
349                 (void **) &n, NULL);
350             sprintf(buf, "%s(%s)", n, tagName(t->t_tag));
351             t->t_msgid = xstrdup(buf);
352         }
353         msgstr = xstrdup(/*@-unrecog@*/ dgettext(specedit, t->t_msgid) /*@=unrecog@*/);
354
355         switch(t->t_tag) {
356         case RPMTAG_SUMMARY:
357         case RPMTAG_GROUP:
358             free(sl->sl_lines[t->t_startx]);
359             sl->sl_lines[t->t_startx] = NULL;
360             if (t->t_lang && strcmp(t->t_lang, RPMBUILD_DEFAULT_LANG))
361                 continue;
362             sprintf(buf, "%s: %s\n",
363                 ((t->t_tag == RPMTAG_GROUP) ? "Group" : "Summary"),
364                 msgstr);
365             sl->sl_lines[t->t_startx] = xstrdup(buf);
366             break;
367         case RPMTAG_DESCRIPTION:
368             for (j = 1; j < t->t_nlines; j++) {
369                 free(sl->sl_lines[t->t_startx + j]);
370                 sl->sl_lines[t->t_startx + j] = NULL;
371             }
372             if (t->t_lang && strcmp(t->t_lang, RPMBUILD_DEFAULT_LANG)) {
373                 free(sl->sl_lines[t->t_startx]);
374                 sl->sl_lines[t->t_startx] = NULL;
375                 continue;
376             }
377             sl->sl_lines[t->t_startx + 1] = xstrdup(msgstr);
378             if (t->t_nlines > 2)
379                 sl->sl_lines[t->t_startx + 2] = xstrdup("\n\n");
380             break;
381         }
382     }
383
384     for (i = 0; i < sl->sl_nlines; i++) {
385         if (sl->sl_lines[i] == NULL)
386             continue;
387         printf("%s", sl->sl_lines[i]);
388     }
389 }
390
391 void rpmDisplayQueryTags(FILE * f) {
392     const struct headerTagTableEntry * t;
393     int i;
394     const struct headerSprintfExtension * ext = rpmHeaderFormats;
395
396     for (i = 0, t = rpmTagTable; i < rpmTagTableSize; i++, t++) {
397         fprintf(f, "%s\n", t->name + 7);
398     }
399
400     while (ext->name) {
401         if (ext->type == HEADER_EXT_TAG)
402             fprintf(f, "%s\n", ext->name + 7), ext++;
403         else if (ext->type == HEADER_EXT_MORE)
404             ext = ext->u.more;
405         else
406             ext++;
407     }
408 }
409
410 int showMatches(QVA_t *qva, rpmdb db, dbiIndexSet matches, QVF_t showPackage)
411 {
412     Header h;
413     int ec = 0;
414     int i;
415
416     for (i = 0; i < dbiIndexSetCount(matches); i++) {
417         int rc;
418         unsigned int recOffset = dbiIndexRecordOffset(matches, i);
419         if (recOffset == 0)
420             continue;
421         rpmMessage(RPMMESS_DEBUG, _("record number %u\n"), recOffset);
422             
423         h = rpmdbGetRecord(db, recOffset);
424         if (h == NULL) {
425                 fprintf(stderr, _("error: could not read database record\n"));
426                 ec = 1;
427         } else {
428                 if ((rc = showPackage(qva, db, h)) != 0)
429                     ec = rc;
430                 headerFree(h);
431         }
432     }
433     return ec;
434 }
435
436 /*
437  * XXX Eliminate linkage loop into librpmbuild.a
438  */
439 int     (*parseSpecVec) (Spec *specp, const char *specFile, const char *rootdir,
440                 const char *buildRoot, int inBuildArch, const char *passPhrase,
441                 char *cookie, int anyarch, int force) = NULL;
442 void    (*freeSpecVec) (Spec spec) = NULL;
443 char    *specedit = NULL;
444
445 int rpmQueryVerify(QVA_t *qva, enum rpmQVSources source, const char * arg,
446         rpmdb db, QVF_t showPackage)
447 {
448     dbiIndexSet matches;
449     Header h;
450     int offset;
451     int rc;
452     int isSource;
453     int recNumber;
454     int retcode = 0;
455     char *end = NULL;
456
457   switch (source) {
458     case RPMQV_RPM:
459     { const char *myargv[2], **argv = myargv;;
460
461       /* XXX prepare for remglob */
462       argv[0] = arg;
463       argv[1] = NULL;
464       while ((arg = *argv++) != NULL) {
465         FD_t fd = Fopen(arg, "r.ufdio");
466         if (Ferror(fd)) {
467             /* XXX Fstrerror */
468             fprintf(stderr, _("open of %s failed: %s\n"), arg,
469 #ifndef NOTYET
470                         urlStrerror(arg));
471 #else
472                         Fstrerror(fd));
473 #endif
474             if (fd)
475                 Fclose(fd);
476             retcode = 1;
477             break;
478         }
479
480         retcode = rpmReadPackageHeader(fd, &h, &isSource, NULL, NULL);
481
482         Fclose(fd);
483
484         switch (retcode) {
485         case 0:
486             if (h == NULL) {
487                 fprintf(stderr, _("old format source packages cannot "
488                         "be queried\n"));
489                 retcode = 1;
490                 break;
491             }
492             retcode = showPackage(qva, db, h);
493             headerFree(h);
494             break;
495         case 1:
496             fprintf(stderr, _("%s does not appear to be a RPM package\n"), arg);
497             /*@fallthrough@*/
498         case 2:
499             fprintf(stderr, _("query of %s failed\n"), arg);
500             retcode = 1;
501             break;
502         }
503       }
504     }   break;
505
506     case RPMQV_SPECFILE:
507         if (showPackage != showQueryPackage)
508             return 1;
509
510         /* XXX Eliminate linkage dependency loop */
511         if (parseSpecVec == NULL || freeSpecVec == NULL)
512             return 1;
513
514       { Spec spec = NULL;
515         Package pkg;
516         char * buildRoot = NULL;
517         int inBuildArch = 0;
518         char * passPhrase = "";
519         char *cookie = NULL;
520         int anyarch = 1;
521         int force = 1;
522
523         rc = parseSpecVec(&spec, arg, "/", buildRoot, inBuildArch, passPhrase,
524                 cookie, anyarch, force);
525         if (rc || spec == NULL) {
526             
527             fprintf(stderr, _("query of specfile %s failed, can't parse\n"), arg);
528             if (spec != NULL) freeSpecVec(spec);
529             retcode = 1;
530             break;
531         }
532
533         if (specedit != NULL) {
534             printNewSpecfile(spec);
535             freeSpecVec(spec);
536             retcode = 0;
537             break;
538         }
539
540         for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
541             showPackage(qva, NULL, pkg->header);
542         }
543         freeSpecVec(spec);
544       } break;
545
546     case RPMQV_ALL:
547         for (offset = rpmdbFirstRecNum(db);
548              offset != 0;
549              offset = rpmdbNextRecNum(db, offset)) {
550                 h = rpmdbGetRecord(db, offset);
551                 if (h == NULL) {
552                     fprintf(stderr, _("could not read database record!\n"));
553                     return 1;
554                 }
555                 if ((rc = showPackage(qva, db, h)) != 0)
556                     retcode = rc;
557                 headerFree(h);
558         }
559         break;
560
561     case RPMQV_GROUP:
562         if (rpmdbFindByGroup(db, arg, &matches)) {
563             fprintf(stderr, _("group %s does not contain any packages\n"), arg);
564             retcode = 1;
565         } else {
566             retcode = showMatches(qva, db, matches, showPackage);
567             dbiFreeIndexRecord(matches);
568         }
569         break;
570
571     case RPMQV_TRIGGEREDBY:
572         if (rpmdbFindByTriggeredBy(db, arg, &matches)) {
573             fprintf(stderr, _("no package triggers %s\n"), arg);
574             retcode = 1;
575         } else {
576             retcode = showMatches(qva, db, matches, showPackage);
577             dbiFreeIndexRecord(matches);
578         }
579         break;
580
581     case RPMQV_WHATREQUIRES:
582         if (rpmdbFindByRequiredBy(db, arg, &matches)) {
583             fprintf(stderr, _("no package requires %s\n"), arg);
584             retcode = 1;
585         } else {
586             retcode = showMatches(qva, db, matches, showPackage);
587             dbiFreeIndexRecord(matches);
588         }
589         break;
590
591     case RPMQV_WHATPROVIDES:
592         if (arg[0] != '/') {
593             if (rpmdbFindByProvides(db, arg, &matches)) {
594                 fprintf(stderr, _("no package provides %s\n"), arg);
595                 retcode = 1;
596             } else {
597                 retcode = showMatches(qva, db, matches, showPackage);
598                 dbiFreeIndexRecord(matches);
599             }
600             break;
601         }
602         /*@fallthrough@*/
603     case RPMQV_PATH:
604         if (rpmdbFindByFile(db, arg, &matches)) {
605             int myerrno = 0;
606             if (access(arg, F_OK) != 0)
607                 myerrno = errno;
608             switch (myerrno) {
609             default:
610                 fprintf(stderr, _("file %s: %s\n"), arg, strerror(myerrno));
611                 break;
612             case 0:
613                 fprintf(stderr, _("file %s is not owned by any package\n"), arg);
614                 break;
615             }
616             retcode = 1;
617         } else {
618             retcode = showMatches(qva, db, matches, showPackage);
619             dbiFreeIndexRecord(matches);
620         }
621         break;
622
623     case RPMQV_DBOFFSET:
624         recNumber = strtoul(arg, &end, 10);
625         if ((*end) || (end == arg) || (recNumber == ULONG_MAX)) {
626             fprintf(stderr, _("invalid package number: %s\n"), arg);
627             return 1;
628         }
629         rpmMessage(RPMMESS_DEBUG, _("package record number: %d\n"), recNumber);
630         h = rpmdbGetRecord(db, recNumber);
631         if (h == NULL)  {
632             fprintf(stderr, _("record %d could not be read\n"), recNumber);
633             retcode = 1;
634         } else {
635             retcode = showPackage(qva, db, h);
636             headerFree(h);
637         }
638         break;
639
640     case RPMQV_PACKAGE:
641         rc = rpmdbFindByLabel(db, arg, &matches);
642         if (rc == 1) {
643             retcode = 1;
644             fprintf(stderr, _("package %s is not installed\n"), arg);
645         } else if (rc == 2) {
646             retcode = 1;
647             fprintf(stderr, _("error looking for package %s\n"), arg);
648         } else {
649             retcode = showMatches(qva, db, matches, showPackage);
650             dbiFreeIndexRecord(matches);
651         }
652         break;
653   }
654    
655     return retcode;
656 }
657
658 int rpmQuery(QVA_t *qva, enum rpmQVSources source, const char * arg)
659 {
660     rpmdb db = NULL;
661     int rc;
662
663     switch (source) {
664     case RPMQV_RPM:
665     case RPMQV_SPECFILE:
666         break;
667     default:
668         if (rpmdbOpen(qva->qva_prefix, &db, O_RDONLY, 0644)) {
669             fprintf(stderr, _("rpmQuery: rpmdbOpen() failed\n"));
670             return 1;
671         }
672         break;
673     }
674
675     rc = rpmQueryVerify(qva, source, arg, db, showQueryPackage);
676
677     if (db)
678         rpmdbClose(db);
679
680     return rc;
681 }
682
683 /* ======================================================================== */
684 #define POPT_QUERYFORMAT        1000
685 #define POPT_WHATREQUIRES       1001
686 #define POPT_WHATPROVIDES       1002
687 #define POPT_QUERYBYNUMBER      1003
688 #define POPT_TRIGGEREDBY        1004
689 #define POPT_DUMP               1005
690 #define POPT_SPECFILE           1006
691
692 /* ========== Query/Verify source popt args */
693 static void rpmQVSourceArgCallback( /*@unused@*/ poptContext con,
694         /*@unused@*/ enum poptCallbackReason reason,
695         const struct poptOption * opt, /*@unused@*/ const char * arg, 
696         const void * data)
697 {
698     QVA_t *qva = (QVA_t *) data;
699
700     switch (opt->val) {
701       case 'a': qva->qva_source |= RPMQV_ALL; qva->qva_sourceCount++; break;
702       case 'f': qva->qva_source |= RPMQV_PATH; qva->qva_sourceCount++; break;
703       case 'g': qva->qva_source |= RPMQV_GROUP; qva->qva_sourceCount++; break;
704       case 'p': qva->qva_source |= RPMQV_RPM; qva->qva_sourceCount++; break;
705       case POPT_WHATPROVIDES: qva->qva_source |= RPMQV_WHATPROVIDES; 
706                               qva->qva_sourceCount++; break;
707       case POPT_WHATREQUIRES: qva->qva_source |= RPMQV_WHATREQUIRES; 
708                               qva->qva_sourceCount++; break;
709       case POPT_TRIGGEREDBY: qva->qva_source |= RPMQV_TRIGGEREDBY;
710                               qva->qva_sourceCount++; break;
711
712 /* XXX SPECFILE is not verify sources */
713       case POPT_SPECFILE:
714         qva->qva_source |= RPMQV_SPECFILE;
715         qva->qva_sourceCount++;
716         break;
717       case POPT_QUERYBYNUMBER:
718         qva->qva_source |= RPMQV_DBOFFSET; 
719         qva->qva_sourceCount++;
720         break;
721     }
722 }
723
724 struct poptOption rpmQVSourcePoptTable[] = {
725         { NULL, '\0', POPT_ARG_CALLBACK | POPT_CBFLAG_INC_DATA, 
726                 rpmQVSourceArgCallback, 0, NULL, NULL },
727         { "file", 'f', 0, 0, 'f',
728                 N_("query package owning file"), "FILE" },
729         { "group", 'g', 0, 0, 'g',
730                 N_("query packages in group"), "GROUP" },
731         { "package", 'p', 0, 0, 'p',
732                 N_("query a package file"), NULL },
733         { "querybynumber", '\0', POPT_ARGFLAG_DOC_HIDDEN, 0, 
734                 POPT_QUERYBYNUMBER, NULL, NULL },
735         { "specfile", '\0', 0, 0, POPT_SPECFILE,
736                 N_("query a spec file"), NULL },
737         { "triggeredby", '\0', 0, 0, POPT_TRIGGEREDBY, 
738                 N_("query the pacakges triggered by the package"), "PACKAGE" },
739         { "whatrequires", '\0', 0, 0, POPT_WHATREQUIRES, 
740                 N_("query the packages which require a capability"), "CAPABILITY" },
741         { "whatprovides", '\0', 0, 0, POPT_WHATPROVIDES, 
742                 N_("query the packages which provide a capability"), "CAPABILITY" },
743         { 0, 0, 0, 0, 0,        NULL, NULL }
744 };
745
746 /* ========== Query specific popt args */
747
748 static void queryArgCallback(/*@unused@*/poptContext con, /*@unused@*/enum poptCallbackReason reason,
749                              const struct poptOption * opt, const char * arg, 
750                              const void * data)
751 {
752     QVA_t *qva = (QVA_t *) data;
753
754     switch (opt->val) {
755       case 'c': qva->qva_flags |= QUERY_FOR_CONFIG | QUERY_FOR_LIST; break;
756       case 'd': qva->qva_flags |= QUERY_FOR_DOCS | QUERY_FOR_LIST; break;
757       case 'l': qva->qva_flags |= QUERY_FOR_LIST; break;
758       case 's': qva->qva_flags |= QUERY_FOR_STATE | QUERY_FOR_LIST; break;
759       case POPT_DUMP: qva->qva_flags |= QUERY_FOR_DUMPFILES | QUERY_FOR_LIST; break;
760       case 'v': rpmIncreaseVerbosity();  break;
761
762       case POPT_QUERYFORMAT:
763       { char *qf = (char *)qva->qva_queryFormat;
764         if (qf) {
765             int len = strlen(qf) + strlen(arg) + 1;
766             qf = xrealloc(qf, len);
767             strcat(qf, arg);
768         } else {
769             qf = xmalloc(strlen(arg) + 1);
770             strcpy(qf, arg);
771         }
772         qva->qva_queryFormat = qf;
773       } break;
774     }
775 }
776
777 struct poptOption rpmQueryPoptTable[] = {
778         { NULL, '\0', POPT_ARG_CALLBACK | POPT_CBFLAG_INC_DATA, 
779                 queryArgCallback, 0, NULL, NULL },
780         { "configfiles", 'c', 0, 0, 'c',
781                 N_("list all configuration files"), NULL },
782         { "docfiles", 'd', 0, 0, 'd',
783                 N_("list all documentation files"), NULL },
784         { "dump", '\0', 0, 0, POPT_DUMP,
785                 N_("dump basic file information"), NULL },
786         { "list", 'l', 0, 0, 'l',
787                 N_("list files in package"), NULL },
788         { "qf", '\0', POPT_ARG_STRING | POPT_ARGFLAG_DOC_HIDDEN, 0, 
789                 POPT_QUERYFORMAT, NULL, NULL },
790         { "queryformat", '\0', POPT_ARG_STRING, 0, POPT_QUERYFORMAT,
791                 N_("use the following query format"), "QUERYFORMAT" },
792         { "specedit", '\0', POPT_ARG_STRING, &specedit, 0,
793                 N_("substitute i18n sections from the following catalogue"),
794                         "METACATALOGUE" },
795         { "state", 's', 0, 0, 's',
796                 N_("display the states of the listed files"), NULL },
797         { "verbose", 'v', 0, 0, 'v',
798                 N_("display a verbose file listing"), NULL },
799         { 0, 0, 0, 0, 0,        NULL, NULL }
800 };
801
802 /* ======================================================================== */