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
27 static void queryArgCallback(poptContext con, enum poptCallbackReason reason,
28 const struct poptOption * opt, const char * arg,
29 struct rpmQueryArguments * data);
31 struct poptOption rpmQuerySourcePoptTable[] = {
32 { NULL, '\0', POPT_ARG_CALLBACK | POPT_CBFLAG_INC_DATA,
33 queryArgCallback, 0, NULL, NULL },
34 { "file", 'f', 0, 0, 'f', "query package owning file", "FILE" },
35 { "group", 'g', 0, 0, 'g', "query packages in group", "GROUP" },
36 { "package", 'p', 0, 0, 'p', "query a package file" },
37 { "triggeredby", '\0', 0, 0, POPT_TRIGGEREDBY,
38 "query the pacakges triggered by the package", "PACKAGE" },
39 { "whatrequires", '\0', 0, 0, POPT_WHATREQUIRES,
40 "query the packages which require a capability", "CAPABILITY" },
41 { "whatprovides", '\0', 0, 0, POPT_WHATPROVIDES,
42 "query the packages which provide a capability", "CAPABILITY" },
46 struct poptOption rpmQueryPoptTable[] = {
47 { NULL, '\0', POPT_ARG_CALLBACK | POPT_CBFLAG_INC_DATA,
48 queryArgCallback, 0, NULL, NULL },
49 { "configfiles", 'c', 0, 0, 'c', "list all configuration files" },
50 { "docfiles", 'd', 0, 0, 'd', "list all documetnation files" },
51 { "dump", '\0', 0, 0, POPT_DUMP, "dump basic file information" },
52 { "list", 'l', 0, 0, 'l', "list files in package" },
53 { "qf", '\0', POPT_ARG_STRING | POPT_ARGFLAG_DOC_HIDDEN, 0,
55 { "querybynumber", '\0', POPT_ARGFLAG_DOC_HIDDEN, 0,
57 { "queryformat", '\0', POPT_ARG_STRING, 0, POPT_QUERYFORMAT,
58 "use the following query format", "QUERYFORMAT" },
59 { "state", 's', 0, 0, 's', "display the states of the listed files" },
60 { "verbose", 'v', 0, 0, 'v', "display a verbose filelisting" },
64 static void queryArgCallback(poptContext con, enum poptCallbackReason reason,
65 const struct poptOption * opt, const char * arg,
66 struct rpmQueryArguments * data) {
70 case 'c': data->flags |= QUERY_FOR_CONFIG | QUERY_FOR_LIST; break;
71 case 'd': data->flags |= QUERY_FOR_DOCS | QUERY_FOR_LIST; break;
72 case 'l': data->flags |= QUERY_FOR_LIST; break;
73 case 's': data->flags |= QUERY_FOR_STATE | QUERY_FOR_LIST; break;
74 case POPT_DUMP: data->flags |= QUERY_FOR_DUMPFILES | QUERY_FOR_LIST; break;
76 case 'a': data->source |= QUERY_ALL; data->sourceCount++; break;
77 case 'f': data->source |= QUERY_PATH; data->sourceCount++; break;
78 case 'g': data->source |= QUERY_GROUP; data->sourceCount++; break;
79 case 'p': data->source |= QUERY_RPM; data->sourceCount++; break;
80 case POPT_WHATPROVIDES: data->source |= QUERY_WHATPROVIDES;
81 data->sourceCount++; break;
82 case POPT_WHATREQUIRES: data->source |= QUERY_WHATREQUIRES;
83 data->sourceCount++; break;
84 case POPT_QUERYBYNUMBER: data->source |= QUERY_DBOFFSET;
85 data->sourceCount++; break;
86 case POPT_TRIGGEREDBY: data->source |= QUERY_TRIGGEREDBY;
87 data->sourceCount++; break;
89 case POPT_QUERYFORMAT:
90 if (data->queryFormat) {
91 len = strlen(data->queryFormat) + strlen(arg) + 1;
92 data->queryFormat = realloc(data->queryFormat, len);
93 strcat(data->queryFormat, arg);
95 data->queryFormat = malloc(strlen(arg) + 1);
96 strcpy(data->queryFormat, arg);
102 static int queryHeader(Header h, char * chptr) {
106 str = headerSprintf(h, chptr, rpmTagTable, rpmHeaderFormats, &error);
108 fprintf(stderr, _("error in format: %s\n"), error);
117 static void printHeader(Header h, int queryFlags, char * queryFormat) {
118 char * name, * version, * release;
120 char * prefix = NULL;
121 char ** fileList, ** fileMD5List;
122 char * fileStatesList;
123 char ** fileOwnerList = NULL;
124 char ** fileGroupList = NULL;
125 char ** fileLinktoList;
126 int_32 * fileFlagsList, * fileMTimeList, * fileSizeList;
127 int_32 * fileUIDList, * fileGIDList;
128 uint_16 * fileModeList;
129 uint_16 * fileRdevList;
132 headerGetEntry(h, RPMTAG_NAME, &type, (void **) &name, &count);
133 headerGetEntry(h, RPMTAG_VERSION, &type, (void **) &version, &count);
134 headerGetEntry(h, RPMTAG_RELEASE, &type, (void **) &release, &count);
136 if (!queryFormat && !queryFlags) {
137 fprintf(stdout, "%s-%s-%s\n", name, version, release);
140 queryHeader(h, queryFormat);
142 if (queryFlags & QUERY_FOR_LIST) {
143 if (!headerGetEntry(h, RPMTAG_FILENAMES, &type, (void **) &fileList,
145 fputs(_("(contains no files)"), stdout);
148 if (!headerGetEntry(h, RPMTAG_FILESTATES, &type,
149 (void **) &fileStatesList, &count)) {
150 fileStatesList = NULL;
152 headerGetEntry(h, RPMTAG_FILEFLAGS, &type,
153 (void **) &fileFlagsList, &count);
154 headerGetEntry(h, RPMTAG_FILESIZES, &type,
155 (void **) &fileSizeList, &count);
156 headerGetEntry(h, RPMTAG_FILEMODES, &type,
157 (void **) &fileModeList, &count);
158 headerGetEntry(h, RPMTAG_FILEMTIMES, &type,
159 (void **) &fileMTimeList, &count);
160 headerGetEntry(h, RPMTAG_FILERDEVS, &type,
161 (void **) &fileRdevList, &count);
162 headerGetEntry(h, RPMTAG_FILELINKTOS, &type,
163 (void **) &fileLinktoList, &count);
164 headerGetEntry(h, RPMTAG_FILEMD5S, &type,
165 (void **) &fileMD5List, &count);
167 if (!headerGetEntry(h, RPMTAG_FILEUIDS, &type,
168 (void **) &fileUIDList, &count)) {
171 headerGetEntry(h, RPMTAG_FILEGIDS, &type,
172 (void **) &fileGIDList, &count);
175 if (!headerGetEntry(h, RPMTAG_FILEUSERNAME, &type,
176 (void **) &fileOwnerList, &count)) {
177 fileOwnerList = NULL;
179 headerGetEntry(h, RPMTAG_FILEGROUPNAME, &type,
180 (void **) &fileGroupList, &count);
183 for (i = 0; i < count; i++) {
184 if (!((queryFlags & QUERY_FOR_DOCS) ||
185 (queryFlags & QUERY_FOR_CONFIG))
186 || ((queryFlags & QUERY_FOR_DOCS) &&
187 (fileFlagsList[i] & RPMFILE_DOC))
188 || ((queryFlags & QUERY_FOR_CONFIG) &&
189 (fileFlagsList[i] & RPMFILE_CONFIG))) {
192 prefix ? fputs(prefix, stdout) : 0;
194 if (queryFlags & QUERY_FOR_STATE) {
195 if (fileStatesList) {
196 switch (fileStatesList[i]) {
197 case RPMFILE_STATE_NORMAL:
198 fputs(_("normal "), stdout); break;
199 case RPMFILE_STATE_REPLACED:
200 fputs(_("replaced "), stdout); break;
201 case RPMFILE_STATE_NETSHARED:
202 fputs(_("net shared "), stdout); break;
203 case RPMFILE_STATE_NOTINSTALLED:
204 fputs(_("not installed "), stdout); break;
206 fprintf(stdout, _("(unknown %3d) "),
210 fputs( _("(no state) "), stdout);
214 if (queryFlags & QUERY_FOR_DUMPFILES) {
215 fprintf(stdout, "%s %d %d %s 0%o ", fileList[i],
216 fileSizeList[i], fileMTimeList[i],
217 fileMD5List[i], fileModeList[i]);
220 fprintf(stdout, "%s %s", fileOwnerList[i],
222 else if (fileUIDList)
223 fprintf(stdout, "%d %d", fileUIDList[i],
226 rpmError(RPMERR_INTERNAL, _("package has "
227 "neither file owner or id lists"));
230 fprintf(stdout, " %s %s %u ",
231 fileFlagsList[i] & RPMFILE_CONFIG ? "1" : "0",
232 fileFlagsList[i] & RPMFILE_DOC ? "1" : "0",
233 (unsigned)fileRdevList[i]);
235 if (strlen(fileLinktoList[i]))
236 fprintf(stdout, "%s\n", fileLinktoList[i]);
238 fprintf(stdout, "X\n");
240 } else if (!rpmIsVerbose()) {
241 fputs(fileList[i], stdout);
243 } else if (fileOwnerList)
244 printFileInfo(fileList[i], fileSizeList[i],
245 fileModeList[i], fileMTimeList[i],
246 fileRdevList[i], fileOwnerList[i],
247 fileGroupList[i], -1,
248 -1, fileLinktoList[i]);
249 else if (fileUIDList) {
250 printFileInfo(fileList[i], fileSizeList[i],
251 fileModeList[i], fileMTimeList[i],
252 fileRdevList[i], NULL,
253 NULL, fileUIDList[i],
254 fileGIDList[i], fileLinktoList[i]);
256 rpmError(RPMERR_INTERNAL, _("package has "
257 "neither file owner or id lists"));
263 free(fileLinktoList);
265 if (fileOwnerList) free(fileOwnerList);
266 if (fileGroupList) free(fileGroupList);
272 static char * permsString(int mode) {
273 static char perms[11];
275 strcpy(perms, "----------");
277 if (mode & S_IRUSR) perms[1] = 'r';
278 if (mode & S_IWUSR) perms[2] = 'w';
279 if (mode & S_IXUSR) perms[3] = 'x';
281 if (mode & S_IRGRP) perms[4] = 'r';
282 if (mode & S_IWGRP) perms[5] = 'w';
283 if (mode & S_IXGRP) perms[6] = 'x';
285 if (mode & S_IROTH) perms[7] = 'r';
286 if (mode & S_IWOTH) perms[8] = 'w';
287 if (mode & S_IXOTH) perms[9] = 'x';
291 perms[9] = ((mode & S_IXOTH) ? 't' : 'T');
293 if (mode & S_ISUID) {
300 if (mode & S_ISGID) {
309 else if (S_ISLNK(mode)) {
312 else if (S_ISFIFO(mode))
314 else if (S_ISSOCK(mode))
316 else if (S_ISCHR(mode)) {
318 } else if (S_ISBLK(mode)) {
325 static void printFileInfo(char * name, unsigned int size, unsigned short mode,
326 unsigned int mtime, unsigned short rdev,
327 char * owner, char * group, int uid, int gid,
330 char ownerfield[9], groupfield[9];
331 char timefield[100] = "";
334 static int thisYear = 0;
335 static int thisMonth = 0;
337 char * namefield = name;
340 perms = permsString(mode);
343 currenttime = time(NULL);
344 tstruct = localtime(¤ttime);
345 thisYear = tstruct->tm_year;
346 thisMonth = tstruct->tm_mon;
349 ownerfield[8] = groupfield[8] = '\0';
352 strncpy(ownerfield, owner, 8);
354 sprintf(ownerfield, "%-8d", uid);
357 strncpy(groupfield, group, 8);
359 sprintf(groupfield, "%-8d", gid);
361 /* this is normally right */
362 sprintf(sizefield, "%10u", size);
364 /* this knows too much about dev_t */
367 namefield = alloca(strlen(name) + strlen(linkto) + 10);
368 sprintf(namefield, "%s -> %s", name, linkto);
369 } else if (S_ISCHR(mode)) {
371 sprintf(sizefield, "%3u, %3u", (rdev >> 8) & 0xff, rdev & 0xFF);
372 } else if (S_ISBLK(mode)) {
374 sprintf(sizefield, "%3u, %3u", (rdev >> 8) & 0xff, rdev & 0xFF);
377 /* this is important if sizeof(int_32) ! sizeof(time_t) */
379 tstruct = localtime(&themtime);
381 if (tstruct->tm_year == thisYear ||
382 ((tstruct->tm_year + 1) == thisYear && tstruct->tm_mon > thisMonth))
383 (void)strftime(timefield, sizeof(timefield) - 1, "%b %d %H:%M",tstruct);
385 (void)strftime(timefield, sizeof(timefield) - 1, "%b %d %Y", tstruct);
387 fprintf(stdout, "%s %8s %8s %10s %s %s\n", perms, ownerfield, groupfield,
388 sizefield, timefield, namefield);
391 static void showMatches(rpmdb db, dbiIndexSet matches, int queryFlags,
392 char * queryFormat) {
396 for (i = 0; i < matches.count; i++) {
397 if (matches.recs[i].recOffset) {
398 rpmMessage(RPMMESS_DEBUG, _("querying record number %d\n"),
399 matches.recs[i].recOffset);
401 h = rpmdbGetRecord(db, matches.recs[i].recOffset);
403 fprintf(stderr, _("error: could not read database record\n"));
405 printHeader(h, queryFlags, queryFormat);
412 int rpmQuery(char * prefix, enum rpmQuerySources source, int queryFlags,
413 char * arg, char * queryFormat) {
424 struct urlContext context;
428 if (source != QUERY_RPM) {
429 if (rpmdbOpen(prefix, &db, O_RDONLY, 0644)) {
438 if ((fd = urlGetFd(arg, &context)) < 0) {
439 fprintf(stderr, _("open of %s failed: %s\n"), arg,
442 } else if (!strcmp(arg, "-")) {
445 if ((fd = open(arg, O_RDONLY)) < 0) {
446 fprintf(stderr, _("open of %s failed: %s\n"), arg,
452 rc = rpmReadPackageHeader(fd, &h, &isSource, NULL, NULL);
456 urlFinishedFd(&context);
462 fprintf(stderr, _("old format source packages cannot "
465 printHeader(h, queryFlags, queryFormat);
471 _("%s does not appear to be a RPM package\n"),
475 fprintf(stderr, _("query of %s failed\n"), arg);
484 offset = rpmdbFirstRecNum(db);
486 h = rpmdbGetRecord(db, offset);
488 fprintf(stderr, _("could not read database record!\n"));
491 printHeader(h, queryFlags, queryFormat);
493 offset = rpmdbNextRecNum(db, offset);
498 if (rpmdbFindByGroup(db, arg, &matches)) {
499 fprintf(stderr, _("group %s does not contain any packages\n"), arg);
502 showMatches(db, matches, queryFlags, queryFormat);
503 dbiFreeIndexRecord(matches);
507 case QUERY_WHATPROVIDES:
508 if (rpmdbFindByProvides(db, arg, &matches)) {
509 fprintf(stderr, _("no package provides %s\n"), arg);
512 showMatches(db, matches, queryFlags, queryFormat);
513 dbiFreeIndexRecord(matches);
517 case QUERY_TRIGGEREDBY:
518 if (rpmdbFindByTriggeredBy(db, arg, &matches)) {
519 fprintf(stderr, _("no package triggers %s\n"), arg);
522 showMatches(db, matches, queryFlags, queryFormat);
523 dbiFreeIndexRecord(matches);
527 case QUERY_WHATREQUIRES:
528 if (rpmdbFindByRequiredBy(db, arg, &matches)) {
529 fprintf(stderr, _("no package requires %s\n"), arg);
532 showMatches(db, matches, queryFlags, queryFormat);
533 dbiFreeIndexRecord(matches);
539 /* Using realpath on the arg isn't correct if the arg is a symlink,
540 * especially if the symlink is a dangling link. What we should
541 * instead do is use realpath() on `.' and then append arg to
544 if (realpath(".", path) != NULL) {
545 if (path[strlen(path)] != '/') {
546 if (strncat(path, "/", PATH_MAX - strlen(path) - 1) == NULL) {
547 fprintf(stderr, _("maximum path length exceeded\n"));
551 /* now append the original file name to the real path */
552 if (strncat(path, arg, PATH_MAX - strlen(path) - 1) == NULL) {
553 fprintf(stderr, _("maximum path length exceeded\n"));
559 if (rpmdbFindByFile(db, arg, &matches)) {
561 if (access(arg, F_OK) != 0)
565 fprintf(stderr, _("file %s: %s\n"), arg, strerror(myerrno));
568 fprintf(stderr, _("file %s is not owned by any package\n"), arg);
573 showMatches(db, matches, queryFlags, queryFormat);
574 dbiFreeIndexRecord(matches);
579 recNumber = strtoul(arg, &end, 10);
580 if ((*end) || (end == arg) || (recNumber == ULONG_MAX)) {
581 fprintf(stderr, _("invalid package number: %s\n"), arg);
584 rpmMessage(RPMMESS_DEBUG, _("showing package: %d\n"), recNumber);
585 h = rpmdbGetRecord(db, recNumber);
587 fprintf(stderr, _("record %d could not be read\n"), recNumber);
590 printHeader(h, queryFlags, queryFormat);
596 rc = rpmdbFindByLabel(db, arg, &matches);
599 fprintf(stderr, _("package %s is not installed\n"), arg);
600 } else if (rc == 2) {
602 fprintf(stderr, _("error looking for package %s\n"), arg);
604 showMatches(db, matches, queryFlags, queryFormat);
605 dbiFreeIndexRecord(matches);
610 if (source != QUERY_RPM) {
617 void rpmDisplayQueryTags(FILE * f) {
618 const struct headerTagTableEntry * t;
620 const struct headerSprintfExtension * ext = rpmHeaderFormats;
622 for (i = 0, t = rpmTagTable; i < rpmTagTableSize; i++, t++) {
623 fprintf(f, "%s\n", t->name + 7);
627 if (ext->type == HEADER_EXT_TAG)
628 fprintf(f, "%s\n", ext->name + 7), ext++;
629 else if (ext->type == HEADER_EXT_MORE)