home *** CD-ROM | disk | FTP | other *** search
/ PC Plus SuperCD (UK) 1999 May / pcp151c.iso / misc / src / install / upgrade.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-05-08  |  10.8 KB  |  455 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <fcntl.h>
  5. #include <rpm/rpmlib.h>
  6. #include <rpm/header.h>
  7. #include <string.h>
  8.  
  9. #include "install.h"
  10. #include "log.h"
  11. #include "hash.h"
  12. #include "pkgs.h"
  13.  
  14. #define MAXPKGS 1024
  15.  
  16. #if 0
  17. static void printMemStats(char *mess)
  18. {
  19.     char buf[1024];
  20.     printf("%s\n", mess);
  21.     sprintf(buf, "cat /proc/%d/status | grep VmSize", getpid());
  22.     system(buf);
  23. }
  24. #endif
  25.  
  26. static void compareFileList(int availFileCount, char **availFiles,
  27.                 int installedFileCount, char **installedFiles,
  28.                 struct hash_table *ht)
  29. {
  30.     int installedX, availX, rc;
  31.     
  32.     availX = 0;
  33.     installedX = 0;
  34.     while (installedX < installedFileCount) {
  35.     if (availX == availFileCount) {
  36.         /* All the rest have moved */
  37.         /* printf("=> %s\n", installedFiles[installedX]); */
  38.         if (strncmp(installedFiles[installedX], "/etc/rc.d/", 10))
  39.         htAddToTable(ht, installedFiles[installedX]);
  40.         installedX++;
  41.     } else {
  42.         rc = strcmp(availFiles[availX], installedFiles[installedX]);
  43.         if (rc > 0) {
  44.         /* Avail > Installed -- file has moved */
  45.         /* printf("=> %s\n", installedFiles[installedX]); */
  46.         if (strncmp(installedFiles[installedX], "/etc/rc.d/", 10))
  47.             htAddToTable(ht, installedFiles[installedX]);
  48.         installedX++;
  49.         } else if (rc < 0) {
  50.         /* Avail < Installed -- avail has some new files */
  51.         availX++;
  52.         } else {
  53.         /* Files are equal -- file not moved */
  54.         availX++;
  55.         installedX++;
  56.         }
  57.     }
  58.     }
  59. }
  60.  
  61. static void addLostFiles( rpmdb db, struct pkgSet *psp, struct hash_table *ht)
  62. {
  63.     int num;
  64.     Header h;
  65.     char *name;
  66.     struct packageInfo **pack;
  67.     struct packageInfo key;
  68.     struct packageInfo *keyaddr = &key;
  69.     char **installedFiles;
  70.     int installedFileCount;
  71.  
  72.     num = rpmdbFirstRecNum(db);
  73.     while (num) {
  74.     h = rpmdbGetRecord(db, num);
  75.     headerGetEntry(h, RPMTAG_NAME, NULL, (void **) &name, NULL);
  76.     if (!strcmp(name, "metroess")) {
  77.         /* metro was removed from 5.1, but leave it if it's already
  78.            installed */
  79.         headerFree(h);
  80.         num = rpmdbNextRecNum(db, num);
  81.         continue;
  82.     }
  83.     key.name = name;
  84.     
  85.     pack = bsearch(&keyaddr, psp->packages, psp->numPackages,
  86.                sizeof(*psp->packages), (void *)pkgCompare);
  87.     if (!pack) {
  88.         if (headerGetEntry(h, RPMTAG_FILENAMES, NULL,
  89.               (void **) &installedFiles, &installedFileCount)) {
  90.         compareFileList(0, NULL, installedFileCount,
  91.                 installedFiles, ht);
  92.         free(installedFiles);
  93.         }
  94.     }
  95.     
  96.     headerFree(h);
  97.     num = rpmdbNextRecNum(db, num);
  98.     }
  99. }
  100.  
  101. static int findPackagesWithObsoletes(rpmdb db, struct pkgSet *psp)
  102. {
  103.     dbiIndexSet matches;
  104.     int rc, count, obsoletesCount;
  105.     struct packageInfo **pip;
  106.     char **obsoletes;
  107.  
  108.     count = psp->numPackages;
  109.     pip = psp->packages;
  110.     while (count--) {
  111.     if ((*pip)->selected) {
  112.         pip++;
  113.         continue;
  114.     }
  115.  
  116.     if (headerGetEntry((*pip)->h, RPMTAG_OBSOLETES, NULL,
  117.                (void **) &obsoletes, &obsoletesCount)) {
  118.         while (obsoletesCount--) {
  119.         rc = rpmdbFindPackage(db, obsoletes[obsoletesCount], &matches);
  120.         if (!rc) {
  121.             if (matches.count) {
  122.             (*pip)->selected = 1;
  123.             dbiFreeIndexRecord(matches);
  124.             break;
  125.             }
  126.  
  127.             dbiFreeIndexRecord(matches);
  128.         }
  129.         }
  130.  
  131.         free(obsoletes);
  132.     }
  133.  
  134.     pip++;
  135.     }
  136.  
  137.     return 0;
  138. }
  139.  
  140. static void errorFunction(void)
  141. {
  142. }
  143.  
  144. static int findUpgradePackages(rpmdb db, struct pkgSet *psp,
  145.                    struct hash_table *ht)
  146. {
  147.     int skipThis;
  148.     Header h, installedHeader;
  149.     char *name, *version, *release;
  150.     dbiIndexSet matches;
  151.     int rc, i, count;
  152.     char **installedFiles, **availFiles;
  153.     int installedFileCount, availFileCount;
  154.     struct packageInfo **pip;
  155.  
  156.     count = psp->numPackages;
  157.     pip = psp->packages;
  158.     while (count--) {
  159.     h = (*pip)->h;
  160.     name = version = release = NULL;
  161.     headerGetEntry(h, RPMTAG_NAME, NULL, (void **) &name, NULL);
  162.     headerGetEntry(h, RPMTAG_VERSION, NULL, (void **) &version, NULL);
  163.     headerGetEntry(h, RPMTAG_RELEASE, NULL, (void **) &release, NULL);
  164.     if (! (name && version && release)) {
  165.         /* bum header */
  166.         logMessage("Failed with bad header");
  167.         return(INST_ERROR);
  168.     }
  169.  
  170.     /* XXX - Need to do serial number stuff someday */
  171.     /*printf("Avail: %s-%s-%s\n", name, version, release);*/
  172.     rc = rpmdbFindPackage(db, name, &matches);
  173.  
  174.     if (rc == 0) {
  175.         skipThis = 0;
  176.         rpmErrorSetCallback(errorFunction);
  177.         for (i = 0; i < matches.count; i++) {
  178.         installedHeader =
  179.             rpmdbGetRecord(db, matches.recs[i].recOffset);
  180.         if (rpmVersionCompare(installedHeader, h) >= 0) {
  181.             /* already have a newer version installed */
  182.             /*printf("Already have newer version\n");*/
  183.             skipThis = 1;
  184.             break;
  185.         }
  186.         }
  187.         rpmErrorSetCallback(NULL);
  188.         if (! skipThis) {
  189.         /*printf("No newer version installed\n");*/
  190.         }
  191.     } else {
  192.         skipThis = 1;
  193.         /*printf("Not installed\n");*/
  194.     }
  195.     
  196.     if (skipThis) {
  197.         /*printf("DO NOT INSTALL\n");*/
  198.     } else {
  199.         /*printf("UPGRADE\n");*/
  200.         (*pip)->selected = 1;
  201.  
  202.         if (!headerGetEntry(h, RPMTAG_FILENAMES, NULL,
  203.               (void **) &availFiles, &availFileCount)) {
  204.         availFiles = NULL;
  205.         availFileCount = 0;
  206.         }
  207.  
  208.         for (i = 0; i < matches.count; i++) {
  209.         /* Compare the file lists */
  210.         installedHeader =
  211.             rpmdbGetRecord(db, matches.recs[i].recOffset);
  212.         if (!headerGetEntry(installedHeader, RPMTAG_FILENAMES, NULL,
  213.                   (void **) &installedFiles,
  214.                   &installedFileCount)) {
  215.             installedFiles = NULL;
  216.             installedFileCount = 0;
  217.         }
  218.  
  219.         compareFileList(availFileCount, availFiles,
  220.                 installedFileCount, installedFiles, ht);
  221.  
  222.         if (installedFiles) {
  223.             free(installedFiles);
  224.         }
  225.         headerFree(installedHeader);
  226.         }
  227.  
  228.         if (availFiles) {
  229.         free(availFiles);
  230.         }
  231.     }
  232.  
  233.     if (rc == 0) {
  234.         dbiFreeIndexRecord(matches);
  235.     }
  236.  
  237.     /*printf("\n\n");*/
  238.  
  239.     pip++;
  240.     }
  241.  
  242.     return 0;
  243. }
  244.  
  245. static int removeMovedFilesAlreadyHandled(struct pkgSet *psp,
  246.                       struct hash_table *ht)
  247. {
  248.     char *name;
  249.     int i, count;
  250.     Header h;
  251.     char **availFiles;
  252.     int availFileCount;
  253.     char *file;
  254.     struct packageInfo **pip;
  255.  
  256.     count = psp->numPackages;
  257.     pip = psp->packages;
  258.     while (count--) {
  259.     h = (*pip)->h;
  260.     if ((*pip)->selected) {
  261.         name = NULL;
  262.         headerGetEntry(h, RPMTAG_NAME, NULL, (void **) &name, NULL);
  263.  
  264.         if (!headerGetEntry(h, RPMTAG_FILENAMES, NULL,
  265.               (void **) &availFiles, &availFileCount)) {
  266.         availFiles = NULL;
  267.         availFileCount = 0;
  268.         }
  269.  
  270.         for (i = 0; i < availFileCount; i++) {
  271.         if ((file = htInTable(ht, availFiles[i]))) {
  272.             *file = '\0';
  273.             /*printf("File already in %s: %s\n", name, availFiles[i]);*/
  274.             break;
  275.         }
  276.         }
  277.         if (availFiles) {
  278.         free(availFiles);
  279.         }
  280.     }
  281.  
  282.     pip++;
  283.     }
  284.  
  285.     return 0;
  286. }
  287.  
  288. static int findPackagesWithRelocatedFiles(struct pkgSet *psp,
  289.                       struct hash_table *ht)
  290. {
  291.     char *name;
  292.     int i, count;
  293.     Header h;
  294.     char **availFiles;
  295.     int availFileCount;
  296.     char *file;
  297.     struct packageInfo **pip;
  298.  
  299.     count = psp->numPackages;
  300.     pip = psp->packages;
  301.     while (count--) {
  302.     h = (*pip)->h;
  303.     if (! (*pip)->selected) {
  304.         name = NULL;
  305.         headerGetEntry(h, RPMTAG_NAME, NULL, (void **) &name, NULL);
  306.  
  307.         availFiles = NULL;
  308.         availFileCount = 0;
  309.         if (headerGetEntry(h, RPMTAG_FILENAMES, NULL,
  310.              (void **) &availFiles, &availFileCount)) {
  311.         for (i = 0; i < availFileCount; i++) {
  312.             if ((file = htInTable(ht, availFiles[i]))) {
  313.             *file = '\0';
  314.             /*printf("Found file in %s: %s\n", name,
  315.               availFiles[i]);*/
  316.             (*pip)->selected = 1;
  317.             break;
  318.             }
  319.         }
  320.         free(availFiles);
  321.         }
  322.     }
  323.  
  324.     pip++;
  325.     }
  326.  
  327.     return 0;
  328. }
  329.  
  330. static void printCount(struct pkgSet *psp)
  331. {
  332.     int i, upgradeCount;
  333.     struct packageInfo **pip;
  334.     
  335.     upgradeCount = 0;
  336.     pip = psp->packages;
  337.     i = psp->numPackages;
  338.     while (i--) {
  339.     if ((*pip)->selected) {
  340.         upgradeCount++;
  341.     }
  342.     pip++;
  343.     }
  344.     logMessage("marked %d packages for upgrade", upgradeCount);
  345. }
  346.  
  347. static int unmarkPackagesAlreadyInstalled(rpmdb db, struct pkgSet *psp)
  348. {
  349.     dbiIndexSet matches;
  350.     Header h, installedHeader;
  351.     char *name, *version, *release;
  352.     struct packageInfo **pip;
  353.     int count, rc, i;
  354.  
  355.     count = psp->numPackages;
  356.     pip = psp->packages;
  357.     while (count--) {
  358.     if ((*pip)->selected) {
  359.         h = (*pip)->h;
  360.         /* If this package is already installed, don't bother */
  361.         name = version = release = NULL;
  362.         headerGetEntry(h, RPMTAG_NAME, NULL, (void **) &name, NULL);
  363.         headerGetEntry(h, RPMTAG_VERSION, NULL, (void **) &version, NULL);
  364.         headerGetEntry(h, RPMTAG_RELEASE, NULL, (void **) &release, NULL);
  365.         if (! (name && version && release)) {
  366.         /* bum header */
  367.         logMessage("Failed with bad header");
  368.         return(INST_ERROR);
  369.         }
  370.         rc = rpmdbFindPackage(db, name, &matches);
  371.         if (rc == 0) {
  372.         rpmErrorSetCallback(errorFunction);
  373.         for (i = 0; i < matches.count; i++) {
  374.             installedHeader =
  375.             rpmdbGetRecord(db, matches.recs[i].recOffset);
  376.             if (rpmVersionCompare(installedHeader, h) >= 0) {
  377.             /* already have a newer version installed */
  378.             /*printf("Already have newer version\n");*/
  379.             (*pip)->selected = 0;
  380.             break;
  381.             }
  382.         }
  383.         rpmErrorSetCallback(NULL);
  384.         dbiFreeIndexRecord(matches);
  385.         }
  386.     }
  387.  
  388.     pip++;
  389.     }
  390.  
  391.     return 0;
  392. }
  393.         
  394.  
  395. int ugFindUpgradePackages(struct pkgSet *psp, char *installRoot)
  396. {
  397.     rpmdb db;
  398.     struct hash_table *hashTable;
  399.  
  400.     logDebugMessage(("ugFindUpgradePackages() ..."));
  401.  
  402.     rpmReadConfigFiles(NULL, NULL, NULL, 0);
  403.  
  404.     if (rpmdbOpen(installRoot, &db, O_CREAT | O_RDWR, 0644)) {
  405.     logMessage("failed opening %s/var/lib/rpm/packages.rpm",
  406.              installRoot);
  407.     return(INST_ERROR);
  408.     }
  409.  
  410.     hashTable = htNewTable(1103);
  411.  
  412.     /* For all packages that are installed, if there is no package       */
  413.     /* available by that name, add the package's files to the hash table */
  414.     addLostFiles(db, psp, hashTable);
  415.     logDebugMessage(("added lost files"));
  416.     printCount(psp);
  417.     
  418.     /* Find packges that are new, and mark them in installThisPackage,  */
  419.     /* updating availPkgs with the count.  Also add files to the hash   */
  420.     /* table that do not exist in the new package - they may have moved */
  421.     if (findUpgradePackages(db, psp, hashTable)) {
  422.     rpmdbClose(db);
  423.     return(INST_ERROR);
  424.     }
  425.     logDebugMessage(("found basic packages to upgrade"));
  426.     printCount(psp);
  427.     /*hash_stats(hashTable);*/
  428.  
  429.     /* Remove any files that were added to the hash table that are in */
  430.     /* some other package marked for upgrade.                         */
  431.     removeMovedFilesAlreadyHandled(psp, hashTable);
  432.     logDebugMessage(("removed extra files which have moved"));
  433.     printCount(psp);
  434.  
  435.     findPackagesWithRelocatedFiles(psp, hashTable);
  436.     logDebugMessage(("found packages with relocated files"));
  437.     printCount(psp);
  438.  
  439.     findPackagesWithObsoletes(db, psp);
  440.     logDebugMessage(("found packages that obsolete installed packages"));
  441.     printCount(psp);
  442.     
  443.     unmarkPackagesAlreadyInstalled(db, psp);
  444.     logDebugMessage(("unmarked packages already installed"));
  445.     printCount(psp);
  446.     
  447.     htFreeHashTable(hashTable);
  448.     
  449.     /*printMemStats("Done");*/
  450.  
  451.     rpmdbClose(db);
  452.  
  453.     return 0;
  454. }
  455.