7 #include "build/rpmbuild.h"
11 static char * permsString(int mode);
12 static void printHeader(Header h, int queryFlags, const char * queryFormat);
13 static void showMatches(rpmdb db, dbiIndexSet matches, int queryFlags,
14 const char * queryFormat);
15 static void printFileInfo(char * name, unsigned int size, unsigned short mode,
16 unsigned int mtime, unsigned short rdev,
17 char * owner, char * group, int uid, int gid,
20 #define POPT_QUERYFORMAT 1000
21 #define POPT_WHATREQUIRES 1001
22 #define POPT_WHATPROVIDES 1002
23 #define POPT_QUERYBYNUMBER 1003
24 #define POPT_TRIGGEREDBY 1004
25 #define POPT_DUMP 1005
26 #define POPT_SPECFILE 1006
28 static void queryArgCallback(poptContext con, enum poptCallbackReason reason,
29 const struct poptOption * opt, const char * arg,
30 struct rpmQueryArguments * data);
32 struct poptOption rpmQuerySourcePoptTable[] = {
33 { NULL, '\0', POPT_ARG_CALLBACK | POPT_CBFLAG_INC_DATA,
34 queryArgCallback, 0, NULL, NULL },
35 { "file", 'f', 0, 0, 'f',
36 N_("query package owning file"), "FILE" },
37 { "group", 'g', 0, 0, 'g',
38 N_("query packages in group"), "GROUP" },
39 { "package", 'p', 0, 0, 'p',
40 N_("query a package file"), NULL },
41 { "specfile", '\0', 0, 0, POPT_SPECFILE,
42 N_("query a spec file"), NULL },
43 { "triggeredby", '\0', 0, 0, POPT_TRIGGEREDBY,
44 N_("query the pacakges triggered by the package"), "PACKAGE" },
45 { "whatrequires", '\0', 0, 0, POPT_WHATREQUIRES,
46 N_("query the packages which require a capability"), "CAPABILITY" },
47 { "whatprovides", '\0', 0, 0, POPT_WHATPROVIDES,
48 N_("query the packages which provide a capability"), "CAPABILITY" },
49 { 0, 0, 0, 0, 0, NULL, NULL }
52 struct poptOption rpmQueryPoptTable[] = {
53 { NULL, '\0', POPT_ARG_CALLBACK | POPT_CBFLAG_INC_DATA,
54 queryArgCallback, 0, NULL, NULL },
55 { "configfiles", 'c', 0, 0, 'c',
56 N_("list all configuration files"), NULL },
57 { "docfiles", 'd', 0, 0, 'd',
58 N_("list all documetnation files"), NULL },
59 { "dump", '\0', 0, 0, POPT_DUMP,
60 N_("dump basic file information"), NULL },
61 { "list", 'l', 0, 0, 'l',
62 N_("list files in package"), NULL },
63 { "qf", '\0', POPT_ARG_STRING | POPT_ARGFLAG_DOC_HIDDEN, 0,
64 POPT_QUERYFORMAT, NULL, NULL },
65 { "querybynumber", '\0', POPT_ARGFLAG_DOC_HIDDEN, 0,
66 POPT_QUERYBYNUMBER, NULL, NULL },
67 { "queryformat", '\0', POPT_ARG_STRING, 0, POPT_QUERYFORMAT,
68 N_("use the following query format"), "QUERYFORMAT" },
69 { "state", 's', 0, 0, 's',
70 N_("display the states of the listed files"), NULL },
71 { "verbose", 'v', 0, 0, 'v',
72 N_("display a verbose file listing"), NULL },
73 { 0, 0, 0, 0, 0, NULL, NULL }
76 static void queryArgCallback(poptContext con, enum poptCallbackReason reason,
77 const struct poptOption * opt, const char * arg,
78 struct rpmQueryArguments * data) {
82 case 'c': data->flags |= QUERY_FOR_CONFIG | QUERY_FOR_LIST; break;
83 case 'd': data->flags |= QUERY_FOR_DOCS | QUERY_FOR_LIST; break;
84 case 'l': data->flags |= QUERY_FOR_LIST; break;
85 case 's': data->flags |= QUERY_FOR_STATE | QUERY_FOR_LIST; break;
86 case POPT_DUMP: data->flags |= QUERY_FOR_DUMPFILES | QUERY_FOR_LIST; break;
88 case 'a': data->source |= QUERY_ALL; data->sourceCount++; break;
89 case 'f': data->source |= QUERY_PATH; data->sourceCount++; break;
90 case 'g': data->source |= QUERY_GROUP; data->sourceCount++; break;
91 case 'p': data->source |= QUERY_RPM; data->sourceCount++; break;
92 case 'v': rpmIncreaseVerbosity(); break;
93 case POPT_SPECFILE: data->source |= QUERY_SPECFILE; data->sourceCount++; break;
94 case POPT_WHATPROVIDES: data->source |= QUERY_WHATPROVIDES;
95 data->sourceCount++; break;
96 case POPT_WHATREQUIRES: data->source |= QUERY_WHATREQUIRES;
97 data->sourceCount++; break;
98 case POPT_QUERYBYNUMBER: data->source |= QUERY_DBOFFSET;
99 data->sourceCount++; break;
100 case POPT_TRIGGEREDBY: data->source |= QUERY_TRIGGEREDBY;
101 data->sourceCount++; break;
103 case POPT_QUERYFORMAT:
104 if (data->queryFormat) {
105 len = strlen(data->queryFormat) + strlen(arg) + 1;
106 data->queryFormat = realloc(data->queryFormat, len);
107 strcat(data->queryFormat, arg);
109 data->queryFormat = malloc(strlen(arg) + 1);
110 strcpy(data->queryFormat, arg);
116 static int queryHeader(Header h, const char * chptr) {
120 str = headerSprintf(h, chptr, rpmTagTable, rpmHeaderFormats, &error);
122 fprintf(stderr, _("error in format: %s\n"), error);
131 static void printHeader(Header h, int queryFlags, const char * queryFormat) {
132 char * name, * version, * release;
134 char * prefix = NULL;
135 char ** fileList, ** fileMD5List;
136 char * fileStatesList;
137 char ** fileOwnerList = NULL;
138 char ** fileGroupList = NULL;
139 char ** fileLinktoList;
140 int_32 * fileFlagsList, * fileMTimeList, * fileSizeList;
141 int_32 * fileUIDList, * fileGIDList;
142 uint_16 * fileModeList;
143 uint_16 * fileRdevList;
146 headerGetEntry(h, RPMTAG_NAME, &type, (void **) &name, &count);
147 headerGetEntry(h, RPMTAG_VERSION, &type, (void **) &version, &count);
148 headerGetEntry(h, RPMTAG_RELEASE, &type, (void **) &release, &count);
150 if (!queryFormat && !queryFlags) {
151 fprintf(stdout, "%s-%s-%s\n", name, version, release);
154 queryHeader(h, queryFormat);
156 if (queryFlags & QUERY_FOR_LIST) {
157 if (!headerGetEntry(h, RPMTAG_FILENAMES, &type, (void **) &fileList,
159 fputs(_("(contains no files)"), stdout);
162 if (!headerGetEntry(h, RPMTAG_FILESTATES, &type,
163 (void **) &fileStatesList, &count)) {
164 fileStatesList = NULL;
166 headerGetEntry(h, RPMTAG_FILEFLAGS, &type,
167 (void **) &fileFlagsList, &count);
168 headerGetEntry(h, RPMTAG_FILESIZES, &type,
169 (void **) &fileSizeList, &count);
170 headerGetEntry(h, RPMTAG_FILEMODES, &type,
171 (void **) &fileModeList, &count);
172 headerGetEntry(h, RPMTAG_FILEMTIMES, &type,
173 (void **) &fileMTimeList, &count);
174 headerGetEntry(h, RPMTAG_FILERDEVS, &type,
175 (void **) &fileRdevList, &count);
176 headerGetEntry(h, RPMTAG_FILELINKTOS, &type,
177 (void **) &fileLinktoList, &count);
178 headerGetEntry(h, RPMTAG_FILEMD5S, &type,
179 (void **) &fileMD5List, &count);
181 if (!headerGetEntry(h, RPMTAG_FILEUIDS, &type,
182 (void **) &fileUIDList, &count)) {
185 headerGetEntry(h, RPMTAG_FILEGIDS, &type,
186 (void **) &fileGIDList, &count);
189 if (!headerGetEntry(h, RPMTAG_FILEUSERNAME, &type,
190 (void **) &fileOwnerList, &count)) {
191 fileOwnerList = NULL;
193 headerGetEntry(h, RPMTAG_FILEGROUPNAME, &type,
194 (void **) &fileGroupList, &count);
197 for (i = 0; i < count; i++) {
198 if (!((queryFlags & QUERY_FOR_DOCS) ||
199 (queryFlags & QUERY_FOR_CONFIG))
200 || ((queryFlags & QUERY_FOR_DOCS) &&
201 (fileFlagsList[i] & RPMFILE_DOC))
202 || ((queryFlags & QUERY_FOR_CONFIG) &&
203 (fileFlagsList[i] & RPMFILE_CONFIG))) {
206 prefix ? fputs(prefix, stdout) : 0;
208 if (queryFlags & QUERY_FOR_STATE) {
209 if (fileStatesList) {
210 switch (fileStatesList[i]) {
211 case RPMFILE_STATE_NORMAL:
212 fputs(_("normal "), stdout); break;
213 case RPMFILE_STATE_REPLACED:
214 fputs(_("replaced "), stdout); break;
215 case RPMFILE_STATE_NETSHARED:
216 fputs(_("net shared "), stdout); break;
217 case RPMFILE_STATE_NOTINSTALLED:
218 fputs(_("not installed "), stdout); break;
220 fprintf(stdout, _("(unknown %3d) "),
224 fputs( _("(no state) "), stdout);
228 if (queryFlags & QUERY_FOR_DUMPFILES) {
229 fprintf(stdout, "%s %d %d %s 0%o ", fileList[i],
230 fileSizeList[i], fileMTimeList[i],
231 fileMD5List[i], fileModeList[i]);
234 fprintf(stdout, "%s %s", fileOwnerList[i],
236 else if (fileUIDList)
237 fprintf(stdout, "%d %d", fileUIDList[i],
240 rpmError(RPMERR_INTERNAL, _("package has "
241 "neither file owner or id lists"));
244 fprintf(stdout, " %s %s %u ",
245 fileFlagsList[i] & RPMFILE_CONFIG ? "1" : "0",
246 fileFlagsList[i] & RPMFILE_DOC ? "1" : "0",
247 (unsigned)fileRdevList[i]);
249 if (strlen(fileLinktoList[i]))
250 fprintf(stdout, "%s\n", fileLinktoList[i]);
252 fprintf(stdout, "X\n");
254 } else if (!rpmIsVerbose()) {
255 fputs(fileList[i], stdout);
257 } else if (fileOwnerList)
258 printFileInfo(fileList[i], fileSizeList[i],
259 fileModeList[i], fileMTimeList[i],
260 fileRdevList[i], fileOwnerList[i],
261 fileGroupList[i], -1,
262 -1, fileLinktoList[i]);
263 else if (fileUIDList) {
264 printFileInfo(fileList[i], fileSizeList[i],
265 fileModeList[i], fileMTimeList[i],
266 fileRdevList[i], NULL,
267 NULL, fileUIDList[i],
268 fileGIDList[i], fileLinktoList[i]);
270 rpmError(RPMERR_INTERNAL, _("package has "
271 "neither file owner or id lists"));
277 free(fileLinktoList);
279 if (fileOwnerList) free(fileOwnerList);
280 if (fileGroupList) free(fileGroupList);
286 static char * permsString(int mode) {
287 static char perms[11];
289 strcpy(perms, "----------");
291 if (mode & S_IRUSR) perms[1] = 'r';
292 if (mode & S_IWUSR) perms[2] = 'w';
293 if (mode & S_IXUSR) perms[3] = 'x';
295 if (mode & S_IRGRP) perms[4] = 'r';
296 if (mode & S_IWGRP) perms[5] = 'w';
297 if (mode & S_IXGRP) perms[6] = 'x';
299 if (mode & S_IROTH) perms[7] = 'r';
300 if (mode & S_IWOTH) perms[8] = 'w';
301 if (mode & S_IXOTH) perms[9] = 'x';
305 perms[9] = ((mode & S_IXOTH) ? 't' : 'T');
307 if (mode & S_ISUID) {
314 if (mode & S_ISGID) {
323 else if (S_ISLNK(mode)) {
326 else if (S_ISFIFO(mode))
328 else if (S_ISSOCK(mode))
330 else if (S_ISCHR(mode)) {
332 } else if (S_ISBLK(mode)) {
339 static void printFileInfo(char * name, unsigned int size, unsigned short mode,
340 unsigned int mtime, unsigned short rdev,
341 char * owner, char * group, int uid, int gid,
344 char ownerfield[9], groupfield[9];
345 char timefield[100] = "";
348 static int thisYear = 0;
349 static int thisMonth = 0;
351 char * namefield = name;
354 perms = permsString(mode);
357 currenttime = time(NULL);
358 tstruct = localtime(¤ttime);
359 thisYear = tstruct->tm_year;
360 thisMonth = tstruct->tm_mon;
363 ownerfield[8] = groupfield[8] = '\0';
366 strncpy(ownerfield, owner, 8);
368 sprintf(ownerfield, "%-8d", uid);
371 strncpy(groupfield, group, 8);
373 sprintf(groupfield, "%-8d", gid);
375 /* this is normally right */
376 sprintf(sizefield, "%10u", size);
378 /* this knows too much about dev_t */
381 namefield = alloca(strlen(name) + strlen(linkto) + 10);
382 sprintf(namefield, "%s -> %s", name, linkto);
383 } else if (S_ISCHR(mode)) {
385 sprintf(sizefield, "%3u, %3u", (rdev >> 8) & 0xff, rdev & 0xFF);
386 } else if (S_ISBLK(mode)) {
388 sprintf(sizefield, "%3u, %3u", (rdev >> 8) & 0xff, rdev & 0xFF);
391 /* this is important if sizeof(int_32) ! sizeof(time_t) */
393 tstruct = localtime(&themtime);
395 if (tstruct->tm_year == thisYear ||
396 ((tstruct->tm_year + 1) == thisYear && tstruct->tm_mon > thisMonth))
397 (void)strftime(timefield, sizeof(timefield) - 1, "%b %d %H:%M",tstruct);
399 (void)strftime(timefield, sizeof(timefield) - 1, "%b %d %Y", tstruct);
401 fprintf(stdout, "%s %8s %8s %10s %s %s\n", perms, ownerfield, groupfield,
402 sizefield, timefield, namefield);
405 static void showMatches(rpmdb db, dbiIndexSet matches, int queryFlags,
406 const char * queryFormat) {
410 for (i = 0; i < dbiIndexSetCount(matches); i++) {
411 unsigned int recOffset = dbiIndexRecordOffset(matches, i);
413 rpmMessage(RPMMESS_DEBUG, _("querying record number %d\n"),
416 h = rpmdbGetRecord(db, recOffset);
418 fprintf(stderr, _("error: could not read database record\n"));
420 printHeader(h, queryFlags, queryFormat);
430 printNewSpecfile(Spec spec)
432 struct speclines *sl = spec->sl;
433 struct spectags *st = spec->st;
437 if (sl == NULL || st == NULL)
440 #define SPECSPACKAGE "specs"
442 for (i = 0; i < st->st_ntags; i++) {
447 /* XXX Summary tag often precedes name, so build msgid now. */
448 if (t->t_msgid == NULL) {
450 headerGetEntry(spec->packages->header, RPMTAG_NAME, NULL,
452 sprintf(buf, "%s(%s)", n, tagName(t->t_tag));
453 t->t_msgid = strdup(buf);
455 msgstr = strdup(dgettext(SPECSPACKAGE, t->t_msgid));
460 FREE(sl->sl_lines[t->t_startx]);
461 if (t->t_lang && strcmp(t->t_lang, RPMBUILD_DEFAULT_LANG))
463 sprintf(buf, "%s: %s\n",
464 ((t->t_tag == RPMTAG_GROUP) ? "Group" : "Summary"),
466 sl->sl_lines[t->t_startx] = strdup(buf);
468 case RPMTAG_DESCRIPTION:
469 for (j = 1; j < t->t_nlines; j++)
470 FREE(sl->sl_lines[t->t_startx + j]);
471 if (t->t_lang && strcmp(t->t_lang, RPMBUILD_DEFAULT_LANG)) {
472 FREE(sl->sl_lines[t->t_startx]);
475 sl->sl_lines[t->t_startx + 1] = strdup(msgstr);
477 sl->sl_lines[t->t_startx + 2] = strdup("\n\n");
482 for (i = 0; i < sl->sl_nlines; i++) {
483 if (sl->sl_lines[i] == NULL)
485 printf("%s", sl->sl_lines[i]);
489 int rpmQuery(const char * prefix, enum rpmQuerySources source, int queryFlags,
490 const char * arg, const char * queryFormat) {
503 if (rpmdbOpen(prefix, &db, O_RDONLY, 0644)) {
504 fprintf(stderr, _("rpmQuery: rpmdbOpen() failed\n"));
517 fd = ufdOpen(arg, O_RDONLY, 0);
518 if (fdFileno(fd) < 0) {
519 fprintf(stderr, _("open of %s failed\n"), arg);
525 rc = rpmReadPackageHeader(fd, &h, &isSource, NULL, NULL);
532 fprintf(stderr, _("old format source packages cannot "
535 printHeader(h, queryFlags, queryFormat);
540 fprintf(stderr, _("%s does not appear to be a RPM package\n"), arg);
543 fprintf(stderr, _("query of %s failed\n"), arg);
552 char * buildRoot = NULL;
554 char * passPhrase = "";
558 rc = parseSpec(&spec, arg, buildRoot, inBuildArch, passPhrase, cookie,
560 if (rc || spec == NULL) {
562 fprintf(stderr, _("query of specfile %s failed, can't parse\n"), arg);
563 if (spec != NULL) freeSpec(spec);
569 printNewSpecfile(spec);
575 for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
577 char *binRpm, *errorString;
578 binRpm = headerSprintf(pkg->header,
579 rpmGetPath("%{_rpmfilename}", NULL),
580 rpmTagTable, rpmHeaderFormats, &errorString);
581 if (!(pkg == spec->packages && pkg->next == NULL))
582 fprintf(stdout, "====== %s\n", binRpm);
585 printHeader(pkg->header, queryFlags, queryFormat);
591 offset = rpmdbFirstRecNum(db);
593 h = rpmdbGetRecord(db, offset);
595 fprintf(stderr, _("could not read database record!\n"));
598 printHeader(h, queryFlags, queryFormat);
600 offset = rpmdbNextRecNum(db, offset);
605 if (rpmdbFindByGroup(db, arg, &matches)) {
606 fprintf(stderr, _("group %s does not contain any packages\n"), arg);
609 showMatches(db, matches, queryFlags, queryFormat);
610 dbiFreeIndexRecord(matches);
614 case QUERY_WHATPROVIDES:
615 if (rpmdbFindByProvides(db, arg, &matches)) {
616 fprintf(stderr, _("no package provides %s\n"), arg);
619 showMatches(db, matches, queryFlags, queryFormat);
620 dbiFreeIndexRecord(matches);
624 case QUERY_TRIGGEREDBY:
625 if (rpmdbFindByTriggeredBy(db, arg, &matches)) {
626 fprintf(stderr, _("no package triggers %s\n"), arg);
629 showMatches(db, matches, queryFlags, queryFormat);
630 dbiFreeIndexRecord(matches);
634 case QUERY_WHATREQUIRES:
635 if (rpmdbFindByRequiredBy(db, arg, &matches)) {
636 fprintf(stderr, _("no package requires %s\n"), arg);
639 showMatches(db, matches, queryFlags, queryFormat);
640 dbiFreeIndexRecord(matches);
645 if (rpmdbFindByFile(db, arg, &matches)) {
647 if (access(arg, F_OK) != 0)
651 fprintf(stderr, _("file %s: %s\n"), arg, strerror(myerrno));
654 fprintf(stderr, _("file %s is not owned by any package\n"), arg);
659 showMatches(db, matches, queryFlags, queryFormat);
660 dbiFreeIndexRecord(matches);
665 recNumber = strtoul(arg, &end, 10);
666 if ((*end) || (end == arg) || (recNumber == ULONG_MAX)) {
667 fprintf(stderr, _("invalid package number: %s\n"), arg);
670 rpmMessage(RPMMESS_DEBUG, _("showing package: %d\n"), recNumber);
671 h = rpmdbGetRecord(db, recNumber);
673 fprintf(stderr, _("record %d could not be read\n"), recNumber);
676 printHeader(h, queryFlags, queryFormat);
682 rc = rpmdbFindByLabel(db, arg, &matches);
685 fprintf(stderr, _("package %s is not installed\n"), arg);
686 } else if (rc == 2) {
688 fprintf(stderr, _("error looking for package %s\n"), arg);
690 showMatches(db, matches, queryFlags, queryFormat);
691 dbiFreeIndexRecord(matches);
708 void rpmDisplayQueryTags(FILE * f) {
709 const struct headerTagTableEntry * t;
711 const struct headerSprintfExtension * ext = rpmHeaderFormats;
713 for (i = 0, t = rpmTagTable; i < rpmTagTableSize; i++, t++) {
714 fprintf(f, "%s\n", t->name + 7);
718 if (ext->type == HEADER_EXT_TAG)
719 fprintf(f, "%s\n", ext->name + 7), ext++;
720 else if (ext->type == HEADER_EXT_MORE)