+#include <alloca.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "Python.h"
#include "rpmlib.h"
+#include "upgrade.h"
/* Forward types */
static PyObject * rpmdbGetAttr(rpmdbObject * s, char * name);
static PyObject * rpmdbFirst(rpmdbObject * s, PyObject * args);
static PyObject * rpmdbNext(rpmdbObject * s, PyObject * args);
+static PyObject * rpmdbByName(rpmdbObject * s, PyObject * args);
+static PyObject * rpmdbByProvides(rpmdbObject * s, PyObject * args);
+static PyObject * rpmdbByFile(rpmdbObject * s, PyObject * args);
static int rpmdbLength(rpmdbObject * s);
static hdrObject * rpmdbSubscript(rpmdbObject * s, PyObject * key);
static void hdrDealloc(hdrObject * s);
static PyObject * hdrGetAttr(hdrObject * s, char * name);
-static PyObject * hdrSubscript(hdrObject * s, int item);
+static PyObject * hdrSubscript(hdrObject * s, PyObject * item);
+static PyObject * hdrKeyList(hdrObject * s, PyObject * args);
+static PyObject * hdrUnload(hdrObject * s, PyObject * args);
static PyObject * hdrVerifyFile(hdrObject * s, PyObject * args);
void initrpm(void);
static rpmdbObject * rpmOpenDB(PyObject * self, PyObject * args);
-static PyObject * archScore(PyObject * self, PyObject * args);
+static PyObject * hdrLoad(PyObject * self, PyObject * args);
static PyObject * rpmHeaderFromPackage(PyObject * self, PyObject * args);
-static PyObject * rpmHeaderFromList(PyObject * self, PyObject * args);
+static PyObject * rpmHeaderFromFile(PyObject * self, PyObject * args);
+static PyObject * archScore(PyObject * self, PyObject * args);
+static PyObject * rpmHeaderFromFD(PyObject * self, PyObject * args);
+static PyObject * findUpgradeSet(PyObject * self, PyObject * args);
+static PyObject * errorSetCallback (PyObject * self, PyObject * args);
+static PyObject * errorString (PyObject * self, PyObject * args);
static PyObject * rpmtransCreate(PyObject * self, PyObject * args);
static PyObject * rpmtransAdd(rpmtransObject * s, PyObject * args);
/* Types */
static PyMethodDef rpmModuleMethods[] = {
- { "opendb", (PyCFunction) rpmOpenDB, METH_VARARGS, NULL },
+ { "TransactionSet", (PyCFunction) rpmtransCreate, 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 },
+ { "headerLoad", (PyCFunction) hdrLoad, METH_VARARGS, NULL },
+ { "opendb", (PyCFunction) rpmOpenDB, METH_VARARGS, NULL },
+ { "readHeaderListFromFD", (PyCFunction) rpmHeaderFromFD, METH_VARARGS, NULL },
+ { "readHeaderListFromFile", (PyCFunction) rpmHeaderFromFile, METH_VARARGS, NULL },
+ { "errorSetCallback", (PyCFunction) errorSetCallback, METH_VARARGS, NULL },
+ { "errorString", (PyCFunction) errorString, METH_VARARGS, NULL },
{ NULL }
} ;
static PyObject * pyrpmError;
-static PySequenceMethods hdrAsSequence = {
- 0, /* length */
- 0, /* concat */
- 0, /* repeat */
- (intargfunc) hdrSubscript, /* item */
- 0, /* slice */
- 0, /* assign item */
- 0, /* assign slice */
+static PyMappingMethods hdrAsMapping = {
+ (inquiry) 0, /* mp_length */
+ (binaryfunc) hdrSubscript, /* mp_subscript */
+ (objobjargproc)0, /* mp_ass_subscript */
};
static PyTypeObject hdrType = {
0, /* tp_compare */
0, /* tp_repr */
0, /* tp_as_number */
- &hdrAsSequence, /* tp_as_sequence */
- 0, /* tp_as_mapping */
+ 0, /* tp_as_sequence */
+ &hdrAsMapping, /* tp_as_mapping */
};
static PyMappingMethods rpmdbAsMapping = {
};
static struct PyMethodDef rpmdbMethods[] = {
- {"firstkey", (PyCFunction) rpmdbFirst, 1 },
- {"nextkey", (PyCFunction) rpmdbNext, 1 },
+ {"firstkey", (PyCFunction) rpmdbFirst, 1 },
+ {"nextkey", (PyCFunction) rpmdbNext, 1 },
+ {"findbyfile", (PyCFunction) rpmdbByFile, 1 },
+ {"findbyname", (PyCFunction) rpmdbByName, 1 },
+ {"findbyprovides", (PyCFunction) rpmdbByProvides, 1 },
{NULL, NULL} /* sentinel */
};
};
static struct PyMethodDef hdrMethods[] = {
+ {"keys", (PyCFunction) hdrKeyList, 1 },
+ {"unload", (PyCFunction) hdrUnload, 1 },
{"verifyFile", (PyCFunction) hdrVerifyFile, 1 },
{NULL, NULL} /* sentinel */
};
+/* External functions */
+int mdfile(const char *fn, unsigned char *digest);
+
/* Code */
void initrpm(void) {
- PyObject * m, * d, * tag;
+ PyObject * m, * d, * tag, * dict;
int i;
rpmReadConfigFiles(NULL, NULL);
pyrpmError = PyString_FromString("rpm.error");
PyDict_SetItemString(d, "error", pyrpmError);
+ dict = PyDict_New();
+
for (i = 0; i < rpmTagTableSize; i++) {
tag = PyInt_FromLong(rpmTagTable[i].val);
PyDict_SetItemString(d, rpmTagTable[i].name, tag);
+
+ PyDict_SetItem(dict, tag, PyString_FromString(rpmTagTable[i].name + 7));
}
+ PyDict_SetItemString(d, "tagnames", dict);
+
PyDict_SetItemString(d, "RPMFILE_STATE_NORMAL",
PyInt_FromLong(RPMFILE_STATE_NORMAL));
PyDict_SetItemString(d, "RPMFILE_STATE_REPLACED",
PyInt_FromLong(RPMCALLBACK_UNINST_STOP));
}
+
+static int psGetArchScore(Header h) {
+ void * pkgArch;
+ int type, count;
+
+ if (!headerGetEntry(h, RPMTAG_ARCH, &type, (void **) &pkgArch, &count) ||
+ type == RPM_INT8_TYPE)
+ return 150;
+ else
+ return rpmMachineScore(RPM_MACHTABLE_INSTARCH, pkgArch);
+}
+
+static int pkgCompareVer(void * first, void * second) {
+ struct packageInfo ** a = first;
+ struct packageInfo ** b = second;
+ int ret, score1, score2;
+
+ /* put packages w/o names at the end */
+ if (!(*a)->name) return 1;
+ if (!(*b)->name) return -1;
+
+ ret = strcasecmp((*a)->name, (*b)->name);
+ if (ret) return ret;
+ score1 = psGetArchScore((*a)->h);
+ if (!score1) return 1;
+ score2 = psGetArchScore((*b)->h);
+ if (!score2) return -1;
+ if (score1 < score2) return -1;
+ if (score1 > score2) return 1;
+ return rpmVersionCompare((*b)->h, (*a)->h);
+}
+
+static void pkgSort(struct pkgSet * psp) {
+ int i;
+ char *name;
+
+ qsort(psp->packages, psp->numPackages, sizeof(*psp->packages),
+ (void *) pkgCompareVer);
+
+ name = psp->packages[0]->name;
+ if (!name) {
+ psp->numPackages = 0;
+ return;
+ }
+ for (i = 1; i < psp->numPackages; i++) {
+ if (!psp->packages[i]->name) break;
+ if (!strcmp(psp->packages[i]->name, name))
+ psp->packages[i]->name = NULL;
+ else
+ name = psp->packages[i]->name;
+ }
+
+ qsort(psp->packages, psp->numPackages, sizeof(*psp->packages),
+ (void *) pkgCompareVer);
+
+ for (i = 0; i < psp->numPackages; i++)
+ if (!psp->packages[i]->name) break;
+ psp->numPackages = i;
+}
+
+static PyObject * findUpgradeSet(PyObject * self, PyObject * args) {
+ PyObject * hdrList, * result;
+ char * root = "/";
+ int i;
+ 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] = alloca(sizeof(struct packageInfo));
+ list.packages[i]->h = hdr->h;
+ list.packages[i]->selected = 0;
+ list.packages[i]->data = hdr;
+
+ headerGetEntry(hdr->h, RPMTAG_NAME, NULL,
+ (void **) &list.packages[i]->name, NULL);
+ }
+
+ pkgSort (&list);
+
+ 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, list.packages[i]->data);
+ }
+
+ return result;
+}
+
static rpmdbObject * rpmOpenDB(PyObject * self, PyObject * args) {
rpmdbObject * o;
char * root = "";
return o;
}
-static PyObject * rpmHeaderFromList(PyObject * self, PyObject * args) {
- char * filespec;
- FD_t fd;
- Header header;
+static PyObject * rpmReadHeaders (FD_t fd) {
PyObject * list;
+ Header header;
hdrObject * h;
- if (!PyArg_ParseTuple(args, "s", &filespec)) return NULL;
- fd = fdOpen(filespec, O_RDONLY, 0);
-
if (!fd) {
PyErr_SetFromErrno(pyrpmError);
return NULL;
}
list = PyList_New(0);
-
+ Py_BEGIN_ALLOW_THREADS
header = headerRead(fd, HEADER_MAGIC_YES);
+ Py_END_ALLOW_THREADS
while (header) {
h = (hdrObject *) PyObject_NEW(PyObject, &hdrType);
h->h = header;
Py_DECREF(h);
+ Py_BEGIN_ALLOW_THREADS
header = headerRead(fd, HEADER_MAGIC_YES);
+ Py_END_ALLOW_THREADS
}
+ return list;
+}
+
+static PyObject * rpmHeaderFromFD(PyObject * self, PyObject * args) {
+ FD_t fd;
+ int fileno;
+ PyObject * list;
+
+ if (!PyArg_ParseTuple(args, "i", &fileno)) return NULL;
+ fd = fdDup(fileno);
+
+ list = rpmReadHeaders (fd);
fdClose(fd);
return list;
}
+
+static PyObject * hdrLoad(PyObject * self, PyObject * args) {
+ char * obj;
+ Header hdr;
+ hdrObject * h;
+ int len;
+
+ if (!PyArg_ParseTuple(args, "s#", &obj, &len)) return NULL;
+
+ hdr = headerLoad(obj);
+ if (!hdr) {
+ PyErr_SetString(pyrpmError, "bad header");
+ return NULL;
+ }
+
+ h = (hdrObject *) PyObject_NEW(PyObject, &hdrType);
+ h->h = hdr;
+ h->fileList = h->linkList = h->md5list = NULL;
+ h->uids = h->gids = h->mtimes = h->fileSizes = NULL;
+ h->modes = h->rdevs = NULL;
+
+ return (PyObject *) h;
+}
+
+static PyObject * rpmHeaderFromFile(PyObject * self, PyObject * args) {
+ char * filespec;
+ FD_t fd;
+ PyObject * list;
+
+ if (!PyArg_ParseTuple(args, "s", &filespec)) return NULL;
+ fd = fdOpen(filespec, O_RDONLY, 0);
+
+ if (!fd) {
+ PyErr_SetFromErrno(pyrpmError);
+ return NULL;
+ }
+
+ list = rpmReadHeaders (fd);
+ fdClose(fd);
+
+ return list;
+}
+
+static PyObject * errorCB = NULL, * errorData = NULL;
+
+static void errorcb (void)
+{
+ PyObject * result, * args = NULL;
+
+ if (errorData)
+ args = Py_BuildValue("(O)", errorData);
+
+ result = PyEval_CallObject(errorCB, args);
+ Py_XDECREF(args);
+
+ if (result == NULL) {
+ PyErr_Print();
+ PyErr_Clear();
+ }
+ Py_DECREF (result);
+}
+
+static PyObject * errorSetCallback (PyObject * self, PyObject * args) {
+ if (errorCB != NULL) {
+ Py_DECREF (errorCB);
+ errorCB = NULL;
+ }
+
+ if (errorData != NULL) {
+ Py_DECREF (errorData);
+ errorData = NULL;
+ }
+
+ if (!PyArg_ParseTuple(args, "O|O", &errorCB, &errorData)) return NULL;
+
+ if (!PyCallable_Check (errorCB)) {
+ PyErr_SetString(PyExc_TypeError, "parameter must be callable");
+ return NULL;
+ }
+
+ Py_INCREF (errorCB);
+ Py_XINCREF (errorData);
+
+ rpmErrorSetCallback (errorcb);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * errorString (PyObject * self, PyObject * args) {
+ return PyString_FromString(rpmErrorString ());
+}
+
static PyObject * rpmHeaderFromPackage(PyObject * self, PyObject * args) {
- PyObject * fileObj;
hdrObject * h;
Header header;
int rc;
static PyObject * rpmdbFirst(rpmdbObject * s, PyObject * args) {
int first;
- if (!PyArg_Parse(args, "")) return NULL;
+ if (!PyArg_ParseTuple (args, "")) return NULL;
first = rpmdbFirstRecNum(s->db);
static PyObject * rpmdbNext(rpmdbObject * s, PyObject * args) {
int where;
- if (!PyArg_Parse(args, "i", &where)) return NULL;
+ if (!PyArg_ParseTuple (args, "i", &where)) return NULL;
where = rpmdbNextRecNum(s->db, where);
return Py_BuildValue("i", where);
}
+static PyObject * handleDbResult(int rc, dbiIndexSet matches) {
+ PyObject * list;
+ int i;
+
+ if (rc == -1) {
+ PyErr_SetString(pyrpmError, "error reading from database");
+ return NULL;
+ }
+
+ list = PyList_New(0);
+
+ if (!rc) {
+ for (i = 0; i < matches.count; i++)
+ PyList_Append(list, PyInt_FromLong(matches.recs[i].recOffset));
+
+ dbiFreeIndexRecord(matches);
+ }
+
+ return list;
+}
+
+static PyObject * rpmdbByName(rpmdbObject * s, PyObject * args) {
+ char * str;
+ dbiIndexSet matches;
+ int rc;
+
+ if (!PyArg_ParseTuple(args, "s", &str)) return NULL;
+
+ rc = rpmdbFindPackage(s->db, str, &matches);
+ return handleDbResult(rc, matches);
+}
+
+static PyObject * rpmdbByFile(rpmdbObject * s, PyObject * args) {
+ char * str;
+ dbiIndexSet matches;
+ int rc;
+
+ if (!PyArg_ParseTuple(args, "s", &str)) return NULL;
+
+ rc = rpmdbFindByFile(s->db, str, &matches);
+ return handleDbResult(rc, matches);
+}
+
+static PyObject * rpmdbByProvides(rpmdbObject * s, PyObject * args) {
+ char * str;
+ dbiIndexSet matches;
+ int rc;
+
+ if (!PyArg_ParseTuple(args, "s", &str)) return NULL;
+
+ rc = rpmdbFindByProvides(s->db, str, &matches);
+ return handleDbResult(rc, matches);
+}
+
static int rpmdbLength(rpmdbObject * s) {
int first;
int count = 0;
return Py_FindMethod(hdrMethods, (PyObject * ) s, name);
}
-static PyObject * hdrSubscript(hdrObject * s, int tag) {
- int type, count;
+static PyObject * hdrSubscript(hdrObject * s, PyObject * item) {
+ int type, count, i, tag = -1;
void * data;
PyObject * o, * metao;
- int i;
char ** stringArray;
int forceArray = 0;
+ char * str;
+
+ if (PyInt_Check(item)) {
+ tag = PyInt_AsLong(item);
+ } else if (PyString_Check(item)) {
+ str = PyString_AsString(item);
+ for (i = 0; i < rpmTagTableSize; i++)
+ if (!strcasecmp(rpmTagTable[i].name + 7, str)) break;
+ if (i < rpmTagTableSize) tag = rpmTagTable[i].val;
+ }
+
+ if (tag == -1) {
+ PyErr_SetString(PyExc_KeyError, "unknown header tag");
+ return NULL;
+ }
if (!headerGetEntry(s->h, tag, &type, &data, &count)) {
Py_INCREF(Py_None);
return o;
}
+static PyObject * hdrKeyList(hdrObject * s, PyObject * args) {
+ PyObject * list;
+ HeaderIterator iter;
+ int tag, type;
+
+ if (!PyArg_ParseTuple(args, "")) return NULL;
+
+ list = PyList_New(0);
+
+ iter = headerInitIterator(s->h);
+ while (headerNextIterator(iter, &tag, &type, NULL, NULL)) {
+ if (tag == HEADER_I18NTABLE) continue;
+
+ switch (type) {
+ case RPM_BIN_TYPE:
+ case RPM_INT32_TYPE:
+ case RPM_CHAR_TYPE:
+ case RPM_INT8_TYPE:
+ case RPM_INT16_TYPE:
+ case RPM_STRING_ARRAY_TYPE:
+ case RPM_STRING_TYPE:
+ PyList_Append(list, PyInt_FromLong(tag));
+ }
+ }
+
+ headerFreeIterator(iter);
+
+ return list;
+}
+
+static PyObject * hdrUnload(hdrObject * s, PyObject * args) {
+ char * buf;
+ int len;
+ PyObject * rc;
+
+ len = headerSizeof(s->h, 0);
+ buf = headerUnload(s->h);
+
+ rc = PyString_FromStringAndSize(buf, len);
+ free(buf);
+
+ return rc;
+}
+
/* Returns a list of these tuple for each part which failed:
(attr_name, correctValue, currentValue)
PyTuple_SetItem(tuple, 0, attrName);
sprintf(buf, "0x%-4x", s->rdevs[fileNumber]);
PyTuple_SetItem(tuple, 1, PyString_FromString(buf));
- sprintf(buf, "0x%-4x", sb.st_rdev);
+ sprintf(buf, "0x%-4x", (unsigned int) sb.st_rdev);
PyTuple_SetItem(tuple, 2, PyString_FromString(buf));
PyList_Append(list, tuple);
}
o = (void *) PyObject_NEW(rpmtransObject, &rpmtransType);
- Py_INCREF(db);
+ Py_XINCREF(db);
o->dbo = db;
+ o->scriptFd = NULL;
o->ts = rpmtransCreateSet(db ? db->db : NULL, rootPath);
o->keyList = PyList_New(0);
rpmtransObject * trans = (void *) o;
rpmtransFree(trans->ts);
- if (trans->dbo) Py_DECREF(trans->dbo);
+ if (trans->dbo) {
+ Py_DECREF(trans->dbo);
+ }
if (trans->scriptFd) fdClose(trans->scriptFd);
+ /* this will free the keyList, and decrement the ref count of all
+ the items on the list as well :-) */
Py_DECREF(trans->keyList);
}
hdrObject * h;
PyObject * key;
char * how = NULL;
+ int isUpgrade = 0;
- if (!PyArg_ParseTuple(args, "OO|s", &h, &key, &s)) return NULL;
+ if (!PyArg_ParseTuple(args, "OO|s", &h, &key, &how)) return NULL;
if (h->ob_type != &hdrType) {
PyErr_SetString(PyExc_TypeError, "bad type for header argument");
return NULL;
}
- if (how && strcmp(how, "a") && strcmp(how, "u")) {
- PyErr_SetString(PyExc_TypeError, "how argument must be \"u\" or \"a\"");
+ if (how && strcmp(how, "a") && strcmp(how, "u") && strcmp(how, "i")) {
+ PyErr_SetString(PyExc_TypeError, "how argument must be \"u\", \"a\", or \"i\"");
return NULL;
- }
+ } else if (how && !strcmp(how, "u"))
+ isUpgrade = 1;
- if (how && strcmp(how, "a"))
+ if (how && !strcmp(how, "a"))
rpmtransAvailablePackage(s->ts, h->h, key);
else
- rpmtransAddPackage(s->ts, h->h, NULL, key, how ? 1 : 0, NULL);
+ rpmtransAddPackage(s->ts, h->h, NULL, key, isUpgrade, NULL);
+ /* This should increment the usage count for me */
if (key) PyList_Append(s->keyList, key);
Py_INCREF(Py_None);
struct tsCallbackType * cbInfo = data;
PyObject * args, * result;
int fd;
- FD_t fdt;
+ static FD_t fdt;
if (cbInfo->pythonError) return NULL;
return NULL;
}
fdt = fdDup(fd);
- close(fd);
Py_DECREF(result);
return fdt;
}
+ if (what == RPMCALLBACK_INST_CLOSE_FILE) {
+ fdClose (fdt);
+ }
+
Py_DECREF(result);
return NULL;
--- /dev/null
+#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
+
+#define USEDEBUG 0
+
+#define DEBUG(x) { \
+ if (USEDEBUG) \
+ printf x; \
+ }
+
+#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 */
+ DEBUG(("=> %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 */
+ DEBUG (("=> %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;
+ 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);
+ 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(&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 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);
+ }
+
+ DEBUG (("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 */
+ DEBUG (("Already have newer version\n"))
+ skipThis = 1;
+ headerFree(installedHeader);
+ break;
+ }
+ headerFree(installedHeader);
+ }
+ rpmErrorSetCallback(NULL);
+ if (! skipThis) {
+ DEBUG (("No newer version installed\n"))
+ }
+ } else {
+ skipThis = 1;
+ DEBUG (("Not installed\n"))
+ }
+
+ if (skipThis) {
+ DEBUG (("DO NOT INSTALL\n"))
+ } else {
+ DEBUG (("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);
+ }
+
+ DEBUG (("\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';
+ DEBUG (("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';
+ DEBUG (("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 */
+ DEBUG (("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;
+}