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