home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 February / CHIP_2_98.iso / misc / src / rpm / query.c < prev    next >
C/C++ Source or Header  |  1997-09-17  |  13KB  |  517 lines

  1. #include "config.h"
  2.  
  3. #include <ctype.h>
  4. #include <errno.h>
  5. #include <fcntl.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <sys/stat.h>
  10. #include <time.h>
  11. #include <sys/param.h>
  12. #include <unistd.h>
  13.  
  14. #if HAVE_ALLOCA_H
  15. # include <alloca.h>
  16. #endif
  17.  
  18. #include "intl.h"
  19. #include "lib/messages.h"
  20. #include "miscfn.h"
  21. #include "rpmlib.h"
  22. #include "query.h"
  23. #include "url.h"
  24.  
  25. static char * permsString(int mode);
  26. static void printHeader(Header h, int queryFlags, char * queryFormat);
  27. static void showMatches(rpmdb db, dbiIndexSet matches, int queryFlags, 
  28.             char * queryFormat);
  29. static void printFileInfo(char * name, unsigned int size, unsigned short mode,
  30.               unsigned int mtime, unsigned short rdev,
  31.               char * owner, char * group, int uid, int gid,
  32.               char * linkto);
  33.  
  34. static int queryHeader(Header h, char * chptr) {
  35.     char * str;
  36.     char * error;
  37.  
  38.     str = headerSprintf(h, chptr, rpmTagTable, rpmHeaderFormats, &error);
  39.     if (!str) {
  40.     fprintf(stderr, "error in format: %s\n", error);
  41.     return 1;
  42.     }
  43.  
  44.     fputs(str, stdout);
  45.  
  46.     return 0;
  47. }
  48.  
  49. static void printHeader(Header h, int queryFlags, char * queryFormat) {
  50.     char * name, * version, * release;
  51.     int_32 count, type;
  52.     char * prefix = NULL;
  53.     char ** fileList, ** fileMD5List;
  54.     char * fileStatesList;
  55.     char ** fileOwnerList = NULL;
  56.     char ** fileGroupList = NULL;
  57.     char ** fileLinktoList;
  58.     int_32 * fileFlagsList, * fileMTimeList, * fileSizeList;
  59.     int_32 * fileUIDList, * fileGIDList;
  60.     uint_16 * fileModeList;
  61.     uint_16 * fileRdevList;
  62.     int i;
  63.  
  64.     headerGetEntry(h, RPMTAG_NAME, &type, (void **) &name, &count);
  65.     headerGetEntry(h, RPMTAG_VERSION, &type, (void **) &version, &count);
  66.     headerGetEntry(h, RPMTAG_RELEASE, &type, (void **) &release, &count);
  67.  
  68.     if (!queryFormat && !queryFlags) {
  69.     printf("%s-%s-%s\n", name, version, release);
  70.     } else {
  71.     if (queryFormat)
  72.         queryHeader(h, queryFormat);
  73.  
  74.     if (queryFlags & QUERY_FOR_LIST) {
  75.         if (!headerGetEntry(h, RPMTAG_FILENAMES, &type, (void **) &fileList, 
  76.          &count)) {
  77.         puts(_("(contains no files)"));
  78.         } else {
  79.         if (!headerGetEntry(h, RPMTAG_FILESTATES, &type, 
  80.              (void **) &fileStatesList, &count)) {
  81.             fileStatesList = NULL;
  82.         }
  83.         headerGetEntry(h, RPMTAG_FILEFLAGS, &type, 
  84.              (void **) &fileFlagsList, &count);
  85.         headerGetEntry(h, RPMTAG_FILESIZES, &type, 
  86.              (void **) &fileSizeList, &count);
  87.         headerGetEntry(h, RPMTAG_FILEMODES, &type, 
  88.              (void **) &fileModeList, &count);
  89.         headerGetEntry(h, RPMTAG_FILEMTIMES, &type, 
  90.              (void **) &fileMTimeList, &count);
  91.         headerGetEntry(h, RPMTAG_FILERDEVS, &type, 
  92.              (void **) &fileRdevList, &count);
  93.         headerGetEntry(h, RPMTAG_FILELINKTOS, &type, 
  94.              (void **) &fileLinktoList, &count);
  95.         headerGetEntry(h, RPMTAG_FILEMD5S, &type, 
  96.              (void **) &fileMD5List, &count);
  97.  
  98.         if (!headerGetEntry(h, RPMTAG_FILEUIDS, &type, 
  99.              (void **) &fileUIDList, &count)) {
  100.             fileUIDList = NULL;
  101.         } else {
  102.             headerGetEntry(h, RPMTAG_FILEGIDS, &type, 
  103.                  (void **) &fileGIDList, &count);
  104.         }
  105.  
  106.         if (!headerGetEntry(h, RPMTAG_FILEUSERNAME, &type, 
  107.              (void **) &fileOwnerList, &count)) {
  108.             fileOwnerList = NULL;
  109.         } else {
  110.             headerGetEntry(h, RPMTAG_FILEGROUPNAME, &type, 
  111.                  (void **) &fileGroupList, &count);
  112.         }
  113.  
  114.         for (i = 0; i < count; i++) {
  115.             if (!((queryFlags & QUERY_FOR_DOCS) || 
  116.               (queryFlags & QUERY_FOR_CONFIG)) 
  117.             || ((queryFlags & QUERY_FOR_DOCS) && 
  118.                 (fileFlagsList[i] & RPMFILE_DOC))
  119.             || ((queryFlags & QUERY_FOR_CONFIG) && 
  120.                 (fileFlagsList[i] & RPMFILE_CONFIG))) {
  121.  
  122.             if (!rpmIsVerbose())
  123.                 prefix ? fputs(prefix, stdout) : 0;
  124.  
  125.             if (queryFlags & QUERY_FOR_STATE) {
  126.                 if (fileStatesList) {
  127.                 switch (fileStatesList[i]) {
  128.                   case RPMFILE_STATE_NORMAL:
  129.                     fputs("normal        ", stdout); break;
  130.                   case RPMFILE_STATE_REPLACED:
  131.                     fputs("replaced      ", stdout); break;
  132.                   case RPMFILE_STATE_NETSHARED:
  133.                     fputs("net shared    ", stdout); break;
  134.                   case RPMFILE_STATE_NOTINSTALLED:
  135.                     fputs("not installed ", stdout); break;
  136.                   default:
  137.                     printf("(unknown %3d) ", 
  138.                       fileStatesList[i]);
  139.                 }
  140.                 } else {
  141.                 fputs(    "(no state)    ", stdout);
  142.                 }
  143.             }
  144.                 
  145.             if (queryFlags & QUERY_FOR_DUMPFILES) {
  146.                 printf("%s %d %d %s 0%o ", fileList[i],
  147.                    fileSizeList[i], fileMTimeList[i],
  148.                    fileMD5List[i], fileModeList[i]);
  149.  
  150.                 if (fileOwnerList)
  151.                 printf("%s %s", fileOwnerList[i], 
  152.                         fileGroupList[i]);
  153.                 else if (fileUIDList)
  154.                 printf("%d %d", fileUIDList[i], 
  155.                         fileGIDList[i]);
  156.                 else {
  157.                 rpmError(RPMERR_INTERNAL, "package has "
  158.                     "neither file owner or id lists");
  159.                 }
  160.  
  161.                 printf(" %s %s %d ", 
  162.                  fileFlagsList[i] & RPMFILE_CONFIG ? "1" : "0",
  163.                  fileFlagsList[i] & RPMFILE_DOC ? "1" : "0",
  164.                  fileRdevList[i]);
  165.  
  166.                 if (strlen(fileLinktoList[i]))
  167.                 printf("%s\n", fileLinktoList[i]);
  168.                 else
  169.                 printf("X\n");
  170.  
  171.             } else if (!rpmIsVerbose()) {
  172.                 puts(fileList[i]);
  173.             } else if (fileOwnerList) 
  174.                 printFileInfo(fileList[i], fileSizeList[i],
  175.                       fileModeList[i], fileMTimeList[i],
  176.                       fileRdevList[i], fileOwnerList[i], 
  177.                       fileGroupList[i], -1, 
  178.                       -1, fileLinktoList[i]);
  179.             else if (fileUIDList) {
  180.                 printFileInfo(fileList[i], fileSizeList[i],
  181.                       fileModeList[i], fileMTimeList[i],
  182.                       fileRdevList[i], NULL, 
  183.                       NULL, fileUIDList[i], 
  184.                       fileGIDList[i], fileLinktoList[i]);
  185.             } else {
  186.                 rpmError(RPMERR_INTERNAL, "package has "
  187.                     "neither file owner or id lists");
  188.             }
  189.             }
  190.         }
  191.         
  192.         free(fileList);
  193.         free(fileLinktoList);
  194.         free(fileMD5List);
  195.         if (fileOwnerList) free(fileOwnerList);
  196.         if (fileGroupList) free(fileGroupList);
  197.         }
  198.     }
  199.     }
  200. }
  201.  
  202. static char * permsString(int mode) {
  203.     static char perms[11];
  204.  
  205.     strcpy(perms, "-----------");
  206.    
  207.     if (mode & S_ISVTX) perms[10] = 't';
  208.  
  209.     if (mode & S_IRUSR) perms[1] = 'r';
  210.     if (mode & S_IWUSR) perms[2] = 'w';
  211.     if (mode & S_IXUSR) perms[3] = 'x';
  212.  
  213.     if (mode & S_IRGRP) perms[4] = 'r';
  214.     if (mode & S_IWGRP) perms[5] = 'w';
  215.     if (mode & S_IXGRP) perms[6] = 'x';
  216.  
  217.     if (mode & S_IROTH) perms[7] = 'r';
  218.     if (mode & S_IWOTH) perms[8] = 'w';
  219.     if (mode & S_IXOTH) perms[9] = 'x';
  220.  
  221.     if (mode & S_ISUID) {
  222.     if (mode & S_IXUSR) 
  223.         perms[3] = 's'; 
  224.     else
  225.         perms[3] = 'S'; 
  226.     }
  227.  
  228.     if (mode & S_ISGID) {
  229.     if (mode & S_IXGRP) 
  230.         perms[6] = 's'; 
  231.     else
  232.         perms[6] = 'S'; 
  233.     }
  234.  
  235.     if (S_ISDIR(mode)) 
  236.     perms[0] = 'd';
  237.     else if (S_ISLNK(mode)) {
  238.     perms[0] = 'l';
  239.     }
  240.     else if (S_ISFIFO(mode)) 
  241.     perms[0] = 'p';
  242.     else if (S_ISSOCK(mode)) 
  243.     perms[0] = 'l';
  244.     else if (S_ISCHR(mode)) {
  245.     perms[0] = 'c';
  246.     } else if (S_ISBLK(mode)) {
  247.     perms[0] = 'b';
  248.     }
  249.  
  250.     return perms;
  251. }
  252.  
  253. static void printFileInfo(char * name, unsigned int size, unsigned short mode,
  254.               unsigned int mtime, unsigned short rdev,
  255.               char * owner, char * group, int uid, int gid,
  256.               char * linkto) {
  257.     char sizefield[15];
  258.     char ownerfield[9], groupfield[9];
  259.     char timefield[100] = "";
  260.     time_t themtime;
  261.     time_t currenttime;
  262.     static int thisYear = 0;
  263.     static int thisMonth = 0;
  264.     struct tm * tstruct;
  265.     char * namefield = name;
  266.     char * perms;
  267.  
  268.     perms = permsString(mode);
  269.  
  270.     if (!thisYear) {
  271.     currenttime = time(NULL);
  272.     tstruct = localtime(¤ttime);
  273.     thisYear = tstruct->tm_year;
  274.     thisMonth = tstruct->tm_mon;
  275.     }
  276.  
  277.     ownerfield[8] = groupfield[8] = '\0';
  278.  
  279.     if (owner) 
  280.     strncpy(ownerfield, owner, 8);
  281.     else
  282.     sprintf(ownerfield, "%-8d", uid);
  283.  
  284.     if (group) 
  285.     strncpy(groupfield, group, 8);
  286.     else 
  287.     sprintf(groupfield, "%-8d", gid);
  288.  
  289.     /* this is normally right */
  290.     sprintf(sizefield, "%10d", size);
  291.  
  292.     /* this knows too much about dev_t */
  293.  
  294.     if (S_ISLNK(mode)) {
  295.     namefield = alloca(strlen(name) + strlen(linkto) + 10);
  296.     sprintf(namefield, "%s -> %s", name, linkto);
  297.     } else if (S_ISCHR(mode)) {
  298.     perms[0] = 'c';
  299.     sprintf(sizefield, "%3d, %3d", rdev >> 8, rdev & 0xFF);
  300.     } else if (S_ISBLK(mode)) {
  301.     perms[0] = 'b';
  302.     sprintf(sizefield, "%3d, %3d", rdev >> 8, rdev & 0xFF);
  303.     }
  304.  
  305.     /* this is important if sizeof(int_32) ! sizeof(time_t) */
  306.     themtime = mtime;
  307.     tstruct = localtime(&themtime);
  308.  
  309.     if (tstruct->tm_year == thisYear || 
  310.     ((tstruct->tm_year + 1) == thisYear && tstruct->tm_mon > thisMonth)) 
  311.     strftime(timefield, sizeof(timefield) - 1, "%b %d %H:%M", tstruct);
  312.     else
  313.     strftime(timefield, sizeof(timefield) - 1, "%b %d  %Y", tstruct);
  314.  
  315.     printf("%s %8s %8s %10s %s %s\n", perms, ownerfield, groupfield, 
  316.         sizefield, timefield, namefield);
  317. }
  318.  
  319. static void showMatches(rpmdb db, dbiIndexSet matches, int queryFlags, 
  320.             char * queryFormat) {
  321.     int i;
  322.     Header h;
  323.  
  324.     for (i = 0; i < matches.count; i++) {
  325.     if (matches.recs[i].recOffset) {
  326.         rpmMessage(RPMMESS_DEBUG, "querying record number %d\n",
  327.             matches.recs[i].recOffset);
  328.         
  329.         h = rpmdbGetRecord(db, matches.recs[i].recOffset);
  330.         if (!h) {
  331.         fprintf(stderr, _("error: could not read database record\n"));
  332.         } else {
  333.         printHeader(h, queryFlags, queryFormat);
  334.         headerFree(h);
  335.         }
  336.     }
  337.     }
  338. }
  339.  
  340. int doQuery(char * prefix, enum querysources source, int queryFlags, 
  341.          char * arg, char * queryFormat) {
  342.     Header h;
  343.     int offset;
  344.     int fd;
  345.     int rc;
  346.     int isSource;
  347.     rpmdb db;
  348.     dbiIndexSet matches;
  349.     int recNumber;
  350.     int retcode = 0;
  351.     char *end = NULL;
  352.     struct urlContext context;
  353.     int isUrl = 0;
  354.     char path[255];
  355.  
  356.     if (source != QUERY_RPM) {
  357.     if (rpmdbOpen(prefix, &db, O_RDONLY, 0644)) {
  358.         exit(1);
  359.     }
  360.     }
  361.  
  362.     switch (source) {
  363.       case QUERY_RPM:
  364.     if (urlIsURL(arg)) {
  365.         isUrl = 1;
  366.         if ((fd = urlGetFd(arg, &context)) < 0) {
  367.         fprintf(stderr, _("open of %s failed: %s\n"), arg, 
  368.             ftpStrerror(fd));
  369.         }
  370.     } else if (!strcmp(arg, "-")) {
  371.         fd = 0;
  372.     } else {
  373.         if ((fd = open(arg, O_RDONLY)) < 0) {
  374.         fprintf(stderr, _("open of %s failed: %s\n"), arg, 
  375.             strerror(errno));
  376.         }
  377.     }
  378.  
  379.     if (fd >= 0) {
  380.         rc = rpmReadPackageHeader(fd, &h, &isSource, NULL, NULL);
  381.  
  382.         close(fd);
  383.         if (isUrl) {
  384.         urlFinishedFd(&context);
  385.         }
  386.  
  387.         switch (rc) {
  388.         case 0:
  389.             if (!h) {
  390.             fprintf(stderr, _("old format source packages cannot "
  391.                 "be queried\n"));
  392.             } else {
  393.             printHeader(h, queryFlags, queryFormat);
  394.             headerFree(h);
  395.             }
  396.             break;
  397.         case 1:
  398.             fprintf(stderr, 
  399.                 _("%s does not appear to be a RPM package\n"), 
  400.                 arg);
  401.             /* fallthrough */
  402.         case 2:
  403.             fprintf(stderr, _("query of %s failed\n"), arg);
  404.             retcode = 1;
  405.         }
  406.  
  407.     }
  408.         
  409.     break;
  410.  
  411.       case QUERY_ALL:
  412.     offset = rpmdbFirstRecNum(db);
  413.     while (offset) {
  414.         h = rpmdbGetRecord(db, offset);
  415.         if (!h) {
  416.         fprintf(stderr, _("could not read database record!\n"));
  417.         return 1;
  418.         }
  419.         printHeader(h, queryFlags, queryFormat);
  420.         headerFree(h);
  421.         offset = rpmdbNextRecNum(db, offset);
  422.     }
  423.     break;
  424.  
  425.       case QUERY_GROUP:
  426.     if (rpmdbFindByGroup(db, arg, &matches)) {
  427.         fprintf(stderr, _("group %s does not contain any packages\n"), arg);
  428.         retcode = 1;
  429.     } else {
  430.         showMatches(db, matches, queryFlags, queryFormat);
  431.         dbiFreeIndexRecord(matches);
  432.     }
  433.     break;
  434.  
  435.       case QUERY_WHATPROVIDES:
  436.     if (rpmdbFindByProvides(db, arg, &matches)) {
  437.         fprintf(stderr, _("no package provides %s\n"), arg);
  438.         retcode = 1;
  439.     } else {
  440.         showMatches(db, matches, queryFlags, queryFormat);
  441.         dbiFreeIndexRecord(matches);
  442.     }
  443.     break;
  444.  
  445.       case QUERY_WHATREQUIRES:
  446.     if (rpmdbFindByRequiredBy(db, arg, &matches)) {
  447.         fprintf(stderr, _("no package requires %s\n"), arg);
  448.         retcode = 1;
  449.     } else {
  450.         showMatches(db, matches, queryFlags, queryFormat);
  451.         dbiFreeIndexRecord(matches);
  452.     }
  453.     break;
  454.  
  455.       case QUERY_PATH:
  456.     if (*arg != '/') {
  457.         if (realpath(arg, path) != NULL)
  458.         arg = path;
  459.     }
  460.     if (rpmdbFindByFile(db, arg, &matches)) {
  461.         fprintf(stderr, _("file %s is not owned by any package\n"), arg);
  462.         retcode = 1;
  463.     } else {
  464.         showMatches(db, matches, queryFlags, queryFormat);
  465.         dbiFreeIndexRecord(matches);
  466.     }
  467.     break;
  468.  
  469.       case QUERY_DBOFFSET:
  470.     recNumber = strtoul(arg, &end, 10);
  471.     if ((*end) || (end == arg) || (recNumber == ULONG_MAX)) {
  472.         fprintf(stderr, _("invalid package number: %s\n"), arg);
  473.         return 1;
  474.     }
  475.     rpmMessage(RPMMESS_DEBUG, _("showing package: %d\n"), recNumber);
  476.     h = rpmdbGetRecord(db, recNumber);
  477.  
  478.     if (!h)  {
  479.         fprintf(stderr, _("record %d could not be read\n"), recNumber);
  480.         retcode = 1;
  481.     } else {
  482.         printHeader(h, queryFlags, queryFormat);
  483.         headerFree(h);
  484.     }
  485.     break;
  486.  
  487.       case QUERY_PACKAGE:
  488.     rc = rpmdbFindByLabel(db, arg, &matches);
  489.     if (rc == 1) {
  490.         retcode = 1;
  491.         fprintf(stderr, _("package %s is not installed\n"), arg);
  492.     } else if (rc == 2) {
  493.         retcode = 1;
  494.         fprintf(stderr, _("error looking for package %s\n"), arg);
  495.     } else {
  496.         showMatches(db, matches, queryFlags, queryFormat);
  497.         dbiFreeIndexRecord(matches);
  498.     }
  499.     break;
  500.     }
  501.    
  502.     if (source != QUERY_RPM) {
  503.     rpmdbClose(db);
  504.     }
  505.  
  506.     return retcode;
  507. }
  508.  
  509. void queryPrintTags(void) {
  510.     const struct headerTagTableEntry * t;
  511.     int i;
  512.  
  513.     for (i = 0, t = rpmTagTable; i < rpmTagTableSize; i++, t++) {
  514.     printf("%s\n", t->name + 7);
  515.     }
  516. }
  517.