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 = malloc(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 *buildRoot,
440 int inBuildArch, const char *passPhrase, char *cookie, int anyarch,
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)
461 fd = ufdOpen(arg, O_RDONLY, 0);
462 if (fdFileno(fd) < 0) {
463 fprintf(stderr, _("open of %s failed: %s\n"), arg,urlStrerror(arg));
469 retcode = rpmReadPackageHeader(fd, &h, &isSource, NULL, NULL);
476 fprintf(stderr, _("old format source packages cannot "
481 retcode = showPackage(qva, db, h);
485 fprintf(stderr, _("%s does not appear to be a RPM package\n"), arg);
488 fprintf(stderr, _("query of %s failed\n"), arg);
495 if (showPackage != showQueryPackage)
498 /* XXX Eliminate linkage dependency loop */
499 if (parseSpecVec == NULL || freeSpecVec == NULL)
504 char * buildRoot = NULL;
506 char * passPhrase = "";
511 rc = parseSpecVec(&spec, arg, buildRoot, inBuildArch, passPhrase,
512 cookie, anyarch, force);
513 if (rc || spec == NULL) {
515 fprintf(stderr, _("query of specfile %s failed, can't parse\n"), arg);
516 if (spec != NULL) freeSpecVec(spec);
521 if (specedit != NULL) {
522 printNewSpecfile(spec);
528 for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
529 showPackage(qva, NULL, pkg->header);
535 for (offset = rpmdbFirstRecNum(db);
537 offset = rpmdbNextRecNum(db, offset)) {
538 h = rpmdbGetRecord(db, offset);
540 fprintf(stderr, _("could not read database record!\n"));
543 if ((rc = showPackage(qva, db, h)) != 0)
550 if (rpmdbFindByGroup(db, arg, &matches)) {
551 fprintf(stderr, _("group %s does not contain any packages\n"), arg);
554 retcode = showMatches(qva, db, matches, showPackage);
555 dbiFreeIndexRecord(matches);
559 case RPMQV_WHATPROVIDES:
560 if (rpmdbFindByProvides(db, arg, &matches)) {
561 fprintf(stderr, _("no package provides %s\n"), arg);
564 retcode = showMatches(qva, db, matches, showPackage);
565 dbiFreeIndexRecord(matches);
569 case RPMQV_TRIGGEREDBY:
570 if (rpmdbFindByTriggeredBy(db, arg, &matches)) {
571 fprintf(stderr, _("no package triggers %s\n"), arg);
574 retcode = showMatches(qva, db, matches, showPackage);
575 dbiFreeIndexRecord(matches);
579 case RPMQV_WHATREQUIRES:
580 if (rpmdbFindByRequiredBy(db, arg, &matches)) {
581 fprintf(stderr, _("no package requires %s\n"), arg);
584 retcode = showMatches(qva, db, matches, showPackage);
585 dbiFreeIndexRecord(matches);
590 if (rpmdbFindByFile(db, arg, &matches)) {
592 if (access(arg, F_OK) != 0)
596 fprintf(stderr, _("file %s: %s\n"), arg, strerror(myerrno));
599 fprintf(stderr, _("file %s is not owned by any package\n"), arg);
604 retcode = showMatches(qva, db, matches, showPackage);
605 dbiFreeIndexRecord(matches);
610 recNumber = strtoul(arg, &end, 10);
611 if ((*end) || (end == arg) || (recNumber == ULONG_MAX)) {
612 fprintf(stderr, _("invalid package number: %s\n"), arg);
615 rpmMessage(RPMMESS_DEBUG, _("package record number: %d\n"), recNumber);
616 h = rpmdbGetRecord(db, recNumber);
618 fprintf(stderr, _("record %d could not be read\n"), recNumber);
621 retcode = showPackage(qva, db, h);
627 rc = rpmdbFindByLabel(db, arg, &matches);
630 fprintf(stderr, _("package %s is not installed\n"), arg);
631 } else if (rc == 2) {
633 fprintf(stderr, _("error looking for package %s\n"), arg);
635 retcode = showMatches(qva, db, matches, showPackage);
636 dbiFreeIndexRecord(matches);
644 int rpmQuery(QVA_t *qva, enum rpmQVSources source, const char * arg)
654 if (rpmdbOpen(qva->qva_prefix, &db, O_RDONLY, 0644)) {
655 fprintf(stderr, _("rpmQuery: rpmdbOpen() failed\n"));
661 rc = rpmQueryVerify(qva, source, arg, db, showQueryPackage);
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
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,
684 QVA_t *qva = (QVA_t *) data;
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;
698 /* XXX SPECFILE is not verify sources */
700 qva->qva_source |= RPMQV_SPECFILE;
701 qva->qva_sourceCount++;
703 case POPT_QUERYBYNUMBER:
704 qva->qva_source |= RPMQV_DBOFFSET;
705 qva->qva_sourceCount++;
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 }
732 /* ========== Query specific popt args */
734 static void queryArgCallback(/*@unused@*/poptContext con, /*@unused@*/enum poptCallbackReason reason,
735 const struct poptOption * opt, const char * arg,
738 QVA_t *qva = (QVA_t *) data;
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;
748 case POPT_QUERYFORMAT:
749 { char *qf = (char *)qva->qva_queryFormat;
751 int len = strlen(qf) + strlen(arg) + 1;
752 qf = xrealloc(qf, len);
755 qf = xmalloc(strlen(arg) + 1);
758 qva->qva_queryFormat = qf;
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"),
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 }
788 /* ======================================================================== */