500 lines
11 KiB
C
500 lines
11 KiB
C
|
/** \ingroup python
|
||
|
* \file python/db-py.c
|
||
|
*/
|
||
|
|
||
|
#include <fcntl.h>
|
||
|
#include <unistd.h>
|
||
|
|
||
|
#include "Python.h"
|
||
|
#include "rpmio_internal.h"
|
||
|
#include "rpmcli.h" /* XXX for rpmCheckSig */
|
||
|
#include "misc.h"
|
||
|
#include "header_internal.h"
|
||
|
#include "upgrade.h"
|
||
|
|
||
|
#include "db-py.h"
|
||
|
#include "header-py.h"
|
||
|
|
||
|
/** \ingroup python
|
||
|
*/
|
||
|
typedef struct rpmdbMIObject_s rpmdbMIObject;
|
||
|
|
||
|
/** \ingroup python
|
||
|
* \class rpmdbMatchIterator
|
||
|
* \brief A python rpmdbMatchIterator object represents the result of an RPM
|
||
|
* database query.
|
||
|
*/
|
||
|
|
||
|
/** \ingroup python
|
||
|
* \name Class: rpmdbMatchIterator
|
||
|
*/
|
||
|
/*@{*/
|
||
|
|
||
|
/** \ingroup python
|
||
|
*/
|
||
|
struct rpmdbMIObject_s {
|
||
|
PyObject_HEAD;
|
||
|
rpmdbObject *db;
|
||
|
rpmdbMatchIterator mi;
|
||
|
} ;
|
||
|
|
||
|
/** \ingroup python
|
||
|
*/
|
||
|
static PyObject *
|
||
|
rpmdbMINext(rpmdbMIObject * s, PyObject * args) {
|
||
|
/* XXX assume header? */
|
||
|
Header h;
|
||
|
hdrObject * ho;
|
||
|
|
||
|
if (!PyArg_ParseTuple (args, "")) return NULL;
|
||
|
|
||
|
h = rpmdbNextIterator(s->mi);
|
||
|
if (!h) {
|
||
|
Py_INCREF(Py_None);
|
||
|
return Py_None;
|
||
|
}
|
||
|
|
||
|
ho = createHeaderObject(h);
|
||
|
|
||
|
return (PyObject *) ho;
|
||
|
}
|
||
|
|
||
|
/** \ingroup python
|
||
|
*/
|
||
|
static PyObject *
|
||
|
rpmdbMIpattern(rpmdbMIObject * s, PyObject * args) {
|
||
|
PyObject *index = NULL;
|
||
|
int type;
|
||
|
char * pattern;
|
||
|
int tag;
|
||
|
|
||
|
if (!PyArg_ParseTuple(args, "Ois", &index, &type, &pattern))
|
||
|
return NULL;
|
||
|
|
||
|
if (index == NULL)
|
||
|
tag = 0;
|
||
|
else if ((tag = tagNumFromPyObject (index)) == -1) {
|
||
|
PyErr_SetString(PyExc_TypeError, "unknown tag type");
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
rpmdbSetIteratorRE(s->mi, tag, type, pattern);
|
||
|
|
||
|
Py_INCREF (Py_None);
|
||
|
return Py_None;
|
||
|
|
||
|
}
|
||
|
|
||
|
/** \ingroup python
|
||
|
*/
|
||
|
static struct PyMethodDef rpmdbMIMethods[] = {
|
||
|
{"next", (PyCFunction) rpmdbMINext, 1 },
|
||
|
{"pattern", (PyCFunction) rpmdbMIpattern, 1 },
|
||
|
{NULL, NULL} /* sentinel */
|
||
|
};
|
||
|
|
||
|
/** \ingroup python
|
||
|
*/
|
||
|
static PyObject * rpmdbMIGetAttr (rpmdbObject *s, char *name) {
|
||
|
return Py_FindMethod (rpmdbMIMethods, (PyObject *) s, name);
|
||
|
}
|
||
|
|
||
|
/** \ingroup python
|
||
|
*/
|
||
|
static void rpmdbMIDealloc(rpmdbMIObject * s) {
|
||
|
if (s && s->mi) {
|
||
|
rpmdbFreeIterator(s->mi);
|
||
|
}
|
||
|
Py_DECREF (s->db);
|
||
|
PyMem_DEL(s);
|
||
|
}
|
||
|
|
||
|
/** \ingroup python
|
||
|
*/
|
||
|
PyTypeObject rpmdbMIType = {
|
||
|
PyObject_HEAD_INIT(NULL)
|
||
|
0, /* ob_size */
|
||
|
"rpmdbMatchIterator", /* tp_name */
|
||
|
sizeof(rpmdbMIObject), /* tp_size */
|
||
|
0, /* tp_itemsize */
|
||
|
(destructor) rpmdbMIDealloc, /* tp_dealloc */
|
||
|
0, /* tp_print */
|
||
|
(getattrfunc) rpmdbMIGetAttr, /* tp_getattr */
|
||
|
0, /* tp_setattr */
|
||
|
0, /* tp_compare */
|
||
|
0, /* tp_repr */
|
||
|
0, /* tp_as_number */
|
||
|
0, /* tp_as_sequence */
|
||
|
0, /* tp_as_mapping */
|
||
|
};
|
||
|
|
||
|
/*@}*/
|
||
|
|
||
|
/** \ingroup python
|
||
|
* \class rpmdb
|
||
|
* \brief A python rpmdb object represents an RPM database.
|
||
|
*
|
||
|
* Instances of the rpmdb object provide access to the records of a
|
||
|
* RPM database. The records are accessed by index number. To
|
||
|
* retrieve the header data in the RPM database, the rpmdb object is
|
||
|
* subscripted as you would access members of a list.
|
||
|
*
|
||
|
* The rpmdb class contains the following methods:
|
||
|
*
|
||
|
* - firstkey() Returns the index of the first record in the database.
|
||
|
* @deprecated Legacy, use rpmdbMatchIterator instead.
|
||
|
*
|
||
|
* - nextkey(index) Returns the index of the next record after "index" in the
|
||
|
* database.
|
||
|
* @param index current rpmdb location
|
||
|
* @deprecated Legacy, use rpmdbMatchIterator instead.
|
||
|
*
|
||
|
* - findbyfile(file) Returns a list of the indexes to records that own file
|
||
|
* "file".
|
||
|
* @param file absolute path to file
|
||
|
*
|
||
|
* - findbyname(name) Returns a list of the indexes to records for packages
|
||
|
* named "name".
|
||
|
* @param name package name
|
||
|
*
|
||
|
* - findbyprovides(dep) Returns a list of the indexes to records for packages
|
||
|
* that provide "dep".
|
||
|
* @param dep provided dependency string
|
||
|
*
|
||
|
* To obtain a rpmdb object, the opendb function in the rpm module
|
||
|
* must be called. The opendb function takes two optional arguments.
|
||
|
* The first optional argument is a boolean flag that specifies if the
|
||
|
* database is to be opened for read/write access or read-only access.
|
||
|
* The second argument specifies an alternate root directory for RPM
|
||
|
* to use.
|
||
|
*
|
||
|
* An example of opening a database and retrieving the first header in
|
||
|
* the database, then printing the name of the package that the header
|
||
|
* represents:
|
||
|
* \code
|
||
|
* import rpm
|
||
|
* rpmdb = rpm.opendb()
|
||
|
* index = rpmdb.firstkey()
|
||
|
* header = rpmdb[index]
|
||
|
* print header[rpm.RPMTAG_NAME]
|
||
|
* \endcode
|
||
|
* To print all of the packages in the database that match a package
|
||
|
* name, the code will look like this:
|
||
|
* \code
|
||
|
* import rpm
|
||
|
* rpmdb = rpm.opendb()
|
||
|
* indexes = rpmdb.findbyname("foo")
|
||
|
* for index in indexes:
|
||
|
* header = rpmdb[index]
|
||
|
* print "%s-%s-%s" % (header[rpm.RPMTAG_NAME],
|
||
|
* header[rpm.RPMTAG_VERSION],
|
||
|
* header[rpm.RPMTAG_RELEASE])
|
||
|
* \endcode
|
||
|
*/
|
||
|
|
||
|
/** \ingroup python
|
||
|
* \name Class: rpmdb
|
||
|
*/
|
||
|
/*@{*/
|
||
|
|
||
|
/**
|
||
|
*/
|
||
|
static PyObject * rpmdbFirst(rpmdbObject * s, PyObject * args) {
|
||
|
int first;
|
||
|
|
||
|
if (!PyArg_ParseTuple (args, "")) return NULL;
|
||
|
|
||
|
/* Acquire all offsets in one fell swoop. */
|
||
|
if (s->offsets == NULL || s->noffs <= 0) {
|
||
|
rpmdbMatchIterator mi;
|
||
|
Header h;
|
||
|
|
||
|
if (s->offsets)
|
||
|
free(s->offsets);
|
||
|
s->offsets = NULL;
|
||
|
s->noffs = 0;
|
||
|
mi = rpmdbInitIterator(s->db, RPMDBI_PACKAGES, NULL, 0);
|
||
|
while ((h = rpmdbNextIterator(mi)) != NULL) {
|
||
|
s->noffs++;
|
||
|
s->offsets = realloc(s->offsets, s->noffs * sizeof(s->offsets[0]));
|
||
|
s->offsets[s->noffs-1] = rpmdbGetIteratorOffset(mi);
|
||
|
}
|
||
|
rpmdbFreeIterator(mi);
|
||
|
}
|
||
|
|
||
|
s->offx = 0;
|
||
|
if (s->offsets != NULL && s->offx < s->noffs)
|
||
|
first = s->offsets[s->offx++];
|
||
|
else
|
||
|
first = 0;
|
||
|
|
||
|
if (!first) {
|
||
|
PyErr_SetString(pyrpmError, "cannot find first entry in database\n");
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
return Py_BuildValue("i", first);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
*/
|
||
|
static PyObject * rpmdbNext(rpmdbObject * s, PyObject * args) {
|
||
|
int where;
|
||
|
|
||
|
if (!PyArg_ParseTuple (args, "i", &where)) return NULL;
|
||
|
|
||
|
if (s->offsets == NULL || s->offx >= s->noffs) {
|
||
|
Py_INCREF(Py_None);
|
||
|
return Py_None;
|
||
|
}
|
||
|
|
||
|
where = s->offsets[s->offx++];
|
||
|
|
||
|
if (!where) {
|
||
|
Py_INCREF(Py_None);
|
||
|
return Py_None;
|
||
|
}
|
||
|
|
||
|
return Py_BuildValue("i", where);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
*/
|
||
|
static PyObject * handleDbResult(rpmdbMatchIterator mi) {
|
||
|
PyObject * list, *o;
|
||
|
|
||
|
list = PyList_New(0);
|
||
|
|
||
|
/* XXX FIXME: unnecessary header mallocs are side effect here */
|
||
|
if (mi != NULL) {
|
||
|
while (rpmdbNextIterator(mi)) {
|
||
|
PyList_Append(list, o=PyInt_FromLong(rpmdbGetIteratorOffset(mi)));
|
||
|
Py_DECREF(o);
|
||
|
}
|
||
|
rpmdbFreeIterator(mi);
|
||
|
}
|
||
|
|
||
|
return list;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
*/
|
||
|
static PyObject * rpmdbByFile(rpmdbObject * s, PyObject * args) {
|
||
|
char * str;
|
||
|
|
||
|
if (!PyArg_ParseTuple(args, "s", &str)) return NULL;
|
||
|
|
||
|
return handleDbResult(rpmdbInitIterator(s->db, RPMTAG_BASENAMES, str, 0));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
*/
|
||
|
static PyObject * rpmdbByName(rpmdbObject * s, PyObject * args) {
|
||
|
char * str;
|
||
|
|
||
|
if (!PyArg_ParseTuple(args, "s", &str)) return NULL;
|
||
|
|
||
|
return handleDbResult(rpmdbInitIterator(s->db, RPMTAG_NAME, str, 0));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
*/
|
||
|
static PyObject * rpmdbByProvides(rpmdbObject * s, PyObject * args) {
|
||
|
char * str;
|
||
|
|
||
|
if (!PyArg_ParseTuple(args, "s", &str)) return NULL;
|
||
|
|
||
|
return handleDbResult(rpmdbInitIterator(s->db, RPMTAG_PROVIDENAME, str, 0));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
*/
|
||
|
static rpmdbMIObject *
|
||
|
py_rpmdbInitIterator (rpmdbObject * s, PyObject * args) {
|
||
|
PyObject *index = NULL;
|
||
|
char *key = NULL;
|
||
|
int len = 0, tag = -1;
|
||
|
rpmdbMIObject * mio;
|
||
|
|
||
|
if (!PyArg_ParseTuple(args, "|Ozi", &index, &key, &len))
|
||
|
return NULL;
|
||
|
|
||
|
if (index == NULL)
|
||
|
tag = 0;
|
||
|
else if ((tag = tagNumFromPyObject (index)) == -1) {
|
||
|
PyErr_SetString(PyExc_TypeError, "unknown tag type");
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
mio = (rpmdbMIObject *) PyObject_NEW(rpmdbMIObject, &rpmdbMIType);
|
||
|
if (mio == NULL) {
|
||
|
PyErr_SetString(pyrpmError, "out of memory creating rpmdbMIObject");
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
mio->mi = rpmdbInitIterator(s->db, tag, key, len);
|
||
|
mio->db = s;
|
||
|
Py_INCREF (mio->db);
|
||
|
|
||
|
return mio;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
*/
|
||
|
static struct PyMethodDef rpmdbMethods[] = {
|
||
|
{"firstkey", (PyCFunction) rpmdbFirst, 1 },
|
||
|
{"nextkey", (PyCFunction) rpmdbNext, 1 },
|
||
|
{"findbyfile", (PyCFunction) rpmdbByFile, 1 },
|
||
|
{"findbyname", (PyCFunction) rpmdbByName, 1 },
|
||
|
{"findbyprovides", (PyCFunction) rpmdbByProvides, 1 },
|
||
|
{"match", (PyCFunction) py_rpmdbInitIterator, 1 },
|
||
|
{NULL, NULL} /* sentinel */
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
*/
|
||
|
static PyObject * rpmdbGetAttr(rpmdbObject * s, char * name) {
|
||
|
return Py_FindMethod(rpmdbMethods, (PyObject * ) s, name);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
*/
|
||
|
static void rpmdbDealloc(rpmdbObject * s) {
|
||
|
if (s->offsets) {
|
||
|
free(s->offsets);
|
||
|
}
|
||
|
if (s->db) {
|
||
|
rpmdbClose(s->db);
|
||
|
}
|
||
|
PyMem_DEL(s);
|
||
|
}
|
||
|
|
||
|
#ifndef DYINGSOON /* XXX OK, when? */
|
||
|
/**
|
||
|
*/
|
||
|
static int
|
||
|
rpmdbLength(rpmdbObject * s) {
|
||
|
int count = 0;
|
||
|
|
||
|
{ rpmdbMatchIterator mi;
|
||
|
|
||
|
/* RPMDBI_PACKAGES */
|
||
|
mi = rpmdbInitIterator(s->db, RPMDBI_PACKAGES, NULL, 0);
|
||
|
while (rpmdbNextIterator(mi) != NULL)
|
||
|
count++;
|
||
|
rpmdbFreeIterator(mi);
|
||
|
}
|
||
|
|
||
|
return count;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
*/
|
||
|
static hdrObject *
|
||
|
rpmdbSubscript(rpmdbObject * s, PyObject * key) {
|
||
|
int offset;
|
||
|
hdrObject * ho;
|
||
|
Header h;
|
||
|
rpmdbMatchIterator mi;
|
||
|
|
||
|
if (!PyInt_Check(key)) {
|
||
|
PyErr_SetString(PyExc_TypeError, "integer expected");
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
offset = (int) PyInt_AsLong(key);
|
||
|
|
||
|
mi = rpmdbInitIterator(s->db, RPMDBI_PACKAGES, &offset, sizeof(offset));
|
||
|
if (!(h = rpmdbNextIterator(mi))) {
|
||
|
rpmdbFreeIterator(mi);
|
||
|
PyErr_SetString(pyrpmError, "cannot read rpmdb entry");
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
ho = createHeaderObject(h);
|
||
|
headerFree(h, NULL);
|
||
|
|
||
|
return ho;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
*/
|
||
|
static PyMappingMethods rpmdbAsMapping = {
|
||
|
(inquiry) rpmdbLength, /* mp_length */
|
||
|
(binaryfunc) rpmdbSubscript, /* mp_subscript */
|
||
|
(objobjargproc)0, /* mp_ass_subscript */
|
||
|
};
|
||
|
#endif
|
||
|
|
||
|
/**
|
||
|
*/
|
||
|
PyTypeObject rpmdbType = {
|
||
|
PyObject_HEAD_INIT(NULL)
|
||
|
0, /* ob_size */
|
||
|
"rpmdb", /* tp_name */
|
||
|
sizeof(rpmdbObject), /* tp_size */
|
||
|
0, /* tp_itemsize */
|
||
|
(destructor) rpmdbDealloc, /* tp_dealloc */
|
||
|
0, /* tp_print */
|
||
|
(getattrfunc) rpmdbGetAttr, /* tp_getattr */
|
||
|
0, /* tp_setattr */
|
||
|
0, /* tp_compare */
|
||
|
0, /* tp_repr */
|
||
|
0, /* tp_as_number */
|
||
|
0, /* tp_as_sequence */
|
||
|
#ifndef DYINGSOON
|
||
|
&rpmdbAsMapping, /* tp_as_mapping */
|
||
|
#else
|
||
|
0,
|
||
|
#endif
|
||
|
};
|
||
|
|
||
|
rpmdb dbFromDb(rpmdbObject * db) {
|
||
|
return db->db;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
*/
|
||
|
rpmdbObject * rpmOpenDB(PyObject * self, PyObject * args) {
|
||
|
rpmdbObject * o;
|
||
|
char * root = "";
|
||
|
int forWrite = 0;
|
||
|
|
||
|
if (!PyArg_ParseTuple(args, "|is", &forWrite, &root)) return NULL;
|
||
|
|
||
|
o = PyObject_NEW(rpmdbObject, &rpmdbType);
|
||
|
o->db = NULL;
|
||
|
o->offx = 0;
|
||
|
o->noffs = 0;
|
||
|
o->offsets = NULL;
|
||
|
|
||
|
if (rpmdbOpen(root, &o->db, forWrite ? O_RDWR | O_CREAT: O_RDONLY, 0644)) {
|
||
|
char * errmsg = "cannot open database in %s";
|
||
|
char * errstr = NULL;
|
||
|
int errsize;
|
||
|
|
||
|
Py_DECREF(o);
|
||
|
/* PyErr_SetString should take varargs... */
|
||
|
errsize = strlen(errmsg) + *root == '\0' ? 15 /* "/var/lib/rpm" */ : strlen(root);
|
||
|
errstr = alloca(errsize);
|
||
|
snprintf(errstr, errsize, errmsg, *root == '\0' ? "/var/lib/rpm" : root);
|
||
|
PyErr_SetString(pyrpmError, errstr);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
return o;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
*/
|
||
|
PyObject * rebuildDB (PyObject * self, PyObject * args) {
|
||
|
char * root = "";
|
||
|
|
||
|
if (!PyArg_ParseTuple(args, "s", &root)) return NULL;
|
||
|
|
||
|
return Py_BuildValue("i", rpmdbRebuild(root));
|
||
|
}
|
||
|
|
||
|
/*@}*/
|
||
|
|