diff options
Diffstat (limited to 'rpmmodule')
-rw-r--r-- | rpmmodule/Makefile | 6 | ||||
-rw-r--r-- | rpmmodule/rpmmodule.c | 47 | ||||
-rw-r--r-- | rpmmodule/upgrade.c | 476 | ||||
-rw-r--r-- | rpmmodule/upgrade.h | 17 |
4 files changed, 543 insertions, 3 deletions
diff --git a/rpmmodule/Makefile b/rpmmodule/Makefile index 375829278..6ae8d1856 100644 --- a/rpmmodule/Makefile +++ b/rpmmodule/Makefile @@ -1,13 +1,13 @@ DESTDIR = $(TOPDIR)/RedHat/instimage/usr/lib/python1.5/site-packages -CFLAGS += -I/usr/include/rpm -I/usr/include/python1.5 -g +CFLAGS += -fPIC -I/usr/include/rpm -I/usr/include/python1.5 -g TARGET = rpmmodule.so all: $(TARGET) -rpmmodule.so: rpmmodule.o - gcc -shared -o $@ rpmmodule.o -lrpm -lz -ldb1 +rpmmodule.so: rpmmodule.o upgrade.o hash.o + gcc -shared -o $@ $^ -lrpm -lz -ldb1 clean: rm -f *.o $(TARGET) diff --git a/rpmmodule/rpmmodule.c b/rpmmodule/rpmmodule.c index 852406f4d..6547ede23 100644 --- a/rpmmodule/rpmmodule.c +++ b/rpmmodule/rpmmodule.c @@ -1,3 +1,4 @@ +#include <alloca.h> #include <errno.h> #include <fcntl.h> #include <sys/stat.h> @@ -6,6 +7,7 @@ #include "Python.h" #include "rpmlib.h" +#include "upgrade.h" /* Forward types */ @@ -32,6 +34,7 @@ static rpmdbObject * rpmOpenDB(PyObject * self, PyObject * args); static PyObject * archScore(PyObject * self, PyObject * args); static PyObject * rpmHeaderFromPackage(PyObject * self, PyObject * args); static PyObject * rpmHeaderFromList(PyObject * self, PyObject * args); +static PyObject * findUpgradeSet(PyObject * self, PyObject * args); static PyObject * rpmtransCreate(PyObject * self, PyObject * args); static PyObject * rpmtransAdd(rpmtransObject * s, PyObject * args); @@ -48,6 +51,7 @@ static int rpmtransSetAttr(rpmtransObject * o, char * name, static PyMethodDef rpmModuleMethods[] = { { "opendb", (PyCFunction) rpmOpenDB, METH_VARARGS, NULL }, { "archscore", (PyCFunction) archScore, METH_VARARGS, NULL }, + { "findUpgradeSet", (PyCFunction) findUpgradeSet, METH_VARARGS, NULL }, { "headerFromPackage", (PyCFunction) rpmHeaderFromPackage, METH_VARARGS, NULL }, { "readHeaderList", (PyCFunction) rpmHeaderFromList, METH_VARARGS, NULL }, { "TransactionSet", (PyCFunction) rpmtransCreate, METH_VARARGS, NULL }, @@ -272,6 +276,49 @@ void initrpm(void) { PyInt_FromLong(RPMCALLBACK_UNINST_STOP)); } +static PyObject * findUpgradeSet(PyObject * self, PyObject * args) { + PyObject * hdrList, * result; + char * root = "/"; + int i, num; + struct pkgSet list; + hdrObject * hdr; + + if (!PyArg_ParseTuple(args, "o|s", &hdrList, &root)) return NULL; + + if (!PyList_Check(hdrList)) { + PyErr_SetString(PyExc_TypeError, "list of headers expected"); + return NULL; + } + + list.numPackages = PyList_Size(hdrList); + list.packages = alloca(sizeof(*list.packages) * list.numPackages); + for (i = 0; i < list.numPackages; i++) { + hdr = (hdrObject *) PyList_GetItem(hdrList, i); + if (hdr->ob_type != &hdrType) { + PyErr_SetString(PyExc_TypeError, "list of headers expected"); + return NULL; + } + list.packages[i].h = hdr->h; + list.packages[i].selected = 0; + + headerGetEntry(hdr->h, RPMTAG_NAME, NULL, + (void **) &list.packages[i].name, NULL); + } + + if (ugFindUpgradePackages(&list, root)) { + PyErr_SetString(pyrpmError, "error during upgrade check"); + return NULL; + } + + result = PyList_New(0); + for (i = 0; i < list.numPackages; i++) { + if (list.packages[i].selected) + PyList_Append(result, PyList_GetItem(hdrList, i)); + } + + return result; +} + static rpmdbObject * rpmOpenDB(PyObject * self, PyObject * args) { rpmdbObject * o; char * root = ""; diff --git a/rpmmodule/upgrade.c b/rpmmodule/upgrade.c new file mode 100644 index 000000000..971555189 --- /dev/null +++ b/rpmmodule/upgrade.c @@ -0,0 +1,476 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <rpm/rpmlib.h> +#include <rpm/header.h> +#include <string.h> + +#include "hash.h" +#include "upgrade.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 + +int pkgCompare(void * first, void * second) { + struct packageInfo ** a = first; + struct packageInfo ** b = second; + + /* put packages w/o names at the end */ + if (!(*a)->name) return 1; + if (!(*b)->name) return -1; + + return strcasecmp((*a)->name, (*b)->name); +} + +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(rpmdb db, struct pkgSet *psp, struct hash_table *ht) +{ + int num; + Header h; + char *name; + struct packageInfo **pack; + struct packageInfo key; + char **installedFiles; + int installedFileCount; + + num = rpmdbFirstRecNum(db); + while (num) { + h = rpmdbGetRecord(db, num); + headerGetEntry(h, RPMTAG_NAME, NULL, (void **) &name, NULL); + if (name && !strcmp(name, "metroess")) { + /* metro was removed from 5.1, but leave it if it's already + installed */ + headerFree(h); + num = rpmdbNextRecNum(db, num); + continue; + } + key.name = name; + + pack = bsearch(&key, 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 int findPackagesWithObsoletes(rpmdb db, struct pkgSet *psp) +{ + dbiIndexSet matches; + int rc, count, obsoletesCount; + struct packageInfo *pip; + char **obsoletes; + + count = psp->numPackages; + pip = psp->packages; + while (count--) { + if (pip->selected) { + pip++; + continue; + } + + if (headerGetEntry(pip->h, RPMTAG_OBSOLETES, NULL, + (void **) &obsoletes, &obsoletesCount)) { + while (obsoletesCount--) { + rc = rpmdbFindPackage(db, obsoletes[obsoletesCount], &matches); + if (!rc) { + if (matches.count) { + pip->selected = 1; + dbiFreeIndexRecord(matches); + break; + } + + dbiFreeIndexRecord(matches); + } + } + + free(obsoletes); + } + + pip++; + } + + return 0; +} + +static void errorFunction(void) +{ +} + +static int findUpgradePackages(rpmdb db, struct pkgSet *psp, + struct hash_table *ht) +{ + int skipThis; + Header h, installedHeader; + char *name, *version, *release; + dbiIndexSet matches; + int rc, i, count; + char **installedFiles, **availFiles; + int installedFileCount, availFileCount; + struct packageInfo *pip; + + count = psp->numPackages; + pip = psp->packages; + while (count--) { + h = pip->h; + 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(-1); + } + + /*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; + headerFree(installedHeader); + break; + } + headerFree(installedHeader); + } + rpmErrorSetCallback(NULL); + if (! skipThis) { + /*printf("No newer version installed\n");*/ + } + } else { + skipThis = 1; + /*printf("Not installed\n");*/ + } + + if (skipThis) { + /*printf("DO NOT INSTALL\n");*/ + } else { + /*printf("UPGRADE\n");*/ + pip->selected = 1; + + 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");*/ + + pip++; + } + + return 0; +} + +static int removeMovedFilesAlreadyHandled(struct pkgSet *psp, + struct hash_table *ht) +{ + char *name; + int i, count; + Header h; + char **availFiles; + int availFileCount; + char *file; + struct packageInfo *pip; + + count = psp->numPackages; + pip = psp->packages; + while (count--) { + h = pip->h; + if (pip->selected) { + 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]);*/ + break; + } + } + if (availFiles) { + free(availFiles); + } + } + + pip++; + } + + return 0; +} + +static int findPackagesWithRelocatedFiles(struct pkgSet *psp, + struct hash_table *ht) +{ + char *name; + int i, count; + Header h; + char **availFiles; + int availFileCount; + char *file; + struct packageInfo *pip; + + count = psp->numPackages; + pip = psp->packages; + while (count--) { + h = pip->h; + if (! pip->selected) { + 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]);*/ + pip->selected = 1; + break; + } + } + free(availFiles); + } + } + + pip++; + } + + return 0; +} + +/* +static void printCount(struct pkgSet *psp) +{ + int i, upgradeCount; + struct packageInfo *pip; + + upgradeCount = 0; + pip = psp->packages; + i = psp->numPackages; + while (i--) { + if (pip->selected) { + upgradeCount++; + } + pip++; + } + logMessage("marked %d packages for upgrade", upgradeCount); +} +*/ + +static int unmarkPackagesAlreadyInstalled(rpmdb db, struct pkgSet *psp) +{ + dbiIndexSet matches; + Header h, installedHeader; + char *name, *version, *release; + struct packageInfo *pip; + int count, rc, i; + + count = psp->numPackages; + pip = psp->packages; + while (count--) { + if (pip->selected) { + h = pip->h; + /* If this package is already installed, don't bother */ + 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(-1); + } + rc = rpmdbFindPackage(db, name, &matches); + if (rc == 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");*/ + pip->selected = 0; + headerFree(installedHeader); + break; + } + headerFree(installedHeader); + } + rpmErrorSetCallback(NULL); + dbiFreeIndexRecord(matches); + } + } + + pip++; + } + + return 0; +} + +static void emptyErrorCallback(void) { +} + +int ugFindUpgradePackages(struct pkgSet *psp, char *installRoot) +{ + rpmdb db; + struct hash_table *hashTable; + rpmErrorCallBackType old; + + /*logDebugMessage(("ugFindUpgradePackages() ..."));*/ + + rpmReadConfigFiles(NULL, NULL); + + rpmSetVerbosity(RPMMESS_FATALERROR); + old = rpmErrorSetCallback(emptyErrorCallback); + + if (rpmdbOpenForTraversal(installRoot, &db)) { + /*logMessage("failed opening %s/var/lib/rpm/packages.rpm", + installRoot);*/ + return(-1); + } + + rpmErrorSetCallback(old); + rpmSetVerbosity(RPMMESS_NORMAL); + + hashTable = htNewTable(1103); + + /* For all packages that are installed, if there is no package */ + /* available by that name, add the package's files to the hash table */ + addLostFiles(db, psp, hashTable); + /*logDebugMessage(("added lost files")); + printCount(psp);*/ + + /* Find packges that are new, and mark them in installThisPackage, */ + /* updating availPkgs with the count. Also add files to the hash */ + /* table that do not exist in the new package - they may have moved */ + if (findUpgradePackages(db, psp, hashTable)) { + rpmdbClose(db); + return(-1); + } + /*logDebugMessage(("found basic packages to upgrade")); + printCount(psp); + hash_stats(hashTable);*/ + + /* Remove any files that were added to the hash table that are in */ + /* some other package marked for upgrade. */ + removeMovedFilesAlreadyHandled(psp, hashTable); + /*logDebugMessage(("removed extra files which have moved")); + printCount(psp);*/ + + findPackagesWithRelocatedFiles(psp, hashTable); + /*logDebugMessage(("found packages with relocated files")); + printCount(psp);*/ + + findPackagesWithObsoletes(db, psp); + /*logDebugMessage(("found packages that obsolete installed packages")); + printCount(psp);*/ + + unmarkPackagesAlreadyInstalled(db, psp); + /*logDebugMessage(("unmarked packages already installed")); + printCount(psp);*/ + + htFreeHashTable(hashTable); + + /*printMemStats("Done");*/ + + rpmdbClose(db); + + return 0; +} diff --git a/rpmmodule/upgrade.h b/rpmmodule/upgrade.h new file mode 100644 index 000000000..96dacba8b --- /dev/null +++ b/rpmmodule/upgrade.h @@ -0,0 +1,17 @@ +#ifndef H_UPGRADE +#define H_UPGRADE + +struct packageInfo { + Header h; + char selected; + char * name; +} ; + +struct pkgSet { + struct packageInfo * packages; + int numPackages; +}; + +int ugFindUpgradePackages(struct pkgSet *psp, char *installRoot); + +#endif |