Make fdFileno() static, use Fileno()/Ferror() analogues throughout.
[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 ** dirList, ** baseNameList;
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 * dirIndexList;
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 **) &baseNameList, &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 **) &dirList, NULL);
190                 headerGetEntry(h, RPMTAG_COMPFILEDIRS, NULL, 
191                          (void **) &dirIndexList, 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                                    dirList[dirIndexList[i]], baseNameList[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(dirList[dirIndexList[i]], fp);
283                             fputs(baseNameList[i], fp);
284                             fputs("\n", fp);
285                         } else {
286                             char * filespec;
287
288                             filespec = xmalloc(strlen(dirList[dirIndexList[i]])
289                                               + strlen(baseNameList[i]) + 1);
290                             strcpy(filespec, dirList[dirIndexList[i]]);
291                             strcat(filespec, baseNameList[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(dirList);
318                 free(baseNameList);
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 *buildRoot,
440                 int inBuildArch, const char *passPhrase, char *cookie, int anyarch,
441                 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       { FD_t fd;
460
461         fd = ufdOpen(arg, O_RDONLY, 0);
462         if (Ferror(fd)) {
463             /* XXX Fstrerror */
464             fprintf(stderr, _("open of %s failed: %s\n"), arg,urlStrerror(arg));
465             Fclose(fd);
466             retcode = 1;
467             break;
468         }
469
470         retcode = rpmReadPackageHeader(fd, &h, &isSource, NULL, NULL);
471
472         Fclose(fd);
473
474         switch (retcode) {
475         case 0:
476             if (h == NULL) {
477                 fprintf(stderr, _("old format source packages cannot "
478                         "be queried\n"));
479                 retcode = 1;
480                 break;
481             }
482             retcode = showPackage(qva, db, h);
483             headerFree(h);
484             break;
485         case 1:
486             fprintf(stderr, _("%s does not appear to be a RPM package\n"), arg);
487             /*@fallthrough@*/
488         case 2:
489             fprintf(stderr, _("query of %s failed\n"), arg);
490             retcode = 1;
491             break;
492         }
493       } break;
494
495       case RPMQV_SPECFILE:
496         if (showPackage != showQueryPackage)
497             return 1;
498
499         /* XXX Eliminate linkage dependency loop */
500         if (parseSpecVec == NULL || freeSpecVec == NULL)
501             return 1;
502
503       { Spec spec = NULL;
504         Package pkg;
505         char * buildRoot = NULL;
506         int inBuildArch = 0;
507         char * passPhrase = "";
508         char *cookie = NULL;
509         int anyarch = 1;
510         int force = 1;
511
512         rc = parseSpecVec(&spec, arg, buildRoot, inBuildArch, passPhrase,
513                 cookie, anyarch, force);
514         if (rc || spec == NULL) {
515             
516             fprintf(stderr, _("query of specfile %s failed, can't parse\n"), arg);
517             if (spec != NULL) freeSpecVec(spec);
518             retcode = 1;
519             break;
520         }
521
522         if (specedit != NULL) {
523             printNewSpecfile(spec);
524             freeSpecVec(spec);
525             retcode = 0;
526             break;
527         }
528
529         for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
530             showPackage(qva, NULL, pkg->header);
531         }
532         freeSpecVec(spec);
533       } break;
534
535       case RPMQV_ALL:
536         for (offset = rpmdbFirstRecNum(db);
537              offset != 0;
538              offset = rpmdbNextRecNum(db, offset)) {
539                 h = rpmdbGetRecord(db, offset);
540                 if (h == NULL) {
541                     fprintf(stderr, _("could not read database record!\n"));
542                     return 1;
543                 }
544                 if ((rc = showPackage(qva, db, h)) != 0)
545                     retcode = rc;
546                 headerFree(h);
547         }
548         break;
549
550       case RPMQV_GROUP:
551         if (rpmdbFindByGroup(db, arg, &matches)) {
552             fprintf(stderr, _("group %s does not contain any packages\n"), arg);
553             retcode = 1;
554         } else {
555             retcode = showMatches(qva, db, matches, showPackage);
556             dbiFreeIndexRecord(matches);
557         }
558         break;
559
560       case RPMQV_WHATPROVIDES:
561         if (rpmdbFindByProvides(db, arg, &matches)) {
562             fprintf(stderr, _("no package provides %s\n"), arg);
563             retcode = 1;
564         } else {
565             retcode = showMatches(qva, db, matches, showPackage);
566             dbiFreeIndexRecord(matches);
567         }
568         break;
569
570       case RPMQV_TRIGGEREDBY:
571         if (rpmdbFindByTriggeredBy(db, arg, &matches)) {
572             fprintf(stderr, _("no package triggers %s\n"), arg);
573             retcode = 1;
574         } else {
575             retcode = showMatches(qva, db, matches, showPackage);
576             dbiFreeIndexRecord(matches);
577         }
578         break;
579
580       case RPMQV_WHATREQUIRES:
581         if (rpmdbFindByRequiredBy(db, arg, &matches)) {
582             fprintf(stderr, _("no package requires %s\n"), arg);
583             retcode = 1;
584         } else {
585             retcode = showMatches(qva, db, matches, showPackage);
586             dbiFreeIndexRecord(matches);
587         }
588         break;
589
590       case RPMQV_PATH:
591         if (rpmdbFindByFile(db, arg, &matches)) {
592             int myerrno = 0;
593             if (access(arg, F_OK) != 0)
594                 myerrno = errno;
595             switch (myerrno) {
596             default:
597                 fprintf(stderr, _("file %s: %s\n"), arg, strerror(myerrno));
598                 break;
599             case 0:
600                 fprintf(stderr, _("file %s is not owned by any package\n"), arg);
601                 break;
602             }
603             retcode = 1;
604         } else {
605             retcode = showMatches(qva, db, matches, showPackage);
606             dbiFreeIndexRecord(matches);
607         }
608         break;
609
610       case RPMQV_DBOFFSET:
611         recNumber = strtoul(arg, &end, 10);
612         if ((*end) || (end == arg) || (recNumber == ULONG_MAX)) {
613             fprintf(stderr, _("invalid package number: %s\n"), arg);
614             return 1;
615         }
616         rpmMessage(RPMMESS_DEBUG, _("package record number: %d\n"), recNumber);
617         h = rpmdbGetRecord(db, recNumber);
618         if (h == NULL)  {
619             fprintf(stderr, _("record %d could not be read\n"), recNumber);
620             retcode = 1;
621         } else {
622             retcode = showPackage(qva, db, h);
623             headerFree(h);
624         }
625         break;
626
627       case RPMQV_PACKAGE:
628         rc = rpmdbFindByLabel(db, arg, &matches);
629         if (rc == 1) {
630             retcode = 1;
631             fprintf(stderr, _("package %s is not installed\n"), arg);
632         } else if (rc == 2) {
633             retcode = 1;
634             fprintf(stderr, _("error looking for package %s\n"), arg);
635         } else {
636             retcode = showMatches(qva, db, matches, showPackage);
637             dbiFreeIndexRecord(matches);
638         }
639         break;
640     }
641    
642     return retcode;
643 }
644
645 int rpmQuery(QVA_t *qva, enum rpmQVSources source, const char * arg)
646 {
647     rpmdb db = NULL;
648     int rc;
649
650     switch (source) {
651     case RPMQV_RPM:
652     case RPMQV_SPECFILE:
653         break;
654     default:
655         if (rpmdbOpen(qva->qva_prefix, &db, O_RDONLY, 0644)) {
656             fprintf(stderr, _("rpmQuery: rpmdbOpen() failed\n"));
657             return 1;
658         }
659         break;
660     }
661
662     rc = rpmQueryVerify(qva, source, arg, db, showQueryPackage);
663
664     if (db)
665         rpmdbClose(db);
666
667     return rc;
668 }
669
670 /* ======================================================================== */
671 #define POPT_QUERYFORMAT        1000
672 #define POPT_WHATREQUIRES       1001
673 #define POPT_WHATPROVIDES       1002
674 #define POPT_QUERYBYNUMBER      1003
675 #define POPT_TRIGGEREDBY        1004
676 #define POPT_DUMP               1005
677 #define POPT_SPECFILE           1006
678
679 /* ========== Query/Verify source popt args */
680 static void rpmQVSourceArgCallback( /*@unused@*/ poptContext con,
681         /*@unused@*/ enum poptCallbackReason reason,
682         const struct poptOption * opt, /*@unused@*/ const char * arg, 
683         const void * data)
684 {
685     QVA_t *qva = (QVA_t *) data;
686
687     switch (opt->val) {
688       case 'a': qva->qva_source |= RPMQV_ALL; qva->qva_sourceCount++; break;
689       case 'f': qva->qva_source |= RPMQV_PATH; qva->qva_sourceCount++; break;
690       case 'g': qva->qva_source |= RPMQV_GROUP; qva->qva_sourceCount++; break;
691       case 'p': qva->qva_source |= RPMQV_RPM; qva->qva_sourceCount++; break;
692       case POPT_WHATPROVIDES: qva->qva_source |= RPMQV_WHATPROVIDES; 
693                               qva->qva_sourceCount++; break;
694       case POPT_WHATREQUIRES: qva->qva_source |= RPMQV_WHATREQUIRES; 
695                               qva->qva_sourceCount++; break;
696       case POPT_TRIGGEREDBY: qva->qva_source |= RPMQV_TRIGGEREDBY;
697                               qva->qva_sourceCount++; break;
698
699 /* XXX SPECFILE is not verify sources */
700       case POPT_SPECFILE:
701         qva->qva_source |= RPMQV_SPECFILE;
702         qva->qva_sourceCount++;
703         break;
704       case POPT_QUERYBYNUMBER:
705         qva->qva_source |= RPMQV_DBOFFSET; 
706         qva->qva_sourceCount++;
707         break;
708     }
709 }
710
711 struct poptOption rpmQVSourcePoptTable[] = {
712         { NULL, '\0', POPT_ARG_CALLBACK | POPT_CBFLAG_INC_DATA, 
713                 rpmQVSourceArgCallback, 0, NULL, NULL },
714         { "file", 'f', 0, 0, 'f',
715                 N_("query package owning file"), "FILE" },
716         { "group", 'g', 0, 0, 'g',
717                 N_("query packages in group"), "GROUP" },
718         { "package", 'p', 0, 0, 'p',
719                 N_("query a package file"), NULL },
720         { "querybynumber", '\0', POPT_ARGFLAG_DOC_HIDDEN, 0, 
721                 POPT_QUERYBYNUMBER, NULL, NULL },
722         { "specfile", '\0', 0, 0, POPT_SPECFILE,
723                 N_("query a spec file"), NULL },
724         { "triggeredby", '\0', 0, 0, POPT_TRIGGEREDBY, 
725                 N_("query the pacakges triggered by the package"), "PACKAGE" },
726         { "whatrequires", '\0', 0, 0, POPT_WHATREQUIRES, 
727                 N_("query the packages which require a capability"), "CAPABILITY" },
728         { "whatprovides", '\0', 0, 0, POPT_WHATPROVIDES, 
729                 N_("query the packages which provide a capability"), "CAPABILITY" },
730         { 0, 0, 0, 0, 0,        NULL, NULL }
731 };
732
733 /* ========== Query specific popt args */
734
735 static void queryArgCallback(/*@unused@*/poptContext con, /*@unused@*/enum poptCallbackReason reason,
736                              const struct poptOption * opt, const char * arg, 
737                              const void * data)
738 {
739     QVA_t *qva = (QVA_t *) data;
740
741     switch (opt->val) {
742       case 'c': qva->qva_flags |= QUERY_FOR_CONFIG | QUERY_FOR_LIST; break;
743       case 'd': qva->qva_flags |= QUERY_FOR_DOCS | QUERY_FOR_LIST; break;
744       case 'l': qva->qva_flags |= QUERY_FOR_LIST; break;
745       case 's': qva->qva_flags |= QUERY_FOR_STATE | QUERY_FOR_LIST; break;
746       case POPT_DUMP: qva->qva_flags |= QUERY_FOR_DUMPFILES | QUERY_FOR_LIST; break;
747       case 'v': rpmIncreaseVerbosity();  break;
748
749       case POPT_QUERYFORMAT:
750       { char *qf = (char *)qva->qva_queryFormat;
751         if (qf) {
752             int len = strlen(qf) + strlen(arg) + 1;
753             qf = xrealloc(qf, len);
754             strcat(qf, arg);
755         } else {
756             qf = xmalloc(strlen(arg) + 1);
757             strcpy(qf, arg);
758         }
759         qva->qva_queryFormat = qf;
760       } break;
761     }
762 }
763
764 struct poptOption rpmQueryPoptTable[] = {
765         { NULL, '\0', POPT_ARG_CALLBACK | POPT_CBFLAG_INC_DATA, 
766                 queryArgCallback, 0, NULL, NULL },
767         { "configfiles", 'c', 0, 0, 'c',
768                 N_("list all configuration files"), NULL },
769         { "docfiles", 'd', 0, 0, 'd',
770                 N_("list all documentation files"), NULL },
771         { "dump", '\0', 0, 0, POPT_DUMP,
772                 N_("dump basic file information"), NULL },
773         { "list", 'l', 0, 0, 'l',
774                 N_("list files in package"), NULL },
775         { "qf", '\0', POPT_ARG_STRING | POPT_ARGFLAG_DOC_HIDDEN, 0, 
776                 POPT_QUERYFORMAT, NULL, NULL },
777         { "queryformat", '\0', POPT_ARG_STRING, 0, POPT_QUERYFORMAT,
778                 N_("use the following query format"), "QUERYFORMAT" },
779         { "specedit", '\0', POPT_ARG_STRING, &specedit, 0,
780                 N_("substitute i18n sections from the following catalogue"),
781                         "METACATALOGUE" },
782         { "state", 's', 0, 0, 's',
783                 N_("display the states of the listed files"), NULL },
784         { "verbose", 'v', 0, 0, 'v',
785                 N_("display a verbose file listing"), NULL },
786         { 0, 0, 0, 0, 0,        NULL, NULL }
787 };
788
789 /* ======================================================================== */