python/upgrade.c

Go to the documentation of this file.
00001 
00005 #include <stdio.h>
00006 #include <stdlib.h>
00007 #include <unistd.h>
00008 #include <fcntl.h>
00009 #include <string.h>
00010 
00011 #include <glob.h>       /* XXX rpmio.h */
00012 #include <dirent.h>     /* XXX rpmio.h */
00013 
00014 #include <rpmlib.h>
00015 
00016 #include "hash.h"
00017 #include "upgrade.h"
00018 
00019 #define MAXPKGS 1024
00020 
00021 #define USEDEBUG 0
00022 
00023 #define DEBUG(x) {   \
00024      if (USEDEBUG)   \
00025          printf x; \
00026      }
00027 
00028 #if 0
00029 static void printMemStats(char *mess)
00030 {
00031     char buf[1024];
00032     printf("%s\n", mess);
00033     sprintf(buf, "cat /proc/%d/status | grep VmSize", getpid());
00034     system(buf);
00035 }
00036 #endif
00037 
00038 /*@access Header@*/             /* compared with NULL. */
00039 /*@access rpmdbMatchIterator@*/ /* compared with NULL. */
00040 
00041 int pkgCompare(void * first, void * second);    /* XXX make gcc shut up. */
00042 int pkgCompare(void * first, void * second) {
00043     struct packageInfo ** a = first;
00044     struct packageInfo ** b = second;
00045 
00046     /* put packages w/o names at the end */
00047     if (!(*a)->name) return 1;
00048     if (!(*b)->name) return -1;
00049 
00050     return xstrcasecmp((*a)->name, (*b)->name);
00051 }
00052 
00053 
00054 /* Adds all files in the second file list which are not in the first
00055    file list to the hash table. */
00056 static void compareFileList(int availFileCount, char ** availBaseNames,
00057                             char ** availDirNames, int * availDirIndexes,
00058                             int instFileCount, char ** instBaseNames,
00059                             char ** instDirNames, int * instDirIndexes,
00060                             struct hash_table *ht)
00061 {
00062     int installedX, availX, rc;
00063     char * availDir, * availBase;
00064     char * instDir, * instBase;
00065     static int i = 0;
00066     
00067     availX = 0;
00068     installedX = 0;
00069     while (installedX < instFileCount) {
00070         instBase = instBaseNames[installedX];
00071         instDir = instDirNames[instDirIndexes[installedX]];
00072 
00073         if (availX == availFileCount) {
00074             /* All the rest have moved */
00075             DEBUG(("=> %d: %s%s\n", i++, instDir, instBase))
00076             if (strncmp(instDir, "/etc/rc.d/", 10))
00077                 htAddToTable(ht, instDir, instBase);
00078             installedX++;
00079         } else {
00080             availBase = availBaseNames[availX];
00081             availDir = availDirNames[availDirIndexes[availX]];
00082 
00083             rc = strcmp(availDir, instDir);
00084             if (!rc) 
00085                 rc = strcmp(availBase, instBase);
00086 
00087             if (rc > 0) {
00088                 /* Avail > Installed -- file has moved */
00089                 DEBUG(("=> %d: %s%s\n", i++, instDir, instBase))
00090                 if (strncmp(instDir, "/etc/rc.d/", 10))
00091                     htAddToTable(ht, instDir, instBase);
00092                 installedX++;
00093             } else if (rc < 0) {
00094                 /* Avail < Installed -- avail has some new files */
00095                 availX++;
00096             } else {
00097                 /* Files are equal -- file not moved */
00098                 availX++;
00099                 installedX++;
00100             }
00101         }
00102     }
00103 }
00104 
00105 static void addLostFiles(rpmdb db, struct pkgSet *psp, struct hash_table *ht)
00106 {
00107     char *name;
00108     struct packageInfo **pack;
00109     struct packageInfo key;
00110     struct packageInfo *keyaddr = &key;
00111     char **installedFiles;
00112     char **installedDirs;
00113     int_32 * installedDirIndexes;
00114     int installedFileCount;
00115     Header h = NULL;
00116     rpmdbMatchIterator mi;
00117 
00118     mi = rpmdbInitIterator(db, RPMDBI_PACKAGES, NULL, 0);
00119     while ((h = rpmdbNextIterator(mi)) != NULL) {
00120 
00121         (void) headerGetEntry(h, RPMTAG_NAME, NULL, (void **) &name, NULL);
00122         if (name && !strcmp(name, "metroess")) {
00123             /* metro was removed from 5.1, but leave it if it's already
00124                installed */
00125             continue;
00126         }
00127         key.name = name;
00128         
00129         pack = bsearch(&keyaddr, psp->packages, psp->numPackages,
00130                        sizeof(*psp->packages), (void *)pkgCompare);
00131         if (!pack) {
00132             if (headerGetEntryMinMemory(h, RPMTAG_BASENAMES, NULL,
00133                           (const void **) &installedFiles, &installedFileCount)
00134             &&  headerGetEntryMinMemory(h, RPMTAG_DIRINDEXES, NULL,
00135                           (const void **) &installedDirIndexes, NULL)
00136             &&  headerGetEntryMinMemory(h, RPMTAG_DIRNAMES, NULL,
00137                           (const void **) &installedDirs, NULL))
00138             {
00139 
00140                 compareFileList(0, NULL, NULL, NULL, installedFileCount,
00141                                 installedFiles, installedDirs,
00142                                 installedDirIndexes, ht);
00143 
00144                 free(installedFiles);
00145                 free(installedDirs);
00146             }
00147         }
00148     }
00149 
00150     mi = rpmdbFreeIterator(mi);
00151 }
00152 
00153 static int findPackagesWithObsoletes(rpmdb db, struct pkgSet *psp)
00154 {
00155     int count, obsoletesCount;
00156     struct packageInfo **pip;
00157     char **obsoletes;
00158 
00159     count = psp->numPackages;
00160     pip = psp->packages;
00161     while (count--) {
00162         if ((*pip)->selected != 0) {
00163             pip++;
00164             continue;
00165         }
00166 
00167         if (headerGetEntryMinMemory((*pip)->h, RPMTAG_OBSOLETENAME, NULL,
00168                        (const void **) &obsoletes, &obsoletesCount)) {
00169             while (obsoletesCount--) {
00170                 if (rpmdbCountPackages(db, obsoletes[obsoletesCount]) > 0) {
00171                     (*pip)->selected = 1;
00172                     break;
00173                 }
00174             }
00175 
00176             free(obsoletes);
00177         }
00178 
00179         pip++;
00180     }
00181 
00182     return 0;
00183 }
00184 
00185 static void errorFunction(void)
00186 {
00187 }
00188 
00189 static int findUpgradePackages(rpmdb db, struct pkgSet *psp,
00190                                struct hash_table *ht)
00191 {
00192     int skipThis;
00193     Header h, installedHeader;
00194     char *name;
00195     int count;
00196     char **installedFiles;
00197     char ** availFiles = NULL;
00198     char ** installedDirs;
00199     char ** availDirs = NULL;
00200     int_32 * installedDirIndexes;
00201     int_32 * availDirIndexes = NULL;
00202     int installedFileCount, availFileCount;
00203     struct packageInfo **pip;
00204 
00205     count = psp->numPackages;
00206     pip = psp->packages;
00207     while (count--) {
00208         h = (*pip)->h;
00209         name = NULL;
00210         if (!headerGetEntry(h, RPMTAG_NAME, NULL, (void **) &name, NULL) ||
00211             name == NULL)
00212         {
00213             /* bum header */
00214             /*logMessage("Failed with bad header");*/
00215             return(-1);
00216         }
00217         
00218         DEBUG (("Avail: %s\n", name));
00219 
00220     {   rpmdbMatchIterator mi;
00221 
00222         mi = rpmdbInitIterator(db, RPMTAG_NAME, name, 0);
00223         skipThis = (mi != NULL ? 0 : 1);
00224         (void) rpmErrorSetCallback(errorFunction);
00225         while ((installedHeader = rpmdbNextIterator(mi)) != NULL) {
00226             if (rpmVersionCompare(installedHeader, h) >= 0) {
00227                 /* already have a newer version installed */
00228                 DEBUG (("Already have newer version\n"))
00229                 skipThis = 1;
00230                 break;
00231             }
00232         }
00233         mi = rpmdbFreeIterator(mi);
00234         (void) rpmErrorSetCallback(NULL);
00235         if (! skipThis) {
00236             DEBUG (("No newer version installed\n"))
00237         }
00238     }
00239         
00240         if (skipThis) {
00241             DEBUG (("DO NOT INSTALL\n"))
00242         } else {
00243             DEBUG (("UPGRADE\n"))
00244             (*pip)->selected = 1;
00245 
00246             if (!headerGetEntryMinMemory(h, RPMTAG_BASENAMES, NULL,
00247                           (const void **) &availFiles, &availFileCount)) {
00248                 availFiles = NULL;
00249                 availFileCount = 0;
00250             } else {
00251                 (void) headerGetEntryMinMemory(h, RPMTAG_DIRNAMES, NULL,
00252                             (const void **) &availDirs, NULL);
00253                 (void) headerGetEntryMinMemory(h, RPMTAG_DIRINDEXES, NULL,
00254                             (const void **) &availDirIndexes, NULL);
00255             }
00256 
00257         {   rpmdbMatchIterator mi;
00258             mi = rpmdbInitIterator(db, RPMTAG_NAME, name, 0);
00259             while((installedHeader = rpmdbNextIterator(mi)) != NULL) {
00260                 if (headerGetEntryMinMemory(installedHeader, RPMTAG_BASENAMES, 
00261                                 NULL, (const void **) &installedFiles,
00262                                 &installedFileCount)
00263                 &&  headerGetEntryMinMemory(installedHeader, RPMTAG_DIRNAMES, 
00264                                 NULL, (const void **) &installedDirs, NULL)
00265                 &&  headerGetEntryMinMemory(installedHeader, RPMTAG_DIRINDEXES, 
00266                                 NULL, (const void **) &installedDirIndexes, NULL))
00267                 {
00268 
00269                     compareFileList(availFileCount, availFiles,
00270                                     availDirs, availDirIndexes,
00271                                     installedFileCount, installedFiles, 
00272                                     installedDirs, installedDirIndexes,
00273                                     ht);
00274 
00275                     free(installedFiles);
00276                     free(installedDirs);
00277                 }
00278             }
00279             mi = rpmdbFreeIterator(mi);
00280         }
00281 
00282             if (availFiles) {
00283                 free(availFiles);
00284                 free(availDirs);
00285             }
00286         }
00287 
00288         DEBUG (("\n\n"))
00289 
00290         pip++;
00291     }
00292 
00293     return 0;
00294 }
00295 
00296 static int removeMovedFilesAlreadyHandled(struct pkgSet *psp,
00297                                           struct hash_table *ht)
00298 {
00299     char *name;
00300     int i, count;
00301     Header h;
00302     char ** availFiles, ** availDirs;
00303     int_32 * availDirIndexes;
00304     int availFileCount;
00305     struct packageInfo **pip;
00306 
00307     count = psp->numPackages;
00308     pip = psp->packages;
00309     while (count--) {
00310         h = (*pip)->h;
00311         if ((*pip)->selected != 0) {
00312             name = NULL;
00313             (void) headerGetEntry(h, RPMTAG_NAME, NULL, (void **) &name, NULL);
00314 
00315             if (headerGetEntryMinMemory(h, RPMTAG_BASENAMES, NULL,
00316                           (const void **) &availFiles, &availFileCount)
00317 
00318             &&  headerGetEntryMinMemory(h, RPMTAG_DIRNAMES, NULL, 
00319                                (const void **) &availDirs, NULL)
00320             &&  headerGetEntryMinMemory(h, RPMTAG_DIRINDEXES, NULL, 
00321                                (const void **) &availDirIndexes, NULL))
00322             {
00323 
00324                 for (i = 0; i < availFileCount; i++) {
00325                     if (htInTable(ht, availDirs[availDirIndexes[i]],
00326                                           availFiles[i])) {
00327                         htRemoveFromTable(ht, availDirs[availDirIndexes[i]],
00328                                           availFiles[i]);
00329                         DEBUG (("File already in %s: %s%s\n", name, 
00330                                 availDirs[availDirIndexes[i]], availFiles[i]))
00331                         break;
00332                     }
00333                 }
00334 
00335                 free(availFiles);
00336                 free(availDirs);
00337             }
00338         }
00339 
00340         pip++;
00341     }
00342 
00343     return 0;
00344 }
00345 
00346 static int findPackagesWithRelocatedFiles(struct pkgSet *psp,
00347                                           struct hash_table *ht)
00348 {
00349     char *name;
00350     int i, count;
00351     Header h;
00352     char **availFiles, **availDirs;
00353     int_32 * availDirIndexes;
00354     int availFileCount;
00355     struct packageInfo **pip;
00356     int_16 * availFileModes;
00357 
00358     count = psp->numPackages;
00359     pip = psp->packages;
00360     while (count--) {
00361         h = (*pip)->h;
00362         if (! (*pip)->selected) {
00363             name = NULL;
00364             (void) headerGetEntry(h, RPMTAG_NAME, NULL, (void **) &name, NULL);
00365 
00366             if (headerGetEntry(h, RPMTAG_BASENAMES, NULL,
00367                          (void **) &availFiles, &availFileCount)
00368             &&  headerGetEntryMinMemory(h, RPMTAG_DIRNAMES, NULL,
00369                             (const void **) &availDirs, NULL)
00370             &&  headerGetEntryMinMemory(h, RPMTAG_DIRINDEXES, NULL,
00371                             (const void **) &availDirIndexes, NULL)
00372             &&  headerGetEntryMinMemory(h, RPMTAG_FILEMODES, NULL,
00373                             (const void **) &availFileModes, NULL))
00374             {
00375 
00376                 for (i = 0; i < availFileCount; i++) {
00377                     if (S_ISDIR(availFileModes[i])) continue;
00378 
00379                     if (htInTable(ht, availDirs[availDirIndexes[i]], 
00380                                     availFiles[i])) {
00381                         htRemoveFromTable(ht, availDirs[availDirIndexes[i]],
00382                                           availFiles[i]);
00383                         DEBUG (("Found file in %s: %s%s\n", name,
00384                                 availDirs[availDirIndexes[i]], availFiles[i]))
00385                         (*pip)->selected = 1;
00386                     }
00387                 }
00388                 free(availFiles);
00389                 free(availDirs);
00390             }
00391         }
00392 
00393         pip++;
00394     }
00395 
00396     return 0;
00397 }
00398 
00399 /*
00400 static void printCount(struct pkgSet *psp)
00401 {
00402     int i, upgradeCount;
00403     struct packageInfo *pip;
00404     
00405     upgradeCount = 0;
00406     pip = psp->packages;
00407     i = psp->numPackages;
00408     while (i--) {
00409         if (pip->selected) {
00410             upgradeCount++;
00411         }
00412         pip++;
00413     }
00414     logMessage("marked %d packages for upgrade", upgradeCount);
00415 }
00416 */
00417 
00418 static int unmarkPackagesAlreadyInstalled(rpmdb db, struct pkgSet *psp)
00419 {
00420     Header h, installedHeader;
00421     char *name;
00422     struct packageInfo **pip;
00423     int count;
00424 
00425     count = psp->numPackages;
00426     pip = psp->packages;
00427     while (count--) {
00428         if ((*pip)->selected != 0) {
00429             h = (*pip)->h;
00430             /* If this package is already installed, don't bother */
00431             name = NULL;
00432             if (!headerGetEntry(h, RPMTAG_NAME, NULL, (void **) &name, NULL) ||
00433                 name == NULL)
00434             {
00435                 /* bum header */
00436                 /*logMessage("Failed with bad header");*/
00437                 return(-1);
00438             }
00439           { rpmdbMatchIterator mi;
00440 
00441             mi = rpmdbInitIterator(db, RPMTAG_NAME, name, 0);
00442             (void) rpmErrorSetCallback(errorFunction);
00443             while((installedHeader = rpmdbNextIterator(mi)) != NULL) {
00444                 if (rpmVersionCompare(installedHeader, h) >= 0) {
00445                     /* already have a newer version installed */
00446                     DEBUG (("Already have newer version\n"))
00447                     (*pip)->selected = 0;
00448                     break;
00449                 }
00450             }
00451             mi = rpmdbFreeIterator(mi);
00452             (void) rpmErrorSetCallback(NULL);
00453           }
00454         }
00455 
00456         pip++;
00457     }
00458 
00459     return 0;
00460 }
00461             
00462 static void emptyErrorCallback(void) {
00463 }
00464 
00465 int ugFindUpgradePackages(struct pkgSet *psp, char *installRoot)
00466 {
00467     rpmdb db;
00468     struct hash_table *hashTable;
00469     rpmErrorCallBackType old;    
00470 
00471     /*logDebugMessage(("ugFindUpgradePackages() ..."));*/
00472 
00473 /*      rpmReadConfigFiles(NULL, NULL); */
00474 
00475     rpmSetVerbosity(RPMMESS_FATALERROR);
00476     old = rpmErrorSetCallback(emptyErrorCallback);
00477 
00478     if (rpmdbOpen(installRoot, &db, O_RDONLY, 0644)) {
00479         /*logMessage("failed opening %s/var/lib/rpm/packages.rpm",
00480                      installRoot);*/
00481         return(-1);
00482     }
00483 
00484     (void) rpmErrorSetCallback(old);
00485     rpmSetVerbosity(RPMMESS_NORMAL);
00486     
00487     hashTable = htNewTable(1103);
00488     if (hashTable == NULL) return (-1);
00489 
00490     /* For all packages that are installed, if there is no package       */
00491     /* available by that name, add the package's files to the hash table */
00492     addLostFiles(db, psp, hashTable);
00493     /*logDebugMessage(("added lost files"));
00494     printCount(psp);*/
00495     
00496     /* Find packges that are new, and mark them in installThisPackage,  */
00497     /* updating availPkgs with the count.  Also add files to the hash   */
00498     /* table that do not exist in the new package - they may have moved */
00499     if (findUpgradePackages(db, psp, hashTable)) {
00500         (void) rpmdbClose(db);
00501         return(-1);
00502     }
00503     /*logDebugMessage(("found basic packages to upgrade"));
00504     printCount(psp);
00505     hash_stats(hashTable);*/
00506 
00507     /* Remove any files that were added to the hash table that are in */
00508     /* some other package marked for upgrade.                         */
00509     (void) removeMovedFilesAlreadyHandled(psp, hashTable);
00510     /*logDebugMessage(("removed extra files which have moved"));
00511     printCount(psp);*/
00512 
00513     (void) findPackagesWithRelocatedFiles(psp, hashTable);
00514     /*logDebugMessage(("found packages with relocated files"));
00515     printCount(psp);*/
00516 
00517     (void) findPackagesWithObsoletes(db, psp);
00518     /*logDebugMessage(("found packages that obsolete installed packages"));
00519     printCount(psp);*/
00520     
00521     (void) unmarkPackagesAlreadyInstalled(db, psp);
00522     /*logDebugMessage(("unmarked packages already installed"));
00523     printCount(psp);*/
00524     
00525     htFreeHashTable(hashTable);
00526     
00527     /*printMemStats("Done");*/
00528 
00529     (void) rpmdbClose(db);
00530 
00531     return 0;
00532 }

Generated on Wed Mar 8 18:19:37 2006 for rpm by  doxygen 1.4.6