11 #include <sys/param.h>
18 #include "lib/messages.h"
24 static char * permsString(int mode);
25 static void printHeader(Header h, int queryFlags, char * queryFormat);
26 static int queryPartial(Header h, char ** chptrptr, int * cntptr,
28 static int queryHeader(Header h, char * chptr);
29 static int queryArray(Header h, char ** chptrptr);
30 static void escapedChar(char ch);
31 static char * handleFormat(Header h, char * chptr, int * count, int arrayNum);
32 static void showMatches(rpmdb db, dbiIndexSet matches, int queryFlags,
34 static int findMatches(rpmdb db, char * name, char * version, char * release,
35 dbiIndexSet * matches);
36 static void printFileInfo(char * name, unsigned int size, unsigned short mode,
37 unsigned int mtime, unsigned short rdev,
38 char * owner, char * group, int uid, int gid,
41 static int queryHeader(Header h, char * chptr) {
44 return queryPartial(h, &chptr, &count, -1);
47 static int queryArray(Header h, char ** chptrptr) {
54 if (queryPartial(h, chptrptr, &count, 0)) return 1;
57 while (arrayNum < count) {
59 if (queryPartial(h, chptrptr, &count, arrayNum++)) return 1;
65 static int queryPartial(Header h, char ** chptrptr, int * cntptr,
67 char * chptr = *chptrptr;
71 while (chptr && *chptr) {
75 if (!*chptr) return 1;
76 escapedChar(*chptr++);
81 if (!*chptr) return 1;
87 chptr = handleFormat(h, chptr, &count, arrayNum);
91 } else if (count != -1 && !*cntptr && !emptyItem){
93 } else if (count != -1 && *cntptr && count != *cntptr) {
94 fprintf(stderr, "(parallel array size mismatch)");
100 if (arrayNum == -1) {
101 printf("(unexpected ']')");
104 *chptrptr = chptr + 1;
108 if (arrayNum != -1) {
109 printf("(unexpected ']')");
112 *chptrptr = chptr + 1;
113 if (queryArray(h, chptrptr)) {
129 static char * handleFormat(Header h, char * chptr, int * cntptr,
131 const char * f = chptr;
134 char how[20], format[20];
137 const struct headerTagTableEntry * t;
149 while (*chptr && *chptr != '{') chptr++;
150 if (!*chptr || (chptr - f > (sizeof(format) - 3))) {
151 fprintf(stderr, "bad query format - %s\n", f);
155 strncat(format, f, chptr - f);
158 while (*chptr && *chptr != '}' && *chptr != ':' ) chptr++;
159 if (tagptr == chptr || !*chptr) {
160 fprintf(stderr, "bad query format - %s\n", f);
166 while (*end && *end != '}') end++;
169 fprintf(stderr, "bad query format - %s\n", f);
172 if ((end - chptr + 1) > sizeof(how)) {
173 fprintf(stderr, "bad query format - %s\n", f);
176 strncpy(how, chptr + 1, end - chptr - 1);
177 how[end - chptr - 1] = '\0';
184 case '=': notArray = 1, tagptr++; break;
185 case '#': showCount = 1, tagptr++; break;
188 tagLength = chptr - tagptr;
191 if (tagLength > (sizeof(tag) - 20)) {
192 fprintf(stderr, "query tag too long\n");
195 memset(tag, 0, sizeof(tag));
196 if (strncmp(tagptr, "RPMTAG_", 7)) {
197 strcpy(tag, "RPMTAG_");
199 strncat(tag, tagptr, tagLength);
201 for (i = 0, t = rpmTagTable; i < rpmTagTableSize; i++, t++) {
202 if (!strcasecmp(tag, t->name)) break;
205 if (i == rpmTagTableSize) {
206 fprintf(stderr, "unknown tag %s\n", tag);
210 if (!headerGetEntry(h, t->val, &type, &p, &count) || !p) {
213 type = RPM_STRING_TYPE;
214 } else if (notArray) {
216 } else if (showCount) {
219 type = RPM_INT32_TYPE;
221 } else if (count > 1 && (arrayNum == -1)) {
224 type = RPM_STRING_TYPE;
225 } else if ((count - 1) < arrayNum && arrayNum != -1) {
226 p = "(past array end)";
228 type = RPM_STRING_TYPE;
229 } else if (arrayNum != -1)
232 if (arrayNum == -1) arrayNum = 0;
235 case RPM_STRING_ARRAY_TYPE:
237 printf(format, ((char **) p)[arrayNum]);
241 case RPM_STRING_TYPE:
249 printf(format, *(((int_8 *) p) + arrayNum));
253 if (!strcmp(how, "perms") || !strcmp(how, "permissions")) {
255 printf(format, permsString(*(((int_16 *) p) + arrayNum)));
256 } else if (!strcmp(how, "octal")) {
257 strcat(format, "#o");
258 printf(format, *(((int_16 *) p) + arrayNum) & 0xFFFF);
261 printf(format, *(((int_16 *) p) + arrayNum));
266 if (!strcmp(how, "date")) {
268 /* this is important if sizeof(int_32) ! sizeof(time_t) */
269 dateint = *(((int_32 *) p) + arrayNum);
270 tstruct = localtime(&dateint);
271 strftime(buf, sizeof(buf) - 1, "%c", tstruct);
273 } else if (!strcmp(how, "fflags")) {
276 anint = *(((int_32 *) p) + arrayNum);
277 if (anint & RPMFILE_DOC)
279 if (anint & RPMFILE_CONFIG)
282 } else if (!strcmp(how, "octal")) {
283 strcat(format, "#o");
284 printf(format, *(((int_32 *) p) + arrayNum));
285 } else if (!strcmp(how, "perms") || !strcmp(how, "permissions")) {
287 printf(format, permsString(*(((int_32 *) p) + arrayNum)));
288 } else if (!strcmp(how, "depflags")) {
290 anint = *(((int_32 *) p) + arrayNum);
291 if (anint & RPMSENSE_LESS)
293 if (anint & RPMSENSE_GREATER)
295 if (anint & RPMSENSE_EQUAL)
297 if (anint & RPMSENSE_SERIAL)
304 printf(format, *(((int_32 *) p) + arrayNum));
309 printf("(can't handle type %d)", type);
316 static void escapedChar(const char ch) {
318 case 'a': putchar('\a'); break;
319 case 'b': putchar('\b'); break;
320 case 'f': putchar('\f'); break;
321 case 'n': putchar('\n'); break;
322 case 'r': putchar('\r'); break;
323 case 't': putchar('\t'); break;
324 case 'v': putchar('\v'); break;
326 default: putchar(ch); break;
330 static void printHeader(Header h, int queryFlags, char * queryFormat) {
331 char * name, * version, * release;
333 char * prefix = NULL;
334 char ** fileList, ** fileMD5List;
335 char * fileStatesList;
336 char ** fileOwnerList = NULL;
337 char ** fileGroupList = NULL;
338 char ** fileLinktoList;
339 int_32 * fileFlagsList, * fileMTimeList, * fileSizeList;
340 int_32 * fileUIDList, * fileGIDList;
341 uint_16 * fileModeList;
342 uint_16 * fileRdevList;
345 headerGetEntry(h, RPMTAG_NAME, &type, (void **) &name, &count);
346 headerGetEntry(h, RPMTAG_VERSION, &type, (void **) &version, &count);
347 headerGetEntry(h, RPMTAG_RELEASE, &type, (void **) &release, &count);
349 if (!queryFormat && !queryFlags) {
350 printf("%s-%s-%s\n", name, version, release);
353 queryHeader(h, queryFormat);
355 if (queryFlags & QUERY_FOR_LIST) {
356 if (!headerGetEntry(h, RPMTAG_FILENAMES, &type, (void **) &fileList,
358 puts("(contains no files)");
360 if (!headerGetEntry(h, RPMTAG_FILESTATES, &type,
361 (void **) &fileStatesList, &count)) {
362 fileStatesList = NULL;
364 headerGetEntry(h, RPMTAG_FILEFLAGS, &type,
365 (void **) &fileFlagsList, &count);
366 headerGetEntry(h, RPMTAG_FILESIZES, &type,
367 (void **) &fileSizeList, &count);
368 headerGetEntry(h, RPMTAG_FILEMODES, &type,
369 (void **) &fileModeList, &count);
370 headerGetEntry(h, RPMTAG_FILEMTIMES, &type,
371 (void **) &fileMTimeList, &count);
372 headerGetEntry(h, RPMTAG_FILERDEVS, &type,
373 (void **) &fileRdevList, &count);
374 headerGetEntry(h, RPMTAG_FILELINKTOS, &type,
375 (void **) &fileLinktoList, &count);
376 headerGetEntry(h, RPMTAG_FILEMD5S, &type,
377 (void **) &fileMD5List, &count);
379 if (!headerGetEntry(h, RPMTAG_FILEUIDS, &type,
380 (void **) &fileUIDList, &count)) {
383 headerGetEntry(h, RPMTAG_FILEGIDS, &type,
384 (void **) &fileGIDList, &count);
387 if (!headerGetEntry(h, RPMTAG_FILEUSERNAME, &type,
388 (void **) &fileOwnerList, &count)) {
389 fileOwnerList = NULL;
391 headerGetEntry(h, RPMTAG_FILEGROUPNAME, &type,
392 (void **) &fileGroupList, &count);
395 for (i = 0; i < count; i++) {
396 if (!((queryFlags & QUERY_FOR_DOCS) ||
397 (queryFlags & QUERY_FOR_CONFIG))
398 || ((queryFlags & QUERY_FOR_DOCS) &&
399 (fileFlagsList[i] & RPMFILE_DOC))
400 || ((queryFlags & QUERY_FOR_CONFIG) &&
401 (fileFlagsList[i] & RPMFILE_CONFIG))) {
404 prefix ? fputs(prefix, stdout) : 0;
406 if (queryFlags & QUERY_FOR_STATE) {
407 if (fileStatesList) {
408 switch (fileStatesList[i]) {
409 case RPMFILE_STATE_NORMAL:
410 fputs("normal ", stdout); break;
411 case RPMFILE_STATE_REPLACED:
412 fputs("replaced ", stdout); break;
413 case RPMFILE_STATE_NETSHARED:
414 fputs("net shared ", stdout); break;
415 case RPMFILE_STATE_NOTINSTALLED:
416 fputs("not installed ", stdout); break;
418 printf("(unknown %3d) ",
422 fputs( "(no state) ", stdout);
426 if (queryFlags & QUERY_FOR_DUMPFILES) {
427 printf("%s %d %d %s 0%o ", fileList[i],
428 fileSizeList[i], fileMTimeList[i],
429 fileMD5List[i], fileModeList[i]);
432 printf("%s %s", fileOwnerList[i],
434 else if (fileUIDList)
435 printf("%d %d", fileUIDList[i],
438 rpmError(RPMERR_INTERNAL, "package has "
439 "neither file owner or id lists");
443 fileFlagsList[i] & RPMFILE_CONFIG ? "1" : "0",
444 fileFlagsList[i] & RPMFILE_DOC ? "1" : "0",
447 if (strlen(fileLinktoList[i]))
448 printf("%s\n", fileLinktoList[i]);
452 } else if (!rpmIsVerbose()) {
454 } else if (fileOwnerList)
455 printFileInfo(fileList[i], fileSizeList[i],
456 fileModeList[i], fileMTimeList[i],
457 fileRdevList[i], fileOwnerList[i],
458 fileGroupList[i], -1,
459 -1, fileLinktoList[i]);
460 else if (fileUIDList) {
461 printFileInfo(fileList[i], fileSizeList[i],
462 fileModeList[i], fileMTimeList[i],
463 fileRdevList[i], NULL,
464 NULL, fileUIDList[i],
465 fileGIDList[i], fileLinktoList[i]);
467 rpmError(RPMERR_INTERNAL, "package has "
468 "neither file owner or id lists");
474 free(fileLinktoList);
476 if (fileOwnerList) free(fileOwnerList);
477 if (fileGroupList) free(fileGroupList);
483 static char * permsString(int mode) {
484 static char perms[11];
486 strcpy(perms, "-----------");
488 if (mode & S_ISVTX) perms[10] = 't';
490 if (mode & S_IRUSR) perms[1] = 'r';
491 if (mode & S_IWUSR) perms[2] = 'w';
492 if (mode & S_IXUSR) perms[3] = 'x';
494 if (mode & S_IRGRP) perms[4] = 'r';
495 if (mode & S_IWGRP) perms[5] = 'w';
496 if (mode & S_IXGRP) perms[6] = 'x';
498 if (mode & S_IROTH) perms[7] = 'r';
499 if (mode & S_IWOTH) perms[8] = 'w';
500 if (mode & S_IXOTH) perms[9] = 'x';
502 if (mode & S_ISUID) {
509 if (mode & S_ISGID) {
518 else if (S_ISLNK(mode)) {
521 else if (S_ISFIFO(mode))
523 else if (S_ISSOCK(mode))
525 else if (S_ISCHR(mode)) {
527 } else if (S_ISBLK(mode)) {
534 static void printFileInfo(char * name, unsigned int size, unsigned short mode,
535 unsigned int mtime, unsigned short rdev,
536 char * owner, char * group, int uid, int gid,
539 char ownerfield[9], groupfield[9];
540 char timefield[100] = "";
543 static int thisYear = 0;
544 static int thisMonth = 0;
546 char * namefield = name;
549 perms = permsString(mode);
552 currenttime = time(NULL);
553 tstruct = localtime(¤ttime);
554 thisYear = tstruct->tm_year;
555 thisMonth = tstruct->tm_mon;
559 strncpy(ownerfield, owner, 8);
561 sprintf(ownerfield, "%-8d", uid);
564 strncpy(groupfield, group, 8);
566 sprintf(groupfield, "%-8d", gid);
568 /* this is normally right */
569 sprintf(sizefield, "%10d", size);
571 /* this knows too much about dev_t */
574 namefield = alloca(strlen(name) + strlen(linkto) + 10);
575 sprintf(namefield, "%s -> %s", name, linkto);
576 } else if (S_ISCHR(mode)) {
578 sprintf(sizefield, "%3d, %3d", rdev >> 8, rdev & 0xFF);
579 } else if (S_ISBLK(mode)) {
581 sprintf(sizefield, "%3d, %3d", rdev >> 8, rdev & 0xFF);
584 /* this is important if sizeof(int_32) ! sizeof(time_t) */
586 tstruct = localtime(&themtime);
588 if (tstruct->tm_year == thisYear ||
589 ((tstruct->tm_year + 1) == thisYear && tstruct->tm_mon > thisMonth))
590 strftime(timefield, sizeof(timefield) - 1, "%b %d %H:%M", tstruct);
592 strftime(timefield, sizeof(timefield) - 1, "%b %d %Y", tstruct);
594 printf("%s %8s %8s %10s %s %s\n", perms, ownerfield, groupfield,
595 sizefield, timefield, namefield);
598 static void showMatches(rpmdb db, dbiIndexSet matches, int queryFlags,
599 char * queryFormat) {
603 for (i = 0; i < matches.count; i++) {
604 if (matches.recs[i].recOffset) {
605 rpmMessage(RPMMESS_DEBUG, "querying record number %d\n",
606 matches.recs[i].recOffset);
608 h = rpmdbGetRecord(db, matches.recs[i].recOffset);
610 fprintf(stderr, "error: could not read database record\n");
612 printHeader(h, queryFlags, queryFormat);
619 int doQuery(char * prefix, enum querysources source, int queryFlags,
620 char * arg, char * queryFormat) {
631 struct urlContext context;
635 if (source != QUERY_RPM) {
636 if (rpmdbOpen(prefix, &db, O_RDONLY, 0644)) {
645 if ((fd = urlGetFd(arg, &context)) < 0) {
646 fprintf(stderr, "open of %s failed: %s\n", arg,
649 } else if (!strcmp(arg, "-")) {
652 if ((fd = open(arg, O_RDONLY)) < 0) {
653 fprintf(stderr, "open of %s failed: %s\n", arg,
659 rc = rpmReadPackageHeader(fd, &h, &isSource, NULL, NULL);
663 urlFinishedFd(&context);
669 fprintf(stderr, "old format source packages cannot be "
672 printHeader(h, queryFlags, queryFormat);
677 fprintf(stderr, "%s does not appear to be a RPM package\n",
681 fprintf(stderr, "query of %s failed\n", arg);
690 offset = rpmdbFirstRecNum(db);
692 h = rpmdbGetRecord(db, offset);
694 fprintf(stderr, "could not read database record!\n");
697 printHeader(h, queryFlags, queryFormat);
699 offset = rpmdbNextRecNum(db, offset);
704 if (rpmdbFindByGroup(db, arg, &matches)) {
705 fprintf(stderr, "group %s does not contain any packages\n", arg);
708 showMatches(db, matches, queryFlags, queryFormat);
709 dbiFreeIndexRecord(matches);
713 case QUERY_WHATPROVIDES:
714 if (rpmdbFindByProvides(db, arg, &matches)) {
715 fprintf(stderr, "no package provides %s\n", arg);
718 showMatches(db, matches, queryFlags, queryFormat);
719 dbiFreeIndexRecord(matches);
723 case QUERY_WHATREQUIRES:
724 if (rpmdbFindByRequiredBy(db, arg, &matches)) {
725 fprintf(stderr, "no package requires %s\n", arg);
728 showMatches(db, matches, queryFlags, queryFormat);
729 dbiFreeIndexRecord(matches);
735 if (realpath(arg, path) != NULL)
738 if (rpmdbFindByFile(db, arg, &matches)) {
739 fprintf(stderr, "file %s is not owned by any package\n", arg);
742 showMatches(db, matches, queryFlags, queryFormat);
743 dbiFreeIndexRecord(matches);
748 recNumber = strtoul(arg, &end, 10);
749 if ((*end) || (end == arg) || (recNumber == ULONG_MAX)) {
750 fprintf(stderr, "invalid package number: %s\n", arg);
753 rpmMessage(RPMMESS_DEBUG, "showing package: %d\n", recNumber);
754 h = rpmdbGetRecord(db, recNumber);
757 fprintf(stderr, "record %d could not be read\n", recNumber);
760 printHeader(h, queryFlags, queryFormat);
766 rc = findPackageByLabel(db, arg, &matches);
769 fprintf(stderr, "package %s is not installed\n", arg);
770 } else if (rc == 2) {
772 fprintf(stderr, "error looking for package %s\n", arg);
774 showMatches(db, matches, queryFlags, queryFormat);
775 dbiFreeIndexRecord(matches);
780 if (source != QUERY_RPM) {
787 /* 0 found matches */
790 int findPackageByLabel(rpmdb db, char * arg, dbiIndexSet * matches) {
791 char * localarg, * chptr;
795 if (!strlen(arg)) return 1;
797 /* did they give us just a name? */
798 rc = findMatches(db, arg, NULL, NULL, matches);
799 if (rc != 1) return rc;
801 /* maybe a name and a release */
802 localarg = alloca(strlen(arg) + 1);
803 strcpy(localarg, arg);
805 chptr = (localarg + strlen(localarg)) - 1;
806 while (chptr > localarg && *chptr != '-') chptr--;
807 if (chptr == localarg) return 1;
810 rc = findMatches(db, localarg, chptr + 1, NULL, matches);
811 if (rc != 1) return rc;
813 /* how about name-version-release? */
816 while (chptr > localarg && *chptr != '-') chptr--;
817 if (chptr == localarg) return 1;
820 return findMatches(db, localarg, chptr + 1, release, matches);
823 /* 0 found matches */
826 int findMatches(rpmdb db, char * name, char * version, char * release,
827 dbiIndexSet * matches) {
831 char * pkgRelease, * pkgVersion;
833 int goodRelease, goodVersion;
836 if ((rc = rpmdbFindPackage(db, name, matches))) {
837 if (rc == -1) return 2; else return 1;
840 if (!version && !release) return 0;
844 /* make sure the version and releases match */
845 for (i = 0; i < matches->count; i++) {
846 if (matches->recs[i].recOffset) {
847 h = rpmdbGetRecord(db, matches->recs[i].recOffset);
849 fprintf(stderr, "error: could not read database record\n");
850 dbiFreeIndexRecord(*matches);
854 headerGetEntry(h, RPMTAG_VERSION, &type, (void **) &pkgVersion, &count);
855 headerGetEntry(h, RPMTAG_RELEASE, &type, (void **) &pkgRelease, &count);
857 goodRelease = goodVersion = 1;
859 if (release && strcmp(release, pkgRelease)) goodRelease = 0;
860 if (version && strcmp(version, pkgVersion)) goodVersion = 0;
862 if (goodRelease && goodVersion)
865 matches->recs[i].recOffset = 0;
870 dbiFreeIndexRecord(*matches);
877 void queryPrintTags(void) {
878 const struct headerTagTableEntry * t;
881 for (i = 0, t = rpmTagTable; i < rpmTagTableSize; i++, t++) {
882 printf("%s\n", t->name);