10 /* ======================================================================== */
11 static char * permsString(int mode)
13 char *perms = xstrdup("----------");
17 else if (S_ISLNK(mode))
19 else if (S_ISFIFO(mode))
21 else if (S_ISSOCK(mode))
23 else if (S_ISCHR(mode))
25 else if (S_ISBLK(mode))
28 if (mode & S_IRUSR) perms[1] = 'r';
29 if (mode & S_IWUSR) perms[2] = 'w';
30 if (mode & S_IXUSR) perms[3] = 'x';
32 if (mode & S_IRGRP) perms[4] = 'r';
33 if (mode & S_IWGRP) perms[5] = 'w';
34 if (mode & S_IXGRP) perms[6] = 'x';
36 if (mode & S_IROTH) perms[7] = 'r';
37 if (mode & S_IWOTH) perms[8] = 'w';
38 if (mode & S_IXOTH) perms[9] = 'x';
41 perms[3] = ((mode & S_IXUSR) ? 's' : 'S');
44 perms[6] = ((mode & S_IXGRP) ? 's' : 'S');
47 perms[9] = ((mode & S_IXOTH) ? 't' : 'T');
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)
59 char ownerfield[9], groupfield[9];
60 char timefield[100] = "";
61 time_t when = mtime; /* important if sizeof(int_32) ! sizeof(time_t) */
64 static struct tm nowtm;
65 const char * namefield = name;
68 /* On first call, grab snapshot of now */
72 nowtm = *tm; /* structure assignment */
75 perms = permsString(mode);
78 strncpy(ownerfield, owner, 8);
80 sprintf(ownerfield, "%-8d", uid);
84 strncpy(groupfield, group, 8);
86 sprintf(groupfield, "%-8d", gid);
89 /* this is normally right */
90 sprintf(sizefield, "%12u", size);
92 /* this knows too much about dev_t */
95 char *nf = alloca(strlen(name) + sizeof(" -> ") + strlen(linkto));
96 sprintf(nf, "%s -> %s", name, linkto);
98 } else if (S_ISCHR(mode)) {
100 sprintf(sizefield, "%3u, %3u", (rdev >> 8) & 0xff, rdev & 0xFF);
101 } else if (S_ISBLK(mode)) {
103 sprintf(sizefield, "%3u, %3u", (rdev >> 8) & 0xff, rdev & 0xFF);
106 /* Convert file mtime to display format */
107 tm = localtime(&when);
109 if (now > when + 6L * 30L * 24L * 60L * 60L || /* Old. */
110 now < when - 60L * 60L) /* In the future. */
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.
123 (void)strftime(timefield, sizeof(timefield) - 1, fmt, tm);
126 fprintf(fp, "%s %8s %8s %10s %s %s\n", perms, ownerfield, groupfield,
127 sizefield, timefield, namefield);
128 if (perms) free(perms);
131 static int queryHeader(FILE *fp, Header h, const char * chptr)
136 str = headerSprintf(h, chptr, rpmTagTable, rpmHeaderFormats, &error);
138 fprintf(stderr, _("error in format: %s\n"), error);
147 int showQueryPackage(QVA_t *qva, /*@unused@*/rpmdb db, Header h)
149 FILE *fp = stdout; /* XXX FIXME: pass as arg */
150 int queryFlags = qva->qva_flags;
151 const char *queryFormat = qva->qva_queryFormat;
153 const char * name, * version, * release;
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;
170 headerNVR(h, &name, &version, &release);
172 if (!queryFormat && !queryFlags) {
173 fprintf(fp, "%s-%s-%s\n", name, version, release);
176 queryHeader(fp, h, queryFormat);
178 if (queryFlags & QUERY_FOR_LIST) {
179 if (!headerGetEntry(h, RPMTAG_COMPFILELIST, &type,
180 (void **) &baseNameList, &count)) {
181 fputs(_("(contains no files)"), fp);
184 if (!headerGetEntry(h, RPMTAG_FILESTATES, &type,
185 (void **) &fileStatesList, &count)) {
186 fileStatesList = NULL;
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);
207 if (!headerGetEntry(h, RPMTAG_FILEUIDS, &type,
208 (void **) &fileUIDList, &count)) {
210 } else if (!headerGetEntry(h, RPMTAG_FILEGIDS, &type,
211 (void **) &fileGIDList, &count)) {
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;
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))) {
232 prefix ? fputs(prefix, fp) : 0;
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;
246 fprintf(fp, _("(unknown %3d) "),
247 (int)fileStatesList[i]);
250 fputs( _("(no state) "), fp);
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]);
260 if (fileOwnerList && fileGroupList)
261 fprintf(fp, "%s %s", fileOwnerList[i],
263 else if (fileUIDList && fileGIDList)
264 fprintf(fp, "%d %d", fileUIDList[i],
267 rpmError(RPMERR_INTERNAL, _("package has "
268 "neither file owner or id lists"));
271 fprintf(fp, " %s %s %u ",
272 fileFlagsList[i] & RPMFILE_CONFIG ? "1" : "0",
273 fileFlagsList[i] & RPMFILE_DOC ? "1" : "0",
274 (unsigned)fileRdevList[i]);
276 if (strlen(fileLinktoList[i]))
277 fprintf(fp, "%s\n", fileLinktoList[i]);
281 } else if (!rpmIsVerbose()) {
282 fputs(dirList[dirIndexList[i]], fp);
283 fputs(baseNameList[i], fp);
288 filespec = xmalloc(strlen(dirList[dirIndexList[i]])
289 + strlen(baseNameList[i]) + 1);
290 strcpy(filespec, dirList[dirIndexList[i]]);
291 strcat(filespec, baseNameList[i]);
293 if (fileOwnerList && fileGroupList) {
294 printFileInfo(fp, filespec, fileSizeList[i],
295 fileModeList[i], fileMTimeList[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],
308 rpmError(RPMERR_INTERNAL, _("package has "
309 "neither file owner or id lists"));
319 free(fileLinktoList);
321 if (fileOwnerList) free(fileOwnerList);
322 if (fileGroupList) free(fileGroupList);
326 return 0; /* XXX FIXME: need real return code */
330 printNewSpecfile(Spec spec)
332 struct speclines *sl = spec->sl;
333 struct spectags *st = spec->st;
337 if (sl == NULL || st == NULL)
340 for (i = 0; i < st->st_ntags; i++) {
345 /* XXX Summary tag often precedes name, so build msgid now. */
346 if (t->t_msgid == NULL) {
348 headerGetEntry(spec->packages->header, RPMTAG_NAME, NULL,
350 sprintf(buf, "%s(%s)", n, tagName(t->t_tag));
351 t->t_msgid = xstrdup(buf);
353 msgstr = xstrdup(/*@-unrecog@*/ dgettext(specedit, t->t_msgid) /*@=unrecog@*/);
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))
362 sprintf(buf, "%s: %s\n",
363 ((t->t_tag == RPMTAG_GROUP) ? "Group" : "Summary"),
365 sl->sl_lines[t->t_startx] = xstrdup(buf);
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;
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;
377 sl->sl_lines[t->t_startx + 1] = xstrdup(msgstr);
379 sl->sl_lines[t->t_startx + 2] = xstrdup("\n\n");
384 for (i = 0; i < sl->sl_nlines; i++) {
385 if (sl->sl_lines[i] == NULL)
387 printf("%s", sl->sl_lines[i]);
391 void rpmDisplayQueryTags(FILE * f) {
392 const struct headerTagTableEntry * t;
394 const struct headerSprintfExtension * ext = rpmHeaderFormats;
396 for (i = 0, t = rpmTagTable; i < rpmTagTableSize; i++, t++) {
397 fprintf(f, "%s\n", t->name + 7);
401 if (ext->type == HEADER_EXT_TAG)
402 fprintf(f, "%s\n", ext->name + 7), ext++;
403 else if (ext->type == HEADER_EXT_MORE)
410 int showMatches(QVA_t *qva, rpmdb db, dbiIndexSet matches, QVF_t showPackage)
416 for (i = 0; i < dbiIndexSetCount(matches); i++) {
418 unsigned int recOffset = dbiIndexRecordOffset(matches, i);
421 rpmMessage(RPMMESS_DEBUG, _("record number %u\n"), recOffset);
423 h = rpmdbGetRecord(db, recOffset);
425 fprintf(stderr, _("error: could not read database record\n"));
428 if ((rc = showPackage(qva, db, h)) != 0)
437 * XXX Eliminate linkage loop into librpmbuild.a
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;
445 int rpmQueryVerify(QVA_t *qva, enum rpmQVSources source, const char * arg,
446 rpmdb db, QVF_t showPackage)
459 { const char *myargv[2], **argv = myargv;;
461 /* XXX prepare for remglob */
464 while ((arg = *argv++) != NULL) {
465 FD_t fd = Fopen(arg, "r.ufdio");
468 fprintf(stderr, _("open of %s failed: %s\n"), arg,
479 retcode = rpmReadPackageHeader(fd, &h, &isSource, NULL, NULL);
486 fprintf(stderr, _("old format source packages cannot "
491 retcode = showPackage(qva, db, h);
495 fprintf(stderr, _("%s does not appear to be a RPM package\n"), arg);
498 fprintf(stderr, _("query of %s failed\n"), arg);
506 if (showPackage != showQueryPackage)
509 /* XXX Eliminate linkage dependency loop */
510 if (parseSpecVec == NULL || freeSpecVec == NULL)
515 char * buildRoot = NULL;
517 char * passPhrase = "";
522 rc = parseSpecVec(&spec, arg, "/", buildRoot, inBuildArch, passPhrase,
523 cookie, anyarch, force);
524 if (rc || spec == NULL) {
526 fprintf(stderr, _("query of specfile %s failed, can't parse\n"), arg);
527 if (spec != NULL) freeSpecVec(spec);
532 if (specedit != NULL) {
533 printNewSpecfile(spec);
539 for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
540 showPackage(qva, NULL, pkg->header);
546 for (offset = rpmdbFirstRecNum(db);
548 offset = rpmdbNextRecNum(db, offset)) {
549 h = rpmdbGetRecord(db, offset);
551 fprintf(stderr, _("could not read database record!\n"));
554 if ((rc = showPackage(qva, db, h)) != 0)
561 if (rpmdbFindByGroup(db, arg, &matches)) {
562 fprintf(stderr, _("group %s does not contain any packages\n"), arg);
565 retcode = showMatches(qva, db, matches, showPackage);
566 dbiFreeIndexRecord(matches);
570 case RPMQV_WHATPROVIDES:
571 if (rpmdbFindByProvides(db, arg, &matches)) {
572 fprintf(stderr, _("no package provides %s\n"), arg);
575 retcode = showMatches(qva, db, matches, showPackage);
576 dbiFreeIndexRecord(matches);
580 case RPMQV_TRIGGEREDBY:
581 if (rpmdbFindByTriggeredBy(db, arg, &matches)) {
582 fprintf(stderr, _("no package triggers %s\n"), arg);
585 retcode = showMatches(qva, db, matches, showPackage);
586 dbiFreeIndexRecord(matches);
590 case RPMQV_WHATREQUIRES:
591 if (rpmdbFindByRequiredBy(db, arg, &matches)) {
592 fprintf(stderr, _("no package requires %s\n"), arg);
595 retcode = showMatches(qva, db, matches, showPackage);
596 dbiFreeIndexRecord(matches);
601 if (rpmdbFindByFile(db, arg, &matches)) {
603 if (access(arg, F_OK) != 0)
607 fprintf(stderr, _("file %s: %s\n"), arg, strerror(myerrno));
610 fprintf(stderr, _("file %s is not owned by any package\n"), arg);
615 retcode = showMatches(qva, db, matches, showPackage);
616 dbiFreeIndexRecord(matches);
621 recNumber = strtoul(arg, &end, 10);
622 if ((*end) || (end == arg) || (recNumber == ULONG_MAX)) {
623 fprintf(stderr, _("invalid package number: %s\n"), arg);
626 rpmMessage(RPMMESS_DEBUG, _("package record number: %d\n"), recNumber);
627 h = rpmdbGetRecord(db, recNumber);
629 fprintf(stderr, _("record %d could not be read\n"), recNumber);
632 retcode = showPackage(qva, db, h);
638 rc = rpmdbFindByLabel(db, arg, &matches);
641 fprintf(stderr, _("package %s is not installed\n"), arg);
642 } else if (rc == 2) {
644 fprintf(stderr, _("error looking for package %s\n"), arg);
646 retcode = showMatches(qva, db, matches, showPackage);
647 dbiFreeIndexRecord(matches);
655 int rpmQuery(QVA_t *qva, enum rpmQVSources source, const char * arg)
665 if (rpmdbOpen(qva->qva_prefix, &db, O_RDONLY, 0644)) {
666 fprintf(stderr, _("rpmQuery: rpmdbOpen() failed\n"));
672 rc = rpmQueryVerify(qva, source, arg, db, showQueryPackage);
680 /* ======================================================================== */
681 #define POPT_QUERYFORMAT 1000
682 #define POPT_WHATREQUIRES 1001
683 #define POPT_WHATPROVIDES 1002
684 #define POPT_QUERYBYNUMBER 1003
685 #define POPT_TRIGGEREDBY 1004
686 #define POPT_DUMP 1005
687 #define POPT_SPECFILE 1006
689 /* ========== Query/Verify source popt args */
690 static void rpmQVSourceArgCallback( /*@unused@*/ poptContext con,
691 /*@unused@*/ enum poptCallbackReason reason,
692 const struct poptOption * opt, /*@unused@*/ const char * arg,
695 QVA_t *qva = (QVA_t *) data;
698 case 'a': qva->qva_source |= RPMQV_ALL; qva->qva_sourceCount++; break;
699 case 'f': qva->qva_source |= RPMQV_PATH; qva->qva_sourceCount++; break;
700 case 'g': qva->qva_source |= RPMQV_GROUP; qva->qva_sourceCount++; break;
701 case 'p': qva->qva_source |= RPMQV_RPM; qva->qva_sourceCount++; break;
702 case POPT_WHATPROVIDES: qva->qva_source |= RPMQV_WHATPROVIDES;
703 qva->qva_sourceCount++; break;
704 case POPT_WHATREQUIRES: qva->qva_source |= RPMQV_WHATREQUIRES;
705 qva->qva_sourceCount++; break;
706 case POPT_TRIGGEREDBY: qva->qva_source |= RPMQV_TRIGGEREDBY;
707 qva->qva_sourceCount++; break;
709 /* XXX SPECFILE is not verify sources */
711 qva->qva_source |= RPMQV_SPECFILE;
712 qva->qva_sourceCount++;
714 case POPT_QUERYBYNUMBER:
715 qva->qva_source |= RPMQV_DBOFFSET;
716 qva->qva_sourceCount++;
721 struct poptOption rpmQVSourcePoptTable[] = {
722 { NULL, '\0', POPT_ARG_CALLBACK | POPT_CBFLAG_INC_DATA,
723 rpmQVSourceArgCallback, 0, NULL, NULL },
724 { "file", 'f', 0, 0, 'f',
725 N_("query package owning file"), "FILE" },
726 { "group", 'g', 0, 0, 'g',
727 N_("query packages in group"), "GROUP" },
728 { "package", 'p', 0, 0, 'p',
729 N_("query a package file"), NULL },
730 { "querybynumber", '\0', POPT_ARGFLAG_DOC_HIDDEN, 0,
731 POPT_QUERYBYNUMBER, NULL, NULL },
732 { "specfile", '\0', 0, 0, POPT_SPECFILE,
733 N_("query a spec file"), NULL },
734 { "triggeredby", '\0', 0, 0, POPT_TRIGGEREDBY,
735 N_("query the pacakges triggered by the package"), "PACKAGE" },
736 { "whatrequires", '\0', 0, 0, POPT_WHATREQUIRES,
737 N_("query the packages which require a capability"), "CAPABILITY" },
738 { "whatprovides", '\0', 0, 0, POPT_WHATPROVIDES,
739 N_("query the packages which provide a capability"), "CAPABILITY" },
740 { 0, 0, 0, 0, 0, NULL, NULL }
743 /* ========== Query specific popt args */
745 static void queryArgCallback(/*@unused@*/poptContext con, /*@unused@*/enum poptCallbackReason reason,
746 const struct poptOption * opt, const char * arg,
749 QVA_t *qva = (QVA_t *) data;
752 case 'c': qva->qva_flags |= QUERY_FOR_CONFIG | QUERY_FOR_LIST; break;
753 case 'd': qva->qva_flags |= QUERY_FOR_DOCS | QUERY_FOR_LIST; break;
754 case 'l': qva->qva_flags |= QUERY_FOR_LIST; break;
755 case 's': qva->qva_flags |= QUERY_FOR_STATE | QUERY_FOR_LIST; break;
756 case POPT_DUMP: qva->qva_flags |= QUERY_FOR_DUMPFILES | QUERY_FOR_LIST; break;
757 case 'v': rpmIncreaseVerbosity(); break;
759 case POPT_QUERYFORMAT:
760 { char *qf = (char *)qva->qva_queryFormat;
762 int len = strlen(qf) + strlen(arg) + 1;
763 qf = xrealloc(qf, len);
766 qf = xmalloc(strlen(arg) + 1);
769 qva->qva_queryFormat = qf;
774 struct poptOption rpmQueryPoptTable[] = {
775 { NULL, '\0', POPT_ARG_CALLBACK | POPT_CBFLAG_INC_DATA,
776 queryArgCallback, 0, NULL, NULL },
777 { "configfiles", 'c', 0, 0, 'c',
778 N_("list all configuration files"), NULL },
779 { "docfiles", 'd', 0, 0, 'd',
780 N_("list all documentation files"), NULL },
781 { "dump", '\0', 0, 0, POPT_DUMP,
782 N_("dump basic file information"), NULL },
783 { "list", 'l', 0, 0, 'l',
784 N_("list files in package"), NULL },
785 { "qf", '\0', POPT_ARG_STRING | POPT_ARGFLAG_DOC_HIDDEN, 0,
786 POPT_QUERYFORMAT, NULL, NULL },
787 { "queryformat", '\0', POPT_ARG_STRING, 0, POPT_QUERYFORMAT,
788 N_("use the following query format"), "QUERYFORMAT" },
789 { "specedit", '\0', POPT_ARG_STRING, &specedit, 0,
790 N_("substitute i18n sections from the following catalogue"),
792 { "state", 's', 0, 0, 's',
793 N_("display the states of the listed files"), NULL },
794 { "verbose", 'v', 0, 0, 'v',
795 N_("display a verbose file listing"), NULL },
796 { 0, 0, 0, 0, 0, NULL, NULL }
799 /* ======================================================================== */