# 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 }