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', "query package owning file", "FILE" },
36 { "group", 'g', 0, 0, 'g', "query packages in group", "GROUP" },
37 { "package", 'p', 0, 0, 'p', "query a package file", NULL },
38 { "specfile", '\0', 0, 0, POPT_SPECFILE, "query a spec file", NULL },
39 { "triggeredby", '\0', 0, 0, POPT_TRIGGEREDBY,
40 "query the pacakges triggered by the package", "PACKAGE" },
41 { "whatrequires", '\0', 0, 0, POPT_WHATREQUIRES,
42 "query the packages which require a capability", "CAPABILITY" },
43 { "whatprovides", '\0', 0, 0, POPT_WHATPROVIDES,
44 "query the packages which provide a capability", "CAPABILITY" },
45 { 0, 0, 0, 0, 0, NULL, NULL }
48 struct poptOption rpmQueryPoptTable[] = {
49 { NULL, '\0', POPT_ARG_CALLBACK | POPT_CBFLAG_INC_DATA,
50 queryArgCallback, 0, NULL, NULL },
51 { "configfiles", 'c', 0, 0, 'c', "list all configuration files", NULL },
52 { "docfiles", 'd', 0, 0, 'd', "list all documetnation files", NULL },
53 { "dump", '\0', 0, 0, POPT_DUMP, "dump basic file information", NULL },
54 { "list", 'l', 0, 0, 'l', "list files in package", NULL },
55 { "qf", '\0', POPT_ARG_STRING | POPT_ARGFLAG_DOC_HIDDEN, 0,
56 POPT_QUERYFORMAT, NULL, NULL },
57 { "querybynumber", '\0', POPT_ARGFLAG_DOC_HIDDEN, 0,
58 POPT_QUERYBYNUMBER, NULL, NULL },
59 { "queryformat", '\0', POPT_ARG_STRING, 0, POPT_QUERYFORMAT,
60 "use the following query format", "QUERYFORMAT" },
61 { "state", 's', 0, 0, 's', "display the states of the listed files", NULL },
62 { "verbose", 'v', 0, 0, 'v', "display a verbose file listing", NULL },
63 { 0, 0, 0, 0, 0, NULL, NULL }
66 static void queryArgCallback(poptContext con, enum poptCallbackReason reason,
67 const struct poptOption * opt, const char * arg,
68 struct rpmQueryArguments * data) {
72 case 'c': data->flags |= QUERY_FOR_CONFIG | QUERY_FOR_LIST; break;
73 case 'd': data->flags |= QUERY_FOR_DOCS | QUERY_FOR_LIST; break;
74 case 'l': data->flags |= QUERY_FOR_LIST; break;
75 case 's': data->flags |= QUERY_FOR_STATE | QUERY_FOR_LIST; break;
76 case POPT_DUMP: data->flags |= QUERY_FOR_DUMPFILES | QUERY_FOR_LIST; break;
78 case 'a': data->source |= QUERY_ALL; data->sourceCount++; break;
79 case 'f': data->source |= QUERY_PATH; data->sourceCount++; break;
80 case 'g': data->source |= QUERY_GROUP; data->sourceCount++; break;
81 case 'p': data->source |= QUERY_RPM; data->sourceCount++; break;
82 case 'v': rpmIncreaseVerbosity(); break;
83 case POPT_SPECFILE: data->source |= QUERY_SPECFILE; data->sourceCount++; break;
84 case POPT_WHATPROVIDES: data->source |= QUERY_WHATPROVIDES;
85 data->sourceCount++; break;
86 case POPT_WHATREQUIRES: data->source |= QUERY_WHATREQUIRES;
87 data->sourceCount++; break;
88 case POPT_QUERYBYNUMBER: data->source |= QUERY_DBOFFSET;
89 data->sourceCount++; break;
90 case POPT_TRIGGEREDBY: data->source |= QUERY_TRIGGEREDBY;
91 data->sourceCount++; break;
93 case POPT_QUERYFORMAT:
94 if (data->queryFormat) {
95 len = strlen(data->queryFormat) + strlen(arg) + 1;
96 data->queryFormat = realloc(data->queryFormat, len);
97 strcat(data->queryFormat, arg);
99 data->queryFormat = malloc(strlen(arg) + 1);
100 strcpy(data->queryFormat, arg);
106 static int queryHeader(Header h, char * chptr) {
110 str = headerSprintf(h, chptr, rpmTagTable, rpmHeaderFormats, &error);
112 fprintf(stderr, _("error in format: %s\n"), error);
121 static void printHeader(Header h, int queryFlags, char * queryFormat) {
122 char * name, * version, * release;
124 char * prefix = NULL;
125 char ** fileList, ** fileMD5List;
126 char * fileStatesList;
127 char ** fileOwnerList = NULL;
128 char ** fileGroupList = NULL;
129 char ** fileLinktoList;
130 int_32 * fileFlagsList, * fileMTimeList, * fileSizeList;
131 int_32 * fileUIDList, * fileGIDList;
132 uint_16 * fileModeList;
133 uint_16 * fileRdevList;
136 headerGetEntry(h, RPMTAG_NAME, &type, (void **) &name, &count);
137 headerGetEntry(h, RPMTAG_VERSION, &type, (void **) &version, &count);
138 headerGetEntry(h, RPMTAG_RELEASE, &type, (void **) &release, &count);
140 if (!queryFormat && !queryFlags) {
141 fprintf(stdout, "%s-%s-%s\n", name, version, release);
144 queryHeader(h, queryFormat);
146 if (queryFlags & QUERY_FOR_LIST) {
147 if (!headerGetEntry(h, RPMTAG_FILENAMES, &type, (void **) &fileList,
149 fputs(_("(contains no files)"), stdout);
152 if (!headerGetEntry(h, RPMTAG_FILESTATES, &type,
153 (void **) &fileStatesList, &count)) {
154 fileStatesList = NULL;
156 headerGetEntry(h, RPMTAG_FILEFLAGS, &type,
157 (void **) &fileFlagsList, &count);
158 headerGetEntry(h, RPMTAG_FILESIZES, &type,
159 (void **) &fileSizeList, &count);
160 headerGetEntry(h, RPMTAG_FILEMODES, &type,
161 (void **) &fileModeList, &count);
162 headerGetEntry(h, RPMTAG_FILEMTIMES, &type,
163 (void **) &fileMTimeList, &count);
164 headerGetEntry(h, RPMTAG_FILERDEVS, &type,
165 (void **) &fileRdevList, &count);
166 headerGetEntry(h, RPMTAG_FILELINKTOS, &type,
167 (void **) &fileLinktoList, &count);
168 headerGetEntry(h, RPMTAG_FILEMD5S, &type,
169 (void **) &fileMD5List, &count);
171 if (!headerGetEntry(h, RPMTAG_FILEUIDS, &type,
172 (void **) &fileUIDList, &count)) {
175 headerGetEntry(h, RPMTAG_FILEGIDS, &type,
176 (void **) &fileGIDList, &count);
179 if (!headerGetEntry(h, RPMTAG_FILEUSERNAME, &type,
180 (void **) &fileOwnerList, &count)) {
181 fileOwnerList = NULL;
183 headerGetEntry(h, RPMTAG_FILEGROUPNAME, &type,
184 (void **) &fileGroupList, &count);
187 for (i = 0; i < count; i++) {
188 if (!((queryFlags & QUERY_FOR_DOCS) ||
189 (queryFlags & QUERY_FOR_CONFIG))
190 || ((queryFlags & QUERY_FOR_DOCS) &&
191 (fileFlagsList[i] & RPMFILE_DOC))
192 || ((queryFlags & QUERY_FOR_CONFIG) &&
193 (fileFlagsList[i] & RPMFILE_CONFIG))) {
196 prefix ? fputs(prefix, stdout) : 0;
198 if (queryFlags & QUERY_FOR_STATE) {
199 if (fileStatesList) {
200 switch (fileStatesList[i]) {
201 case RPMFILE_STATE_NORMAL:
202 fputs(_("normal "), stdout); break;
203 case RPMFILE_STATE_REPLACED:
204 fputs(_("replaced "), stdout); break;
205 case RPMFILE_STATE_NETSHARED:
206 fputs(_("net shared "), stdout); break;
207 case RPMFILE_STATE_NOTINSTALLED:
208 fputs(_("not installed "), stdout); break;
210 fprintf(stdout, _("(unknown %3d) "),
214 fputs( _("(no state) "), stdout);
218 if (queryFlags & QUERY_FOR_DUMPFILES) {
219 fprintf(stdout, "%s %d %d %s 0%o ", fileList[i],
220 fileSizeList[i], fileMTimeList[i],
221 fileMD5List[i], fileModeList[i]);
224 fprintf(stdout, "%s %s", fileOwnerList[i],
226 else if (fileUIDList)
227 fprintf(stdout, "%d %d", fileUIDList[i],
230 rpmError(RPMERR_INTERNAL, _("package has "
231 "neither file owner or id lists"));
234 fprintf(stdout, " %s %s %u ",
235 fileFlagsList[i] & RPMFILE_CONFIG ? "1" : "0",
236 fileFlagsList[i] & RPMFILE_DOC ? "1" : "0",
237 (unsigned)fileRdevList[i]);
239 if (strlen(fileLinktoList[i]))
240 fprintf(stdout, "%s\n", fileLinktoList[i]);
242 fprintf(stdout, "X\n");
244 } else if (!rpmIsVerbose()) {
245 fputs(fileList[i], stdout);
247 } else if (fileOwnerList)
248 printFileInfo(fileList[i], fileSizeList[i],
249 fileModeList[i], fileMTimeList[i],
250 fileRdevList[i], fileOwnerList[i],
251 fileGroupList[i], -1,
252 -1, fileLinktoList[i]);
253 else if (fileUIDList) {
254 printFileInfo(fileList[i], fileSizeList[i],
255 fileModeList[i], fileMTimeList[i],
256 fileRdevList[i], NULL,
257 NULL, fileUIDList[i],
258 fileGIDList[i], fileLinktoList[i]);
260 rpmError(RPMERR_INTERNAL, _("package has "
261 "neither file owner or id lists"));
267 free(fileLinktoList);
269 if (fileOwnerList) free(fileOwnerList);
270 if (fileGroupList) free(fileGroupList);
276 static char * permsString(int mode) {
277 static char perms[11];
279 strcpy(perms, "----------");
281 if (mode & S_IRUSR) perms[1] = 'r';
282 if (mode & S_IWUSR) perms[2] = 'w';
283 if (mode & S_IXUSR) perms[3] = 'x';
285 if (mode & S_IRGRP) perms[4] = 'r';
286 if (mode & S_IWGRP) perms[5] = 'w';
287 if (mode & S_IXGRP) perms[6] = 'x';
289 if (mode & S_IROTH) perms[7] = 'r';
290 if (mode & S_IWOTH) perms[8] = 'w';
291 if (mode & S_IXOTH) perms[9] = 'x';
295 perms[9] = ((mode & S_IXOTH) ? 't' : 'T');
297 if (mode & S_ISUID) {
304 if (mode & S_ISGID) {
313 else if (S_ISLNK(mode)) {
316 else if (S_ISFIFO(mode))
318 else if (S_ISSOCK(mode))
320 else if (S_ISCHR(mode)) {
322 } else if (S_ISBLK(mode)) {
329 static void printFileInfo(char * name, unsigned int size, unsigned short mode,
330 unsigned int mtime, unsigned short rdev,
331 char * owner, char * group, int uid, int gid,
334 char ownerfield[9], groupfield[9];
335 char timefield[100] = "";
338 static int thisYear = 0;
339 static int thisMonth = 0;
341 char * namefield = name;
344 perms = permsString(mode);
347 currenttime = time(NULL);
348 tstruct = localtime(¤ttime);
349 thisYear = tstruct->tm_year;
350 thisMonth = tstruct->tm_mon;
353 ownerfield[8] = groupfield[8] = '\0';
356 strncpy(ownerfield, owner, 8);
358 sprintf(ownerfield, "%-8d", uid);
361 strncpy(groupfield, group, 8);
363 sprintf(groupfield, "%-8d", gid);
365 /* this is normally right */
366 sprintf(sizefield, "%10u", size);
368 /* this knows too much about dev_t */
371 namefield = alloca(strlen(name) + strlen(linkto) + 10);
372 sprintf(namefield, "%s -> %s", name, linkto);
373 } else if (S_ISCHR(mode)) {
375 sprintf(sizefield, "%3u, %3u", (rdev >> 8) & 0xff, rdev & 0xFF);
376 } else if (S_ISBLK(mode)) {
378 sprintf(sizefield, "%3u, %3u", (rdev >> 8) & 0xff, rdev & 0xFF);
381 /* this is important if sizeof(int_32) ! sizeof(time_t) */
383 tstruct = localtime(&themtime);
385 if (tstruct->tm_year == thisYear ||
386 ((tstruct->tm_year + 1) == thisYear && tstruct->tm_mon > thisMonth))
387 (void)strftime(timefield, sizeof(timefield) - 1, "%b %d %H:%M",tstruct);
389 (void)strftime(timefield, sizeof(timefield) - 1, "%b %d %Y", tstruct);
391 fprintf(stdout, "%s %8s %8s %10s %s %s\n", perms, ownerfield, groupfield,
392 sizefield, timefield, namefield);
395 static void showMatches(rpmdb db, dbiIndexSet matches, int queryFlags,
396 char * queryFormat) {
400 for (i = 0; i < dbiIndexSetCount(matches); i++) {
401 unsigned int recOffset = dbiIndexRecordOffset(matches, i);
403 rpmMessage(RPMMESS_DEBUG, _("querying record number %d\n"),
406 h = rpmdbGetRecord(db, recOffset);
408 fprintf(stderr, _("error: could not read database record\n"));
410 printHeader(h, queryFlags, queryFormat);
417 int rpmQuery(char * prefix, enum rpmQuerySources source, int queryFlags,
418 char * arg, char * queryFormat) {
428 struct urlContext context;
433 if (rpmdbOpen(prefix, &db, O_RDONLY, 0644)) {
434 fprintf(stderr, _("rpmQuery: rpmdbOpen() failed\n"));
450 if ((fdno = urlGetFd(arg, &context)) < 0) {
451 fprintf(stderr, _("open of %s failed: %s\n"), arg,
456 } else if (!strcmp(arg, "-")) {
457 fd = fdDup(STDIN_FILENO);
459 if (fdFileno(fd = fdOpen( arg, O_RDONLY, 0)) < 0) {
460 fprintf(stderr, _("open of %s failed: %s\n"), arg,
465 if (fd != NULL && fdFileno(fd) >= 0) {
466 rc = rpmReadPackageHeader(fd, &h, &isSource, NULL, NULL);
470 urlFinishedFd(&context);
476 fprintf(stderr, _("old format source packages cannot "
479 printHeader(h, queryFlags, queryFormat);
485 _("%s does not appear to be a RPM package\n"),
489 fprintf(stderr, _("query of %s failed\n"), arg);
498 char * buildRoot = NULL;
500 char * passPhrase = "";
504 rc = parseSpec(&spec, arg, buildRoot, inBuildArch, passPhrase, cookie,
506 if (rc || spec == NULL) {
508 fprintf(stderr, _("query of specfile %s failed, can't parse\n"), arg);
509 if (spec != NULL) freeSpec(spec);
513 for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
515 char *binRpm, *errorString;
516 binRpm = headerSprintf(pkg->header, rpmGetVar(RPMVAR_RPMFILENAME),
517 rpmTagTable, rpmHeaderFormats, &errorString);
518 if (!(pkg == spec->packages && pkg->next == NULL))
519 fprintf(stdout, "====== %s\n", binRpm);
522 printHeader(pkg->header, queryFlags, queryFormat);
528 offset = rpmdbFirstRecNum(db);
530 h = rpmdbGetRecord(db, offset);
532 fprintf(stderr, _("could not read database record!\n"));
535 printHeader(h, queryFlags, queryFormat);
537 offset = rpmdbNextRecNum(db, offset);
542 if (rpmdbFindByGroup(db, arg, &matches)) {
543 fprintf(stderr, _("group %s does not contain any packages\n"), arg);
546 showMatches(db, matches, queryFlags, queryFormat);
547 dbiFreeIndexRecord(matches);
551 case QUERY_WHATPROVIDES:
552 if (rpmdbFindByProvides(db, arg, &matches)) {
553 fprintf(stderr, _("no package provides %s\n"), arg);
556 showMatches(db, matches, queryFlags, queryFormat);
557 dbiFreeIndexRecord(matches);
561 case QUERY_TRIGGEREDBY:
562 if (rpmdbFindByTriggeredBy(db, arg, &matches)) {
563 fprintf(stderr, _("no package triggers %s\n"), arg);
566 showMatches(db, matches, queryFlags, queryFormat);
567 dbiFreeIndexRecord(matches);
571 case QUERY_WHATREQUIRES:
572 if (rpmdbFindByRequiredBy(db, arg, &matches)) {
573 fprintf(stderr, _("no package requires %s\n"), arg);
576 showMatches(db, matches, queryFlags, queryFormat);
577 dbiFreeIndexRecord(matches);
583 /* Using realpath on the arg isn't correct if the arg is a symlink,
584 * especially if the symlink is a dangling link. What we should
585 * instead do is use realpath() on `.' and then append arg to
588 if (realpath(".", path) != NULL) {
589 if (path[strlen(path)] != '/') {
590 if (strncat(path, "/", PATH_MAX - strlen(path) - 1) == NULL) {
591 fprintf(stderr, _("maximum path length exceeded\n"));
595 /* now append the original file name to the real path */
596 if (strncat(path, arg, PATH_MAX - strlen(path) - 1) == NULL) {
597 fprintf(stderr, _("maximum path length exceeded\n"));
603 if (rpmdbFindByFile(db, arg, &matches)) {
605 if (access(arg, F_OK) != 0)
609 fprintf(stderr, _("file %s: %s\n"), arg, strerror(myerrno));
612 fprintf(stderr, _("file %s is not owned by any package\n"), arg);
617 showMatches(db, matches, queryFlags, queryFormat);
618 dbiFreeIndexRecord(matches);
623 recNumber = strtoul(arg, &end, 10);
624 if ((*end) || (end == arg) || (recNumber == ULONG_MAX)) {
625 fprintf(stderr, _("invalid package number: %s\n"), arg);
628 rpmMessage(RPMMESS_DEBUG, _("showing package: %d\n"), recNumber);
629 h = rpmdbGetRecord(db, recNumber);
631 fprintf(stderr, _("record %d could not be read\n"), recNumber);
634 printHeader(h, queryFlags, queryFormat);
640 rc = rpmdbFindByLabel(db, arg, &matches);
643 fprintf(stderr, _("package %s is not installed\n"), arg);
644 } else if (rc == 2) {
646 fprintf(stderr, _("error looking for package %s\n"), arg);
648 showMatches(db, matches, queryFlags, queryFormat);
649 dbiFreeIndexRecord(matches);
666 void rpmDisplayQueryTags(FILE * f) {
667 const struct headerTagTableEntry * t;
669 const struct headerSprintfExtension * ext = rpmHeaderFormats;
671 for (i = 0, t = rpmTagTable; i < rpmTagTableSize; i++, t++) {
672 fprintf(f, "%s\n", t->name + 7);
676 if (ext->type == HEADER_EXT_TAG)
677 fprintf(f, "%s\n", ext->name + 7), ext++;
678 else if (ext->type == HEADER_EXT_MORE)