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 ** fileList;
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;
169 headerNVR(h, &name, &version, &release);
171 if (!queryFormat && !queryFlags) {
172 fprintf(fp, "%s-%s-%s\n", name, version, release);
175 queryHeader(fp, h, queryFormat);
177 if (queryFlags & QUERY_FOR_LIST) {
178 if (!headerGetEntry(h, RPMTAG_FILENAMES, &type, (void **) &fileList,
180 fputs(_("(contains no files)"), fp);
183 if (!headerGetEntry(h, RPMTAG_FILESTATES, &type,
184 (void **) &fileStatesList, &count)) {
185 fileStatesList = NULL;
187 headerGetEntry(h, RPMTAG_FILEFLAGS, &type,
188 (void **) &fileFlagsList, &count);
189 headerGetEntry(h, RPMTAG_FILESIZES, &type,
190 (void **) &fileSizeList, &count);
191 headerGetEntry(h, RPMTAG_FILEMODES, &type,
192 (void **) &fileModeList, &count);
193 headerGetEntry(h, RPMTAG_FILEMTIMES, &type,
194 (void **) &fileMTimeList, &count);
195 headerGetEntry(h, RPMTAG_FILERDEVS, &type,
196 (void **) &fileRdevList, &count);
197 headerGetEntry(h, RPMTAG_FILELINKTOS, &type,
198 (void **) &fileLinktoList, &count);
199 headerGetEntry(h, RPMTAG_FILEMD5S, &type,
200 (void **) &fileMD5List, &count);
202 if (!headerGetEntry(h, RPMTAG_FILEUIDS, &type,
203 (void **) &fileUIDList, &count)) {
205 } else if (!headerGetEntry(h, RPMTAG_FILEGIDS, &type,
206 (void **) &fileGIDList, &count)) {
210 if (!headerGetEntry(h, RPMTAG_FILEUSERNAME, &type,
211 (void **) &fileOwnerList, &count)) {
212 fileOwnerList = NULL;
213 } else if (!headerGetEntry(h, RPMTAG_FILEGROUPNAME, &type,
214 (void **) &fileGroupList, &count)) {
215 fileGroupList = NULL;
218 for (i = 0; i < count; i++) {
219 if (!((queryFlags & QUERY_FOR_DOCS) ||
220 (queryFlags & QUERY_FOR_CONFIG))
221 || ((queryFlags & QUERY_FOR_DOCS) &&
222 (fileFlagsList[i] & RPMFILE_DOC))
223 || ((queryFlags & QUERY_FOR_CONFIG) &&
224 (fileFlagsList[i] & RPMFILE_CONFIG))) {
227 prefix ? fputs(prefix, fp) : 0;
229 if (queryFlags & QUERY_FOR_STATE) {
230 if (fileStatesList) {
231 switch (fileStatesList[i]) {
232 case RPMFILE_STATE_NORMAL:
233 fputs(_("normal "), fp); break;
234 case RPMFILE_STATE_REPLACED:
235 fputs(_("replaced "), fp); break;
236 case RPMFILE_STATE_NOTINSTALLED:
237 fputs(_("not installed "), fp); break;
238 case RPMFILE_STATE_NETSHARED:
239 fputs(_("net shared "), fp); break;
241 fprintf(fp, _("(unknown %3d) "),
242 (int)fileStatesList[i]);
245 fputs( _("(no state) "), fp);
249 if (queryFlags & QUERY_FOR_DUMPFILES) {
250 fprintf(fp, "%s %d %d %s 0%o ", fileList[i],
251 fileSizeList[i], fileMTimeList[i],
252 fileMD5List[i], fileModeList[i]);
254 if (fileOwnerList && fileGroupList)
255 fprintf(fp, "%s %s", fileOwnerList[i],
257 else if (fileUIDList && fileGIDList)
258 fprintf(fp, "%d %d", fileUIDList[i],
261 rpmError(RPMERR_INTERNAL, _("package has "
262 "neither file owner or id lists"));
265 fprintf(fp, " %s %s %u ",
266 fileFlagsList[i] & RPMFILE_CONFIG ? "1" : "0",
267 fileFlagsList[i] & RPMFILE_DOC ? "1" : "0",
268 (unsigned)fileRdevList[i]);
270 if (strlen(fileLinktoList[i]))
271 fprintf(fp, "%s\n", fileLinktoList[i]);
275 } else if (!rpmIsVerbose()) {
276 fputs(fileList[i], fp);
278 } else if (fileOwnerList && fileGroupList)
279 printFileInfo(fp, fileList[i], fileSizeList[i],
280 fileModeList[i], fileMTimeList[i],
281 fileRdevList[i], fileOwnerList[i],
282 fileGroupList[i], -1,
283 -1, fileLinktoList[i]);
284 else if (fileUIDList && fileGIDList) {
285 printFileInfo(fp, fileList[i], fileSizeList[i],
286 fileModeList[i], fileMTimeList[i],
287 fileRdevList[i], NULL,
288 NULL, fileUIDList[i],
289 fileGIDList[i], fileLinktoList[i]);
291 rpmError(RPMERR_INTERNAL, _("package has "
292 "neither file owner or id lists"));
298 free(fileLinktoList);
300 if (fileOwnerList) free(fileOwnerList);
301 if (fileGroupList) free(fileGroupList);
305 return 0; /* XXX FIXME: need real return code */
309 printNewSpecfile(Spec spec)
311 struct speclines *sl = spec->sl;
312 struct spectags *st = spec->st;
316 if (sl == NULL || st == NULL)
319 for (i = 0; i < st->st_ntags; i++) {
324 /* XXX Summary tag often precedes name, so build msgid now. */
325 if (t->t_msgid == NULL) {
327 headerGetEntry(spec->packages->header, RPMTAG_NAME, NULL,
329 sprintf(buf, "%s(%s)", n, tagName(t->t_tag));
330 t->t_msgid = xstrdup(buf);
332 msgstr = xstrdup(dgettext(specedit, t->t_msgid));
337 free(sl->sl_lines[t->t_startx]);
338 sl->sl_lines[t->t_startx] = NULL;
339 if (t->t_lang && strcmp(t->t_lang, RPMBUILD_DEFAULT_LANG))
341 sprintf(buf, "%s: %s\n",
342 ((t->t_tag == RPMTAG_GROUP) ? "Group" : "Summary"),
344 sl->sl_lines[t->t_startx] = xstrdup(buf);
346 case RPMTAG_DESCRIPTION:
347 for (j = 1; j < t->t_nlines; j++) {
348 free(sl->sl_lines[t->t_startx + j]);
349 sl->sl_lines[t->t_startx + j] = NULL;
351 if (t->t_lang && strcmp(t->t_lang, RPMBUILD_DEFAULT_LANG)) {
352 free(sl->sl_lines[t->t_startx]);
353 sl->sl_lines[t->t_startx] = NULL;
356 sl->sl_lines[t->t_startx + 1] = xstrdup(msgstr);
358 sl->sl_lines[t->t_startx + 2] = xstrdup("\n\n");
363 for (i = 0; i < sl->sl_nlines; i++) {
364 if (sl->sl_lines[i] == NULL)
366 printf("%s", sl->sl_lines[i]);
370 void rpmDisplayQueryTags(FILE * f) {
371 const struct headerTagTableEntry * t;
373 const struct headerSprintfExtension * ext = rpmHeaderFormats;
375 for (i = 0, t = rpmTagTable; i < rpmTagTableSize; i++, t++) {
376 fprintf(f, "%s\n", t->name + 7);
380 if (ext->type == HEADER_EXT_TAG)
381 fprintf(f, "%s\n", ext->name + 7), ext++;
382 else if (ext->type == HEADER_EXT_MORE)
389 int showMatches(QVA_t *qva, rpmdb db, dbiIndexSet matches, QVF_t showPackage)
395 for (i = 0; i < dbiIndexSetCount(matches); i++) {
397 unsigned int recOffset = dbiIndexRecordOffset(matches, i);
400 rpmMessage(RPMMESS_DEBUG, _("record number %u\n"), recOffset);
402 h = rpmdbGetRecord(db, recOffset);
404 fprintf(stderr, _("error: could not read database record\n"));
407 if ((rc = showPackage(qva, db, h)) != 0)
416 * XXX Eliminate linkage loop into librpmbuild.a
418 int (*parseSpecVec) (Spec *specp, const char *specFile, const char *buildRoot,
419 int inBuildArch, const char *passPhrase, char *cookie, int anyarch,
421 void (*freeSpecVec) (Spec spec) = NULL;
422 char *specedit = NULL;
424 int rpmQueryVerify(QVA_t *qva, enum rpmQVSources source, const char * arg,
425 rpmdb db, QVF_t showPackage)
440 fd = ufdOpen(arg, O_RDONLY, 0);
441 if (fdFileno(fd) < 0) {
442 fprintf(stderr, _("open of %s failed: %s\n"), arg,urlStrerror(arg));
448 retcode = rpmReadPackageHeader(fd, &h, &isSource, NULL, NULL);
455 fprintf(stderr, _("old format source packages cannot "
460 retcode = showPackage(qva, db, h);
464 fprintf(stderr, _("%s does not appear to be a RPM package\n"), arg);
467 fprintf(stderr, _("query of %s failed\n"), arg);
474 if (showPackage != showQueryPackage)
477 /* XXX Eliminate linkage dependency loop */
478 if (parseSpecVec == NULL || freeSpecVec == NULL)
483 char * buildRoot = NULL;
485 char * passPhrase = "";
490 rc = parseSpecVec(&spec, arg, buildRoot, inBuildArch, passPhrase,
491 cookie, anyarch, force);
492 if (rc || spec == NULL) {
494 fprintf(stderr, _("query of specfile %s failed, can't parse\n"), arg);
495 if (spec != NULL) freeSpecVec(spec);
500 if (specedit != NULL) {
501 printNewSpecfile(spec);
507 for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
508 showPackage(qva, NULL, pkg->header);
514 for (offset = rpmdbFirstRecNum(db);
516 offset = rpmdbNextRecNum(db, offset)) {
517 h = rpmdbGetRecord(db, offset);
519 fprintf(stderr, _("could not read database record!\n"));
522 if ((rc = showPackage(qva, db, h)) != 0)
529 if (rpmdbFindByGroup(db, arg, &matches)) {
530 fprintf(stderr, _("group %s does not contain any packages\n"), arg);
533 retcode = showMatches(qva, db, matches, showPackage);
534 dbiFreeIndexRecord(matches);
538 case RPMQV_WHATPROVIDES:
539 if (rpmdbFindByProvides(db, arg, &matches)) {
540 fprintf(stderr, _("no package provides %s\n"), arg);
543 retcode = showMatches(qva, db, matches, showPackage);
544 dbiFreeIndexRecord(matches);
548 case RPMQV_TRIGGEREDBY:
549 if (rpmdbFindByTriggeredBy(db, arg, &matches)) {
550 fprintf(stderr, _("no package triggers %s\n"), arg);
553 retcode = showMatches(qva, db, matches, showPackage);
554 dbiFreeIndexRecord(matches);
558 case RPMQV_WHATREQUIRES:
559 if (rpmdbFindByRequiredBy(db, arg, &matches)) {
560 fprintf(stderr, _("no package requires %s\n"), arg);
563 retcode = showMatches(qva, db, matches, showPackage);
564 dbiFreeIndexRecord(matches);
569 if (rpmdbFindByFile(db, arg, &matches)) {
571 if (access(arg, F_OK) != 0)
575 fprintf(stderr, _("file %s: %s\n"), arg, strerror(myerrno));
578 fprintf(stderr, _("file %s is not owned by any package\n"), arg);
583 retcode = showMatches(qva, db, matches, showPackage);
584 dbiFreeIndexRecord(matches);
589 recNumber = strtoul(arg, &end, 10);
590 if ((*end) || (end == arg) || (recNumber == ULONG_MAX)) {
591 fprintf(stderr, _("invalid package number: %s\n"), arg);
594 rpmMessage(RPMMESS_DEBUG, _("package record number: %d\n"), recNumber);
595 h = rpmdbGetRecord(db, recNumber);
597 fprintf(stderr, _("record %d could not be read\n"), recNumber);
600 retcode = showPackage(qva, db, h);
606 rc = rpmdbFindByLabel(db, arg, &matches);
609 fprintf(stderr, _("package %s is not installed\n"), arg);
610 } else if (rc == 2) {
612 fprintf(stderr, _("error looking for package %s\n"), arg);
614 retcode = showMatches(qva, db, matches, showPackage);
615 dbiFreeIndexRecord(matches);
623 int rpmQuery(QVA_t *qva, enum rpmQVSources source, const char * arg)
633 if (rpmdbOpen(qva->qva_prefix, &db, O_RDONLY, 0644)) {
634 fprintf(stderr, _("rpmQuery: rpmdbOpen() failed\n"));
640 rc = rpmQueryVerify(qva, source, arg, db, showQueryPackage);
648 /* ======================================================================== */
649 #define POPT_QUERYFORMAT 1000
650 #define POPT_WHATREQUIRES 1001
651 #define POPT_WHATPROVIDES 1002
652 #define POPT_QUERYBYNUMBER 1003
653 #define POPT_TRIGGEREDBY 1004
654 #define POPT_DUMP 1005
655 #define POPT_SPECFILE 1006
657 /* ========== Query/Verify source popt args */
658 static void rpmQVSourceArgCallback(/*@unused@*/poptContext con, /*@unused@*/enum poptCallbackReason reason,
659 const struct poptOption * opt, /*@unused@*/const char * arg,
664 case 'a': qva->qva_source |= RPMQV_ALL; qva->qva_sourceCount++; break;
665 case 'f': qva->qva_source |= RPMQV_PATH; qva->qva_sourceCount++; break;
666 case 'g': qva->qva_source |= RPMQV_GROUP; qva->qva_sourceCount++; break;
667 case 'p': qva->qva_source |= RPMQV_RPM; qva->qva_sourceCount++; break;
668 case POPT_WHATPROVIDES: qva->qva_source |= RPMQV_WHATPROVIDES;
669 qva->qva_sourceCount++; break;
670 case POPT_WHATREQUIRES: qva->qva_source |= RPMQV_WHATREQUIRES;
671 qva->qva_sourceCount++; break;
672 case POPT_TRIGGEREDBY: qva->qva_source |= RPMQV_TRIGGEREDBY;
673 qva->qva_sourceCount++; break;
675 /* XXX SPECFILE is not verify sources */
677 qva->qva_source |= RPMQV_SPECFILE;
678 qva->qva_sourceCount++;
680 case POPT_QUERYBYNUMBER:
681 qva->qva_source |= RPMQV_DBOFFSET;
682 qva->qva_sourceCount++;
687 struct poptOption rpmQVSourcePoptTable[] = {
688 { NULL, '\0', POPT_ARG_CALLBACK | POPT_CBFLAG_INC_DATA,
689 rpmQVSourceArgCallback, 0, NULL, NULL },
690 { "file", 'f', 0, 0, 'f',
691 N_("query package owning file"), "FILE" },
692 { "group", 'g', 0, 0, 'g',
693 N_("query packages in group"), "GROUP" },
694 { "package", 'p', 0, 0, 'p',
695 N_("query a package file"), NULL },
696 { "querybynumber", '\0', POPT_ARGFLAG_DOC_HIDDEN, 0,
697 POPT_QUERYBYNUMBER, NULL, NULL },
698 { "specfile", '\0', 0, 0, POPT_SPECFILE,
699 N_("query a spec file"), NULL },
700 { "triggeredby", '\0', 0, 0, POPT_TRIGGEREDBY,
701 N_("query the pacakges triggered by the package"), "PACKAGE" },
702 { "whatrequires", '\0', 0, 0, POPT_WHATREQUIRES,
703 N_("query the packages which require a capability"), "CAPABILITY" },
704 { "whatprovides", '\0', 0, 0, POPT_WHATPROVIDES,
705 N_("query the packages which provide a capability"), "CAPABILITY" },
706 { 0, 0, 0, 0, 0, NULL, NULL }
709 /* ========== Query specific popt args */
711 static void queryArgCallback(/*@unused@*/poptContext con, /*@unused@*/enum poptCallbackReason reason,
712 const struct poptOption * opt, const char * arg,
716 case 'c': qva->qva_flags |= QUERY_FOR_CONFIG | QUERY_FOR_LIST; break;
717 case 'd': qva->qva_flags |= QUERY_FOR_DOCS | QUERY_FOR_LIST; break;
718 case 'l': qva->qva_flags |= QUERY_FOR_LIST; break;
719 case 's': qva->qva_flags |= QUERY_FOR_STATE | QUERY_FOR_LIST; break;
720 case POPT_DUMP: qva->qva_flags |= QUERY_FOR_DUMPFILES | QUERY_FOR_LIST; break;
721 case 'v': rpmIncreaseVerbosity(); break;
723 case POPT_QUERYFORMAT:
724 { char *qf = (char *)qva->qva_queryFormat;
726 int len = strlen(qf) + strlen(arg) + 1;
727 qf = xrealloc(qf, len);
730 qf = xmalloc(strlen(arg) + 1);
733 qva->qva_queryFormat = qf;
738 struct poptOption rpmQueryPoptTable[] = {
739 { NULL, '\0', POPT_ARG_CALLBACK | POPT_CBFLAG_INC_DATA,
740 queryArgCallback, 0, NULL, NULL },
741 { "configfiles", 'c', 0, 0, 'c',
742 N_("list all configuration files"), NULL },
743 { "docfiles", 'd', 0, 0, 'd',
744 N_("list all documentation files"), NULL },
745 { "dump", '\0', 0, 0, POPT_DUMP,
746 N_("dump basic file information"), NULL },
747 { "list", 'l', 0, 0, 'l',
748 N_("list files in package"), NULL },
749 { "qf", '\0', POPT_ARG_STRING | POPT_ARGFLAG_DOC_HIDDEN, 0,
750 POPT_QUERYFORMAT, NULL, NULL },
751 { "queryformat", '\0', POPT_ARG_STRING, 0, POPT_QUERYFORMAT,
752 N_("use the following query format"), "QUERYFORMAT" },
753 { "specedit", '\0', POPT_ARG_STRING, &specedit, 0,
754 N_("substitute i18n sections from the following catalogue"),
756 { "state", 's', 0, 0, 's',
757 N_("display the states of the listed files"), NULL },
758 { "verbose", 'v', 0, 0, 'v',
759 N_("display a verbose file listing"), NULL },
760 { 0, 0, 0, 0, 0, NULL, NULL }
763 /* ======================================================================== */