12 /* ======================================================================== */
13 static char * permsString(int mode)
15 char *perms = xstrdup("----------");
19 else if (S_ISLNK(mode))
21 else if (S_ISFIFO(mode))
23 else if (S_ISSOCK(mode))
25 else if (S_ISCHR(mode))
27 else if (S_ISBLK(mode))
30 if (mode & S_IRUSR) perms[1] = 'r';
31 if (mode & S_IWUSR) perms[2] = 'w';
32 if (mode & S_IXUSR) perms[3] = 'x';
34 if (mode & S_IRGRP) perms[4] = 'r';
35 if (mode & S_IWGRP) perms[5] = 'w';
36 if (mode & S_IXGRP) perms[6] = 'x';
38 if (mode & S_IROTH) perms[7] = 'r';
39 if (mode & S_IWOTH) perms[8] = 'w';
40 if (mode & S_IXOTH) perms[9] = 'x';
43 perms[3] = ((mode & S_IXUSR) ? 's' : 'S');
46 perms[6] = ((mode & S_IXGRP) ? 's' : 'S');
49 perms[9] = ((mode & S_IXOTH) ? 't' : 'T');
54 static void printFileInfo(FILE *fp, const char * name,
55 unsigned int size, unsigned short mode,
56 unsigned int mtime, unsigned short rdev,
57 const char * owner, const char * group,
58 int uid, int gid, const char * linkto)
61 char ownerfield[9], groupfield[9];
62 char timefield[100] = "";
63 time_t when = mtime; /* important if sizeof(int_32) ! sizeof(time_t) */
66 static struct tm nowtm;
67 const char * namefield = name;
70 /* On first call, grab snapshot of now */
74 nowtm = *tm; /* structure assignment */
77 perms = permsString(mode);
80 strncpy(ownerfield, owner, 8);
82 sprintf(ownerfield, "%-8d", uid);
86 strncpy(groupfield, group, 8);
88 sprintf(groupfield, "%-8d", gid);
91 /* this is normally right */
92 sprintf(sizefield, "%12u", size);
94 /* this knows too much about dev_t */
97 char *nf = alloca(strlen(name) + sizeof(" -> ") + strlen(linkto));
98 sprintf(nf, "%s -> %s", name, linkto);
100 } else if (S_ISCHR(mode)) {
102 sprintf(sizefield, "%3u, %3u", (rdev >> 8) & 0xff, rdev & 0xFF);
103 } else if (S_ISBLK(mode)) {
105 sprintf(sizefield, "%3u, %3u", (rdev >> 8) & 0xff, rdev & 0xFF);
108 /* Convert file mtime to display format */
109 tm = localtime(&when);
111 if (now > when + 6L * 30L * 24L * 60L * 60L || /* Old. */
112 now < when - 60L * 60L) /* In the future. */
114 /* The file is fairly old or in the future.
115 * POSIX says the cutoff is 6 months old;
116 * approximate this by 6*30 days.
117 * Allow a 1 hour slop factor for what is considered "the future",
118 * to allow for NFS server/client clock disagreement.
119 * Show the year instead of the time of day.
125 (void)strftime(timefield, sizeof(timefield) - 1, fmt, tm);
128 fprintf(fp, "%s %8s %8s %10s %s %s\n", perms, ownerfield, groupfield,
129 sizefield, timefield, namefield);
130 if (perms) free(perms);
133 static int queryHeader(FILE *fp, Header h, const char * chptr)
138 str = headerSprintf(h, chptr, rpmTagTable, rpmHeaderFormats, &errstr);
140 fprintf(stderr, _("error in format: %s\n"), errstr);
149 int showQueryPackage(QVA_t *qva, /*@unused@*/rpmdb db, Header h)
151 FILE *fp = stdout; /* XXX FIXME: pass as arg */
152 int queryFlags = qva->qva_flags;
153 const char *queryFormat = qva->qva_queryFormat;
155 const char * name, * version, * release;
157 char * prefix = NULL;
158 const char ** dirNames, ** baseNames;
159 const char ** fileMD5List;
160 const char * fileStatesList;
161 const char ** fileOwnerList = NULL;
162 const char ** fileGroupList = NULL;
163 const char ** fileLinktoList;
164 int_32 * fileFlagsList, * fileMTimeList, * fileSizeList;
165 int_32 * fileUIDList = NULL;
166 int_32 * fileGIDList = NULL;
167 uint_16 * fileModeList;
168 uint_16 * fileRdevList;
172 headerNVR(h, &name, &version, &release);
174 if (!queryFormat && !queryFlags) {
175 fprintf(fp, "%s-%s-%s\n", name, version, release);
178 queryHeader(fp, h, queryFormat);
180 if (queryFlags & QUERY_FOR_LIST) {
181 if (!headerGetEntry(h, RPMTAG_BASENAMES, &type,
182 (void **) &baseNames, &count)) {
183 fputs(_("(contains no files)"), fp);
186 if (!headerGetEntry(h, RPMTAG_FILESTATES, &type,
187 (void **) &fileStatesList, &count)) {
188 fileStatesList = NULL;
190 headerGetEntry(h, RPMTAG_DIRNAMES, NULL,
191 (void **) &dirNames, NULL);
192 headerGetEntry(h, RPMTAG_DIRINDEXES, NULL,
193 (void **) &dirIndexes, NULL);
194 headerGetEntry(h, RPMTAG_FILEFLAGS, &type,
195 (void **) &fileFlagsList, &count);
196 headerGetEntry(h, RPMTAG_FILESIZES, &type,
197 (void **) &fileSizeList, &count);
198 headerGetEntry(h, RPMTAG_FILEMODES, &type,
199 (void **) &fileModeList, &count);
200 headerGetEntry(h, RPMTAG_FILEMTIMES, &type,
201 (void **) &fileMTimeList, &count);
202 headerGetEntry(h, RPMTAG_FILERDEVS, &type,
203 (void **) &fileRdevList, &count);
204 headerGetEntry(h, RPMTAG_FILELINKTOS, &type,
205 (void **) &fileLinktoList, &count);
206 headerGetEntry(h, RPMTAG_FILEMD5S, &type,
207 (void **) &fileMD5List, &count);
209 if (!headerGetEntry(h, RPMTAG_FILEUIDS, &type,
210 (void **) &fileUIDList, &count)) {
212 } else if (!headerGetEntry(h, RPMTAG_FILEGIDS, &type,
213 (void **) &fileGIDList, &count)) {
217 if (!headerGetEntry(h, RPMTAG_FILEUSERNAME, &type,
218 (void **) &fileOwnerList, &count)) {
219 fileOwnerList = NULL;
220 } else if (!headerGetEntry(h, RPMTAG_FILEGROUPNAME, &type,
221 (void **) &fileGroupList, &count)) {
222 fileGroupList = NULL;
225 for (i = 0; i < count; i++) {
226 if (!((queryFlags & QUERY_FOR_DOCS) ||
227 (queryFlags & QUERY_FOR_CONFIG))
228 || ((queryFlags & QUERY_FOR_DOCS) &&
229 (fileFlagsList[i] & RPMFILE_DOC))
230 || ((queryFlags & QUERY_FOR_CONFIG) &&
231 (fileFlagsList[i] & RPMFILE_CONFIG))) {
234 prefix ? fputs(prefix, fp) : 0;
236 if (queryFlags & QUERY_FOR_STATE) {
237 if (fileStatesList) {
238 switch (fileStatesList[i]) {
239 case RPMFILE_STATE_NORMAL:
240 fputs(_("normal "), fp); break;
241 case RPMFILE_STATE_REPLACED:
242 fputs(_("replaced "), fp); break;
243 case RPMFILE_STATE_NOTINSTALLED:
244 fputs(_("not installed "), fp); break;
245 case RPMFILE_STATE_NETSHARED:
246 fputs(_("net shared "), fp); break;
248 fprintf(fp, _("(unknown %3d) "),
249 (int)fileStatesList[i]);
252 fputs( _("(no state) "), fp);
256 if (queryFlags & QUERY_FOR_DUMPFILES) {
257 fprintf(fp, "%s%s %d %d %s 0%o ",
258 dirNames[dirIndexes[i]], baseNames[i],
259 fileSizeList[i], fileMTimeList[i],
260 fileMD5List[i], fileModeList[i]);
262 if (fileOwnerList && fileGroupList)
263 fprintf(fp, "%s %s", fileOwnerList[i],
265 else if (fileUIDList && fileGIDList)
266 fprintf(fp, "%d %d", fileUIDList[i],
269 rpmError(RPMERR_INTERNAL, _("package has "
270 "neither file owner or id lists"));
273 fprintf(fp, " %s %s %u ",
274 fileFlagsList[i] & RPMFILE_CONFIG ? "1" : "0",
275 fileFlagsList[i] & RPMFILE_DOC ? "1" : "0",
276 (unsigned)fileRdevList[i]);
278 if (strlen(fileLinktoList[i]))
279 fprintf(fp, "%s\n", fileLinktoList[i]);
283 } else if (!rpmIsVerbose()) {
284 fputs(dirNames[dirIndexes[i]], fp);
285 fputs(baseNames[i], fp);
290 filespec = xmalloc(strlen(dirNames[dirIndexes[i]])
291 + strlen(baseNames[i]) + 1);
292 strcpy(filespec, dirNames[dirIndexes[i]]);
293 strcat(filespec, baseNames[i]);
295 if (fileOwnerList && fileGroupList) {
296 printFileInfo(fp, filespec, fileSizeList[i],
297 fileModeList[i], fileMTimeList[i],
300 fileGroupList[i], -1,
301 -1, fileLinktoList[i]);
302 } else if (fileUIDList && fileGIDList) {
303 printFileInfo(fp, filespec, fileSizeList[i],
304 fileModeList[i], fileMTimeList[i],
305 fileRdevList[i], NULL,
306 NULL, fileUIDList[i],
310 rpmError(RPMERR_INTERNAL, _("package has "
311 "neither file owner or id lists"));
321 free(fileLinktoList);
323 if (fileOwnerList) free(fileOwnerList);
324 if (fileGroupList) free(fileGroupList);
328 return 0; /* XXX FIXME: need real return code */
332 printNewSpecfile(Spec spec)
334 Header h = spec->packages->header;
335 struct speclines *sl = spec->sl;
336 struct spectags *st = spec->st;
337 const char * msgstr = NULL;
340 if (sl == NULL || st == NULL)
343 for (i = 0; i < st->st_ntags; i++) {
344 struct spectag * t = st->st_t + i;
345 const char * tn = tagName(t->t_tag);
350 (void) stpcpy( stpcpy( stpcpy( fmt, "%{"), tn), "}\n");
351 if (msgstr) xfree(msgstr);
352 msgstr = headerSprintf(h, fmt, rpmTagTable, rpmHeaderFormats, &errstr);
353 if (msgstr == NULL) {
354 fprintf(stderr, _("can't query %s: %s\n"), tn, errstr);
361 free(sl->sl_lines[t->t_startx]);
362 sl->sl_lines[t->t_startx] = NULL;
363 if (t->t_lang && strcmp(t->t_lang, RPMBUILD_DEFAULT_LANG))
365 { char *buf = xmalloc(strlen(tn) + sizeof(": ") + strlen(msgstr));
366 (void) stpcpy( stpcpy( stpcpy(buf, tn), ": "), msgstr);
367 sl->sl_lines[t->t_startx] = buf;
370 case RPMTAG_DESCRIPTION:
371 for (j = 1; j < t->t_nlines; j++) {
372 free(sl->sl_lines[t->t_startx + j]);
373 sl->sl_lines[t->t_startx + j] = NULL;
375 if (t->t_lang && strcmp(t->t_lang, RPMBUILD_DEFAULT_LANG)) {
376 free(sl->sl_lines[t->t_startx]);
377 sl->sl_lines[t->t_startx] = NULL;
380 sl->sl_lines[t->t_startx + 1] = xstrdup(msgstr);
382 sl->sl_lines[t->t_startx + 2] = xstrdup("\n\n");
386 if (msgstr) xfree(msgstr);
388 for (i = 0; i < sl->sl_nlines; i++) {
389 if (sl->sl_lines[i] == NULL)
391 printf("%s", sl->sl_lines[i]);
395 void rpmDisplayQueryTags(FILE * f)
397 const struct headerTagTableEntry * t;
399 const struct headerSprintfExtension * ext = rpmHeaderFormats;
401 for (i = 0, t = rpmTagTable; i < rpmTagTableSize; i++, t++) {
402 fprintf(f, "%s\n", t->name + 7);
406 if (ext->type == HEADER_EXT_MORE) {
410 /* XXX don't print query tags twice. */
411 for (i = 0, t = rpmTagTable; i < rpmTagTableSize; i++, t++) {
412 if (!strcmp(t->name, ext->name))
415 if (i >= rpmTagTableSize && ext->type == HEADER_EXT_TAG)
416 fprintf(f, "%s\n", ext->name + 7);
421 int XshowMatches(QVA_t *qva, rpmdbMatchIterator mi, QVF_t showPackage)
426 while ((h = rpmdbNextIterator(mi)) != NULL) {
428 if ((rc = showPackage(qva, NULL, h)) != 0)
431 rpmdbFreeIterator(mi);
435 int showMatches(QVA_t *qva, rpmdb db, dbiIndexSet matches, QVF_t showPackage)
441 for (i = 0; i < dbiIndexSetCount(matches); i++) {
443 unsigned int recOffset = dbiIndexRecordOffset(matches, i);
446 rpmMessage(RPMMESS_DEBUG, _("package record number: %u\n"), recOffset);
448 h = rpmdbGetRecord(db, recOffset);
450 fprintf(stderr, _("error: could not read database record\n"));
453 if ((rc = showPackage(qva, db, h)) != 0)
462 * XXX Eliminate linkage loop into librpmbuild.a
464 int (*parseSpecVec) (Spec *specp, const char *specFile, const char *rootdir,
465 const char *buildRoot, int inBuildArch, const char *passPhrase,
466 char *cookie, int anyarch, int force) = NULL;
467 void (*freeSpecVec) (Spec spec) = NULL;
469 int rpmQueryVerify(QVA_t *qva, enum rpmQVSources source, const char * arg,
470 rpmdb db, QVF_t showPackage)
472 dbiIndexSet matches = NULL; /* XXX DYING */
473 rpmdbMatchIterator mi = NULL;
483 const char ** argv = NULL;
486 rc = rpmGlob(arg, &argc, &argv);
489 for (i = 0; i < argc; i++) {
491 fd = Fopen(argv[i], "r.ufdio");
494 fprintf(stderr, _("open of %s failed: %s\n"), argv[i],
496 urlStrerror(argv[i]));
505 retcode = rpmReadPackageHeader(fd, &h, &isSource, NULL, NULL);
512 fprintf(stderr, _("old format source packages cannot "
517 retcode = showPackage(qva, db, h);
521 fprintf(stderr, _("%s does not appear to be a RPM package\n"),
525 fprintf(stderr, _("query of %s failed\n"), argv[i]);
531 for (i = 0; i < argc; i++)
538 if (showPackage != showQueryPackage)
541 /* XXX Eliminate linkage dependency loop */
542 if (parseSpecVec == NULL || freeSpecVec == NULL)
547 char * buildRoot = NULL;
549 char * passPhrase = "";
554 rc = parseSpecVec(&spec, arg, "/", buildRoot, inBuildArch, passPhrase,
555 cookie, anyarch, force);
556 if (rc || spec == NULL) {
558 fprintf(stderr, _("query of specfile %s failed, can't parse\n"), arg);
559 if (spec != NULL) freeSpecVec(spec);
565 printNewSpecfile(spec);
571 for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
572 showPackage(qva, NULL, pkg->header);
578 /* RPMDBI_PACKAGES */
579 mi = rpmdbInitIterator(db, 0, NULL, 0);
581 fprintf(stderr, _("no packages\n"));
584 retcode = XshowMatches(qva, mi, showPackage);
589 mi = rpmdbInitIterator(db, RPMTAG_GROUP, arg, 0);
591 fprintf(stderr, _("group %s does not contain any packages\n"), arg);
594 retcode = XshowMatches(qva, mi, showPackage);
598 case RPMQV_TRIGGEREDBY:
599 mi = rpmdbInitIterator(db, RPMTAG_TRIGGERNAME, arg, 0);
601 fprintf(stderr, _("no package triggers %s\n"), arg);
604 retcode = XshowMatches(qva, mi, showPackage);
608 case RPMQV_WHATREQUIRES:
609 mi = rpmdbInitIterator(db, RPMTAG_REQUIRENAME, arg, 0);
611 fprintf(stderr, _("no package requires %s\n"), arg);
614 retcode = XshowMatches(qva, mi, showPackage);
618 case RPMQV_WHATPROVIDES:
620 mi = rpmdbInitIterator(db, RPMTAG_PROVIDENAME, arg, 0);
622 fprintf(stderr, _("no package provides %s\n"), arg);
625 retcode = XshowMatches(qva, mi, showPackage);
631 mi = rpmdbInitIterator(db, RPMTAG_BASENAMES, arg, 0);
634 if (access(arg, F_OK) != 0)
638 fprintf(stderr, _("file %s: %s\n"), arg, strerror(myerrno));
641 fprintf(stderr, _("file %s is not owned by any package\n"), arg);
646 retcode = XshowMatches(qva, mi, showPackage);
652 const char * myarg = arg;
655 /* XXX should be in strtoul */
664 recOffset = strtoul(myarg, &end, mybase);
665 if ((*end) || (end == arg) || (recOffset == ULONG_MAX)) {
666 fprintf(stderr, _("invalid package number: %s\n"), arg);
669 rpmMessage(RPMMESS_DEBUG, _("package record number: %u\n"), recOffset);
670 /* RPMDBI_PACKAGES */
671 mi = rpmdbInitIterator(db, 0, &recOffset, sizeof(recOffset));
673 fprintf(stderr, _("record %d could not be read\n"), recOffset);
676 retcode = XshowMatches(qva, mi, showPackage);
681 rc = rpmdbFindByLabel(db, arg, &matches);
684 fprintf(stderr, _("package %s is not installed\n"), arg);
685 } else if (rc == 2) {
687 fprintf(stderr, _("error looking for package %s\n"), arg);
689 retcode = showMatches(qva, db, matches, showPackage);
694 if (matches) { /* XXX DYING */
695 dbiFreeIndexSet(matches);
701 int rpmQuery(QVA_t *qva, enum rpmQVSources source, const char * arg)
711 if (rpmdbOpen(qva->qva_prefix, &db, O_RDONLY, 0644)) {
712 fprintf(stderr, _("rpmQuery: rpmdbOpen() failed\n"));
718 rc = rpmQueryVerify(qva, source, arg, db, showQueryPackage);
726 /* ======================================================================== */
727 #define POPT_QUERYFORMAT 1000
728 #define POPT_WHATREQUIRES 1001
729 #define POPT_WHATPROVIDES 1002
730 #define POPT_QUERYBYNUMBER 1003
731 #define POPT_TRIGGEREDBY 1004
732 #define POPT_DUMP 1005
733 #define POPT_SPECFILE 1006
735 /* ========== Query/Verify source popt args */
736 static void rpmQVSourceArgCallback( /*@unused@*/ poptContext con,
737 /*@unused@*/ enum poptCallbackReason reason,
738 const struct poptOption * opt, /*@unused@*/ const char * arg,
741 QVA_t *qva = (QVA_t *) data;
744 case 'a': qva->qva_source |= RPMQV_ALL; qva->qva_sourceCount++; break;
745 case 'f': qva->qva_source |= RPMQV_PATH; qva->qva_sourceCount++; break;
746 case 'g': qva->qva_source |= RPMQV_GROUP; qva->qva_sourceCount++; break;
747 case 'p': qva->qva_source |= RPMQV_RPM; qva->qva_sourceCount++; break;
748 case POPT_WHATPROVIDES: qva->qva_source |= RPMQV_WHATPROVIDES;
749 qva->qva_sourceCount++; break;
750 case POPT_WHATREQUIRES: qva->qva_source |= RPMQV_WHATREQUIRES;
751 qva->qva_sourceCount++; break;
752 case POPT_TRIGGEREDBY: qva->qva_source |= RPMQV_TRIGGEREDBY;
753 qva->qva_sourceCount++; break;
755 /* XXX SPECFILE is not verify sources */
757 qva->qva_source |= RPMQV_SPECFILE;
758 qva->qva_sourceCount++;
760 case POPT_QUERYBYNUMBER:
761 qva->qva_source |= RPMQV_DBOFFSET;
762 qva->qva_sourceCount++;
767 struct poptOption rpmQVSourcePoptTable[] = {
768 { NULL, '\0', POPT_ARG_CALLBACK | POPT_CBFLAG_INC_DATA,
769 rpmQVSourceArgCallback, 0, NULL, NULL },
770 { "file", 'f', 0, 0, 'f',
771 N_("query package owning file"), "FILE" },
772 { "group", 'g', 0, 0, 'g',
773 N_("query packages in group"), "GROUP" },
774 { "package", 'p', 0, 0, 'p',
775 N_("query a package file"), NULL },
776 { "querybynumber", '\0', POPT_ARGFLAG_DOC_HIDDEN, 0,
777 POPT_QUERYBYNUMBER, NULL, NULL },
778 { "specfile", '\0', 0, 0, POPT_SPECFILE,
779 N_("query a spec file"), NULL },
780 { "triggeredby", '\0', 0, 0, POPT_TRIGGEREDBY,
781 N_("query the pacakges triggered by the package"), "PACKAGE" },
782 { "whatrequires", '\0', 0, 0, POPT_WHATREQUIRES,
783 N_("query the packages which require a capability"), "CAPABILITY" },
784 { "whatprovides", '\0', 0, 0, POPT_WHATPROVIDES,
785 N_("query the packages which provide a capability"), "CAPABILITY" },
786 { 0, 0, 0, 0, 0, NULL, NULL }
789 /* ========== Query specific popt args */
791 static void queryArgCallback(/*@unused@*/poptContext con, /*@unused@*/enum poptCallbackReason reason,
792 const struct poptOption * opt, const char * arg,
795 QVA_t *qva = (QVA_t *) data;
798 case 'c': qva->qva_flags |= QUERY_FOR_CONFIG | QUERY_FOR_LIST; break;
799 case 'd': qva->qva_flags |= QUERY_FOR_DOCS | QUERY_FOR_LIST; break;
800 case 'l': qva->qva_flags |= QUERY_FOR_LIST; break;
801 case 's': qva->qva_flags |= QUERY_FOR_STATE | QUERY_FOR_LIST; break;
802 case POPT_DUMP: qva->qva_flags |= QUERY_FOR_DUMPFILES | QUERY_FOR_LIST; break;
803 case 'v': rpmIncreaseVerbosity(); break;
805 case POPT_QUERYFORMAT:
806 { char *qf = (char *)qva->qva_queryFormat;
808 int len = strlen(qf) + strlen(arg) + 1;
809 qf = xrealloc(qf, len);
812 qf = xmalloc(strlen(arg) + 1);
815 qva->qva_queryFormat = qf;
820 struct poptOption rpmQueryPoptTable[] = {
821 { NULL, '\0', POPT_ARG_CALLBACK | POPT_CBFLAG_INC_DATA,
822 queryArgCallback, 0, NULL, NULL },
823 { "configfiles", 'c', 0, 0, 'c',
824 N_("list all configuration files"), NULL },
825 { "docfiles", 'd', 0, 0, 'd',
826 N_("list all documentation files"), NULL },
827 { "dump", '\0', 0, 0, POPT_DUMP,
828 N_("dump basic file information"), NULL },
829 { "list", 'l', 0, 0, 'l',
830 N_("list files in package"), NULL },
831 { "qf", '\0', POPT_ARG_STRING | POPT_ARGFLAG_DOC_HIDDEN, 0,
832 POPT_QUERYFORMAT, NULL, NULL },
833 { "queryformat", '\0', POPT_ARG_STRING, 0, POPT_QUERYFORMAT,
834 N_("use the following query format"), "QUERYFORMAT" },
835 { "specedit", '\0', POPT_ARG_VAL, &specedit, -1,
836 N_("substitute i18n sections into spec file"), NULL },
837 { "state", 's', 0, 0, 's',
838 N_("display the states of the listed files"), NULL },
839 { "verbose", 'v', 0, 0, 'v',
840 N_("display a verbose file listing"), NULL },
841 { 0, 0, 0, 0, 0, NULL, NULL }
844 /* ======================================================================== */