#include #include #include #include #include #include #include #include "install.h" #include "log.h" #include "hash.h" #include "pkgs.h" #define MAXPKGS 1024 #if 0 static void printMemStats(char *mess) { char buf[1024]; printf("%s\n", mess); sprintf(buf, "cat /proc/%d/status | grep VmSize", getpid()); system(buf); } #endif static void compareFileList(int availFileCount, char **availFiles, int installedFileCount, char **installedFiles, struct hash_table *ht) { int installedX, availX, rc; availX = 0; installedX = 0; while (installedX < installedFileCount) { if (availX == availFileCount) { /* All the rest have moved */ /* printf("=> %s\n", installedFiles[installedX]); */ if (strncmp(installedFiles[installedX], "/etc/rc.d/", 10)) htAddToTable(ht, installedFiles[installedX]); installedX++; } else { rc = strcmp(availFiles[availX], installedFiles[installedX]); if (rc > 0) { /* Avail > Installed -- file has moved */ /* printf("=> %s\n", installedFiles[installedX]); */ if (strncmp(installedFiles[installedX], "/etc/rc.d/", 10)) htAddToTable(ht, installedFiles[installedX]); installedX++; } else if (rc < 0) { /* Avail < Installed -- avail has some new files */ availX++; } else { /* Files are equal -- file not moved */ availX++; installedX++; } } } } static void addLostFiles(struct pkgSet *psp, struct hash_table *ht, rpmdb db) { int num; Header h; char *name; struct packageInfo **pack; struct packageInfo key; struct packageInfo *keyaddr = &key; char **installedFiles; int installedFileCount; num = rpmdbFirstRecNum(db); while (num) { h = rpmdbGetRecord(db, num); headerGetEntry(h, RPMTAG_NAME, NULL, (void **) &name, NULL); key.name = name; pack = bsearch(&keyaddr, psp->packages, psp->numPackages, sizeof(*psp->packages), (void *)pkgCompare); if (!pack) { if (headerGetEntry(h, RPMTAG_FILENAMES, NULL, (void **) &installedFiles, &installedFileCount)) { compareFileList(0, NULL, installedFileCount, installedFiles, ht); free(installedFiles); } } headerFree(h); num = rpmdbNextRecNum(db, num); } } static void errorFunction(void) { } static int findUpgradePackages(rpmdb db, int ugdbfd, struct hash_table *ht, char **resultArray, int *availPkgs) { int pkgNum, skipThis; Header h, installedHeader; char *name, *version, *release; dbiIndexSet matches; int rc, i; char **installedFiles, **availFiles; int installedFileCount, availFileCount; lseek(ugdbfd, 0, SEEK_SET); pkgNum = 0; while ((h = headerRead(ugdbfd, HEADER_MAGIC_YES))) { name = version = release = NULL; headerGetEntry(h, RPMTAG_NAME, NULL, (void **) &name, NULL); headerGetEntry(h, RPMTAG_VERSION, NULL, (void **) &version, NULL); headerGetEntry(h, RPMTAG_RELEASE, NULL, (void **) &release, NULL); if (! (name && version && release)) { /* bum header */ logMessage("Failed with bad header"); return(INST_ERROR); } /* XXX - Need to do serial number stuff someday */ /*printf("Avail: %s-%s-%s\n", name, version, release);*/ rc = rpmdbFindPackage(db, name, &matches); if (rc == 0) { skipThis = 0; rpmErrorSetCallback(errorFunction); for (i = 0; i < matches.count; i++) { installedHeader = rpmdbGetRecord(db, matches.recs[i].recOffset); if (rpmVersionCompare(installedHeader, h) > 0) { /* already have a newer version installed */ /*printf("Already have newer version\n");*/ skipThis = 1; break; } } rpmErrorSetCallback(NULL); if (! skipThis) { /* no newer version installed */ /*printf("No newer version installed\n");*/ skipThis = 0; } } else { skipThis = 1; /*printf("Not installed\n");*/ } if (skipThis) { /*printf("DO NOT INSTALL\n");*/ } else { /*printf("UPGRADE\n");*/ if (!resultArray[pkgNum]) { resultArray[pkgNum] = strdup(name); } if (!headerGetEntry(h, RPMTAG_FILENAMES, NULL, (void **) &availFiles, &availFileCount)) { availFiles = NULL; availFileCount = 0; } for (i = 0; i < matches.count; i++) { /* Compare the file lists */ installedHeader = rpmdbGetRecord(db, matches.recs[i].recOffset); if (!headerGetEntry(installedHeader, RPMTAG_FILENAMES, NULL, (void **) &installedFiles, &installedFileCount)) { installedFiles = NULL; installedFileCount = 0; } compareFileList(availFileCount, availFiles, installedFileCount, installedFiles, ht); if (installedFiles) { free(installedFiles); } headerFree(installedHeader); } if (availFiles) { free(availFiles); } } if (rc == 0) { dbiFreeIndexRecord(matches); } /*printf("\n\n");*/ headerFree(h); pkgNum++; } *availPkgs = pkgNum; return 0; } static int removeMovedFilesAlreadyHandled(int ugdbfd, struct hash_table *ht, char **resultArray) { int pkgNum; char *name; int i; Header h; char **availFiles; int availFileCount; char *file; lseek(ugdbfd, 0, SEEK_SET); pkgNum = 0; while ((h = headerRead(ugdbfd, HEADER_MAGIC_YES))) { if (resultArray[pkgNum]) { name = NULL; headerGetEntry(h, RPMTAG_NAME, NULL, (void **) &name, NULL); if (!headerGetEntry(h, RPMTAG_FILENAMES, NULL, (void **) &availFiles, &availFileCount)) { availFiles = NULL; availFileCount = 0; } for (i = 0; i < availFileCount; i++) { if ((file = htInTable(ht, availFiles[i]))) { *file = '\0'; /*printf("File already in %s: %s\n", name, availFiles[i]);*/ if (!resultArray[pkgNum]) { resultArray[pkgNum] = strdup(name); } break; } } if (availFiles) { free(availFiles); } } pkgNum++; headerFree(h); } return 0; } static int findPackagesWithRelocatedFiles(int ugdbfd, struct hash_table *ht, char **resultArray) { int pkgNum; char *name; int i; Header h; char **availFiles; int availFileCount; char *file; lseek(ugdbfd, 0, SEEK_SET); pkgNum = 0; while ((h = headerRead(ugdbfd, HEADER_MAGIC_YES))) { if (! resultArray[pkgNum]) { name = NULL; headerGetEntry(h, RPMTAG_NAME, NULL, (void **) &name, NULL); availFiles = NULL; availFileCount = 0; if (headerGetEntry(h, RPMTAG_FILENAMES, NULL, (void **) &availFiles, &availFileCount)) { for (i = 0; i < availFileCount; i++) { if ((file = htInTable(ht, availFiles[i]))) { *file = '\0'; /*printf("Found file in %s: %s\n", name, availFiles[i]);*/ if (!resultArray[pkgNum]) { resultArray[pkgNum] = strdup(name); } break; } } free(availFiles); } } pkgNum++; headerFree(h); } return 0; } int ugFindUpgradePackages(struct pkgSet *psp, char *installRoot, char *ugdbName) { int fd; rpmdb db; struct hash_table *hashTable; char *installThisPackage[MAXPKGS]; int availPkgs, i, upgradeCount; struct packageInfo **pack; struct packageInfo key; struct packageInfo *keyaddr = &key; if ((fd = open(ugdbName, O_RDONLY)) < 0) { logMessage("failed opening %s", ugdbName); return(INST_ERROR); } rpmReadConfigFiles(NULL, NULL, NULL, 0); if (rpmdbOpen(installRoot, &db, O_RDWR | O_CREAT, 0644)) { close(fd); logMessage("failed opening %s/var/lib/rpm/packages.rpm", installRoot); return(INST_ERROR); } for (i = 0; i < MAXPKGS; i++) { installThisPackage[i] = NULL; } hashTable = htNewTable(1103); addLostFiles(psp, hashTable, db); if (findUpgradePackages(db, fd, hashTable, \ installThisPackage, &availPkgs)) { close(fd); rpmdbClose(db); return(INST_ERROR); } /*hash_stats(hashTable);*/ removeMovedFilesAlreadyHandled(fd, hashTable, installThisPackage); findPackagesWithRelocatedFiles(fd, hashTable, installThisPackage); htFreeHashTable(hashTable); /*printMemStats("Done");*/ rpmdbClose(db); close(fd); upgradeCount = 0; for (i = 0; i < MAXPKGS; i++) { if (installThisPackage[i]) { key.name = installThisPackage[i]; pack = bsearch(&keyaddr, psp->packages, psp->numPackages, sizeof(*psp->packages), (void *)pkgCompare); (*pack)->selected = 1; free(installThisPackage[i]); upgradeCount++; } } logMessage("ugFindUpgradePackages() marked %d packages", upgradeCount); return 0; }