7 #include "build/rpmbuild.h"
11 static char * permsString(int mode);
12 static void printHeader(Header h, int queryFlags, char * queryFormat);
13 static void showMatches(rpmdb db, dbiIndexSet matches, int queryFlags,
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, 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, 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 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);
427 int rpmQuery(char * prefix, enum rpmQuerySources source, int queryFlags,
428 char * arg, char * queryFormat) {
442 if (rpmdbOpen(prefix, &db, O_RDONLY, 0644)) {
443 fprintf(stderr, _("rpmQuery: rpmdbOpen() failed\n"));
456 fd = ufdOpen(arg, O_RDONLY, 0);
458 fprintf(stderr, _("open of %s failed\n"), arg);
464 if (fdFileno(fd) >= 0) {
465 rc = rpmReadPackageHeader(fd, &h, &isSource, NULL, NULL);
474 fprintf(stderr, _("old format source packages cannot "
477 printHeader(h, queryFlags, queryFormat);
482 fprintf(stderr, _("%s does not appear to be a RPM package\n"), arg);
485 fprintf(stderr, _("query of %s failed\n"), arg);
494 char * buildRoot = NULL;
496 char * passPhrase = "";
500 rc = parseSpec(&spec, arg, buildRoot, inBuildArch, passPhrase, cookie,
502 if (rc || spec == NULL) {
504 fprintf(stderr, _("query of specfile %s failed, can't parse\n"), arg);
505 if (spec != NULL) freeSpec(spec);
509 for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
511 char *binRpm, *errorString;
512 binRpm = headerSprintf(pkg->header, rpmGetVar(RPMVAR_RPMFILENAME),
513 rpmTagTable, rpmHeaderFormats, &errorString);
514 if (!(pkg == spec->packages && pkg->next == NULL))
515 fprintf(stdout, "====== %s\n", binRpm);
518 printHeader(pkg->header, queryFlags, queryFormat);
524 offset = rpmdbFirstRecNum(db);
526 h = rpmdbGetRecord(db, offset);
528 fprintf(stderr, _("could not read database record!\n"));
531 printHeader(h, queryFlags, queryFormat);
533 offset = rpmdbNextRecNum(db, offset);
538 if (rpmdbFindByGroup(db, arg, &matches)) {
539 fprintf(stderr, _("group %s does not contain any packages\n"), arg);
542 showMatches(db, matches, queryFlags, queryFormat);
543 dbiFreeIndexRecord(matches);
547 case QUERY_WHATPROVIDES:
548 if (rpmdbFindByProvides(db, arg, &matches)) {
549 fprintf(stderr, _("no package provides %s\n"), arg);
552 showMatches(db, matches, queryFlags, queryFormat);
553 dbiFreeIndexRecord(matches);
557 case QUERY_TRIGGEREDBY:
558 if (rpmdbFindByTriggeredBy(db, arg, &matches)) {
559 fprintf(stderr, _("no package triggers %s\n"), arg);
562 showMatches(db, matches, queryFlags, queryFormat);
563 dbiFreeIndexRecord(matches);
567 case QUERY_WHATREQUIRES:
568 if (rpmdbFindByRequiredBy(db, arg, &matches)) {
569 fprintf(stderr, _("no package requires %s\n"), arg);
572 showMatches(db, matches, queryFlags, queryFormat);
573 dbiFreeIndexRecord(matches);
579 /* Using realpath on the arg isn't correct if the arg is a symlink,
580 * especially if the symlink is a dangling link. What we should
581 * instead do is use realpath() on `.' and then append arg to
584 if (realpath(".", path) != NULL) {
585 if (path[strlen(path)] != '/') {
586 if (strncat(path, "/", PATH_MAX - strlen(path) - 1) == NULL) {
587 fprintf(stderr, _("maximum path length exceeded\n"));
591 /* now append the original file name to the real path */
592 if (strncat(path, arg, PATH_MAX - strlen(path) - 1) == NULL) {
593 fprintf(stderr, _("maximum path length exceeded\n"));
599 if (rpmdbFindByFile(db, arg, &matches)) {
601 if (access(arg, F_OK) != 0)
605 fprintf(stderr, _("file %s: %s\n"), arg, strerror(myerrno));
608 fprintf(stderr, _("file %s is not owned by any package\n"), arg);
613 showMatches(db, matches, queryFlags, queryFormat);
614 dbiFreeIndexRecord(matches);
619 recNumber = strtoul(arg, &end, 10);
620 if ((*end) || (end == arg) || (recNumber == ULONG_MAX)) {
621 fprintf(stderr, _("invalid package number: %s\n"), arg);
624 rpmMessage(RPMMESS_DEBUG, _("showing package: %d\n"), recNumber);
625 h = rpmdbGetRecord(db, recNumber);
627 fprintf(stderr, _("record %d could not be read\n"), recNumber);
630 printHeader(h, queryFlags, queryFormat);
636 rc = rpmdbFindByLabel(db, arg, &matches);
639 fprintf(stderr, _("package %s is not installed\n"), arg);
640 } else if (rc == 2) {
642 fprintf(stderr, _("error looking for package %s\n"), arg);
644 showMatches(db, matches, queryFlags, queryFormat);
645 dbiFreeIndexRecord(matches);
662 void rpmDisplayQueryTags(FILE * f) {
663 const struct headerTagTableEntry * t;
665 const struct headerSprintfExtension * ext = rpmHeaderFormats;
667 for (i = 0, t = rpmTagTable; i < rpmTagTableSize; i++, t++) {
668 fprintf(f, "%s\n", t->name + 7);
672 if (ext->type == HEADER_EXT_TAG)
673 fprintf(f, "%s\n", ext->name + 7), ext++;
674 else if (ext->type == HEADER_EXT_MORE)