2 * \file python/rpmmodule.c
12 #include <glob.h> /* XXX rpmio.h */
13 #include <dirent.h> /* XXX rpmio.h */
20 #include "rpmio_internal.h"
23 extern int _rpmio_debug;
27 #defin PyObject_HEAD int _PyObjectHead
30 extern int mdfile(const char *fn, unsigned char *digest);
35 int rpmvercmp(const char * one, const char * two);
40 typedef struct rpmdbObject_s rpmdbObject;
44 typedef struct rpmdbMIObject_s rpmdbMIObject;
48 typedef struct rpmtransObject_s rpmtransObject;
52 typedef struct hdrObject_s hdrObject;
56 static PyObject * pyrpmError;
60 * \brief A python header object represents an RPM package header.
62 * All RPM packages have headers that provide metadata for the package.
63 * Header objects can be returned by database queries or loaded from a
64 * binary package on disk.
66 * The headerFromPackage function loads the package header from a
67 * package on disk. It returns a tuple of a "isSource" flag and the
68 * header object. The "isSource" flag is set to 1 if the package
69 * header was read from a source rpm or to 0 if the package header was
70 * read from a binary rpm.
76 * fd = os.open("/tmp/foo-1.0-1.i386.rpm", os.O_RDONLY)
77 * (header, isSource) = rpm.headerFromPackage(fd)
80 * The Python interface to the header data is quite elegant. It
81 * presents the data in a dictionary form. We'll take the header we
82 * just loaded and access the data within it:
84 * print header[rpm.RPMTAG_NAME]
85 * print header[rpm.RPMTAG_VERSION]
86 * print header[rpm.RPMTAG_RELEASE]
88 * in the case of our "foor-1.0-1.i386.rpm" package, this code would
95 * You make also access the header data by string name:
97 * print header['name']
99 * This method of access is a bit slower because the name must be
100 * translated into the tag number dynamically.
104 * \name Class: header
119 int_32 * uids, * gids;
120 unsigned short * rdevs;
121 unsigned short * modes;
126 static PyObject * hdrKeyList(hdrObject * s, PyObject * args) {
131 if (!PyArg_ParseTuple(args, "")) return NULL;
133 list = PyList_New(0);
135 iter = headerInitIterator(s->h);
136 while (headerNextIterator(iter, &tag, &type, NULL, NULL)) {
137 if (tag == HEADER_I18NTABLE) continue;
145 case RPM_STRING_ARRAY_TYPE:
146 case RPM_STRING_TYPE:
147 PyList_Append(list, o=PyInt_FromLong(tag));
152 headerFreeIterator(iter);
159 static PyObject * hdrUnload(hdrObject * s, PyObject * args, PyObject *keywords) {
163 static char *kwlist[] = { "legacyHeader", NULL};
165 if (!PyArg_ParseTupleAndKeywords(args, keywords, "|i", kwlist, &legacy))
171 h = headerCopy(s->h);
172 len = headerSizeof(h, 0);
173 buf = headerUnload(h);
175 len = headerSizeof(s->h, 0);
176 buf = headerUnload(s->h);
179 rc = PyString_FromStringAndSize(buf, len);
185 /* Returns a list of these tuple for each part which failed:
187 (attr_name, correctValue, currentValue)
189 It should be passwd the file number to verify.
193 static PyObject * hdrVerifyFile(hdrObject * s, PyObject * args) {
195 rpmVerifyAttrs verifyResult = 0;
196 PyObject * list, * tuple, * attrName;
202 struct tm * timeStruct;
204 if (!PyInt_Check(args)) {
205 PyErr_SetString(PyExc_TypeError, "integer expected");
209 fileNumber = (int) PyInt_AsLong(args);
211 if (rpmVerifyFile("", s->h, fileNumber, &verifyResult, RPMVERIFY_NONE)) {
216 list = PyList_New(0);
218 if (!verifyResult) return list;
221 headerGetEntry(s->h, RPMTAG_OLDFILENAMES, &type, (void **) &s->fileList,
225 lstat(s->fileList[fileNumber], &sb);
227 if (verifyResult & RPMVERIFY_MD5) {
229 headerGetEntry(s->h, RPMTAG_FILEMD5S, &type, (void **) &s->md5list,
233 if (mdfile(s->fileList[fileNumber], buf)) {
234 strcpy(buf, "(unknown)");
237 tuple = PyTuple_New(3);
238 attrName = PyString_FromString("checksum");
239 PyTuple_SetItem(tuple, 0, attrName);
240 PyTuple_SetItem(tuple, 1, PyString_FromString(s->md5list[fileNumber]));
241 PyTuple_SetItem(tuple, 2, PyString_FromString(buf));
242 PyList_Append(list, tuple);
246 if (verifyResult & RPMVERIFY_FILESIZE) {
248 headerGetEntry(s->h, RPMTAG_FILESIZES, &type, (void **) &s->fileSizes,
253 tuple = PyTuple_New(3);
254 attrName = PyString_FromString("size");
255 PyTuple_SetItem(tuple, 0, attrName);
257 sprintf(buf, "%d", 100);
258 PyTuple_SetItem(tuple, 1, PyString_FromString(buf));
259 sprintf(buf, "%ld", sb.st_size);
260 PyTuple_SetItem(tuple, 2, PyString_FromString(buf));
261 PyList_Append(list, tuple);
265 if (verifyResult & RPMVERIFY_LINKTO) {
267 headerGetEntry(s->h, RPMTAG_FILELINKTOS, &type, (void **) &s->linkList,
271 i = readlink(s->fileList[fileNumber], buf, sizeof(buf));
273 strcpy(buf, "(unknown)");
277 tuple = PyTuple_New(3);
278 attrName = PyString_FromString("link");
279 PyTuple_SetItem(tuple, 0, attrName);
280 PyTuple_SetItem(tuple, 1, PyString_FromString(s->linkList[fileNumber]));
281 PyTuple_SetItem(tuple, 2, PyString_FromString(buf));
282 PyList_Append(list, tuple);
286 if (verifyResult & RPMVERIFY_MTIME) {
288 headerGetEntry(s->h, RPMTAG_FILEMTIMES, &type, (void **) &s->mtimes,
292 tuple = PyTuple_New(3);
293 attrName = PyString_FromString("time");
294 PyTuple_SetItem(tuple, 0, attrName);
296 timeInt = sb.st_mtime;
297 timeStruct = localtime(&timeInt);
298 strftime(buf, sizeof(buf) - 1, "%c", timeStruct);
299 PyTuple_SetItem(tuple, 1, PyString_FromString(buf));
301 timeInt = s->mtimes[fileNumber];
302 timeStruct = localtime(&timeInt);
303 strftime(buf, sizeof(buf) - 1, "%c", timeStruct);
305 PyTuple_SetItem(tuple, 2, PyString_FromString(buf));
307 PyList_Append(list, tuple);
311 if (verifyResult & RPMVERIFY_RDEV) {
313 headerGetEntry(s->h, RPMTAG_FILERDEVS, &type, (void **) &s->rdevs,
317 tuple = PyTuple_New(3);
318 attrName = PyString_FromString("device");
320 PyTuple_SetItem(tuple, 0, attrName);
321 sprintf(buf, "0x%-4x", s->rdevs[fileNumber]);
322 PyTuple_SetItem(tuple, 1, PyString_FromString(buf));
323 sprintf(buf, "0x%-4x", (unsigned int) sb.st_rdev);
324 PyTuple_SetItem(tuple, 2, PyString_FromString(buf));
325 PyList_Append(list, tuple);
329 /* RPMVERIFY_USER and RPM_VERIFY_GROUP are handled wrong here, but rpmlib.a
330 doesn't do these correctly either. At least this is consistent. */
331 if (verifyResult & RPMVERIFY_USER) {
333 headerGetEntry(s->h, RPMTAG_FILEUIDS, &type, (void **) &s->uids,
337 tuple = PyTuple_New(3);
338 attrName = PyString_FromString("uid");
339 PyTuple_SetItem(tuple, 0, attrName);
340 sprintf(buf, "%d", s->uids[fileNumber]);
341 PyTuple_SetItem(tuple, 1, PyString_FromString(buf));
342 sprintf(buf, "%d", sb.st_uid);
343 PyTuple_SetItem(tuple, 2, PyString_FromString(buf));
344 PyList_Append(list, tuple);
348 if (verifyResult & RPMVERIFY_GROUP) {
350 headerGetEntry(s->h, RPMTAG_FILEGIDS, &type, (void **) &s->gids,
354 tuple = PyTuple_New(3);
355 attrName = PyString_FromString("gid");
356 PyTuple_SetItem(tuple, 0, attrName);
357 sprintf(buf, "%d", s->gids[fileNumber]);
358 PyTuple_SetItem(tuple, 1, PyString_FromString(buf));
359 sprintf(buf, "%d", sb.st_gid);
360 PyTuple_SetItem(tuple, 2, PyString_FromString(buf));
361 PyList_Append(list, tuple);
365 if (verifyResult & RPMVERIFY_MODE) {
367 headerGetEntry(s->h, RPMTAG_FILEMODES, &type, (void **) &s->modes,
371 tuple = PyTuple_New(3);
372 attrName = PyString_FromString("permissions");
373 PyTuple_SetItem(tuple, 0, attrName);
374 sprintf(buf, "0%-4o", s->modes[fileNumber]);
375 PyTuple_SetItem(tuple, 1, PyString_FromString(buf));
376 sprintf(buf, "0%-4o", sb.st_mode);
377 PyTuple_SetItem(tuple, 2, PyString_FromString(buf));
378 PyList_Append(list, tuple);
387 static PyObject * hdrExpandFilelist(hdrObject * s, PyObject * args) {
388 expandFilelist (s->h);
396 static PyObject * hdrCompressFilelist(hdrObject * s, PyObject * args) {
397 compressFilelist (s->h);
403 /* make a header with _all_ the tags we need */
406 static void mungeFilelist(Header h)
408 const char ** fileNames = NULL;
411 if (!headerIsEntry (h, RPMTAG_BASENAMES)
412 || !headerIsEntry (h, RPMTAG_DIRNAMES)
413 || !headerIsEntry (h, RPMTAG_DIRINDEXES))
416 rpmBuildFileList(h, &fileNames, &count);
418 if (fileNames == NULL || count <= 0)
421 headerAddEntry(h, RPMTAG_OLDFILENAMES, RPM_STRING_ARRAY_TYPE,
424 free((void *)fileNames);
429 static PyObject * hdrFullFilelist(hdrObject * s, PyObject * args) {
430 mungeFilelist (s->h);
438 static struct PyMethodDef hdrMethods[] = {
439 {"keys", (PyCFunction) hdrKeyList, 1 },
440 {"unload", (PyCFunction) hdrUnload, METH_VARARGS|METH_KEYWORDS },
441 {"verifyFile", (PyCFunction) hdrVerifyFile, 1 },
442 {"expandFilelist", (PyCFunction) hdrExpandFilelist, 1 },
443 {"compressFilelist", (PyCFunction) hdrCompressFilelist, 1 },
444 {"fullFilelist", (PyCFunction) hdrFullFilelist, 1 },
445 {NULL, NULL} /* sentinel */
450 static PyObject * hdrGetAttr(hdrObject * s, char * name) {
451 return Py_FindMethod(hdrMethods, (PyObject * ) s, name);
456 static void hdrDealloc(hdrObject * s) {
457 if (s->h) headerFree(s->h);
458 if (s->sigs) headerFree(s->sigs);
459 if (s->md5list) free(s->md5list);
460 if (s->fileList) free(s->fileList);
461 if (s->linkList) free(s->linkList);
467 static long tagNumFromPyObject (PyObject *item)
472 if (PyInt_Check(item)) {
473 return PyInt_AsLong(item);
474 } else if (PyString_Check(item)) {
475 str = PyString_AsString(item);
476 for (i = 0; i < rpmTagTableSize; i++)
477 if (!xstrcasecmp(rpmTagTable[i].name + 7, str)) break;
478 if (i < rpmTagTableSize) return rpmTagTable[i].val;
485 static PyObject * hdrSubscript(hdrObject * s, PyObject * item) {
486 int type, count, i, tag = -1;
488 PyObject * o, * metao;
493 struct headerSprintfExtension * ext = NULL;
494 const struct headerSprintfExtension * extensions = rpmHeaderFormats;
496 if (PyCObject_Check (item))
497 ext = PyCObject_AsVoidPtr(item);
499 tag = tagNumFromPyObject (item);
500 if (tag == -1 && PyString_Check(item)) {
501 /* if we still don't have the tag, go looking for the header
503 str = PyString_AsString(item);
504 while (extensions->name) {
505 if (extensions->type == HEADER_EXT_TAG
506 && !xstrcasecmp(extensions->name + 7, str)) {
507 (const struct headerSprintfExtension *) ext = extensions;
514 ext->u.tagFunction(s->h, &type, (const void **) &data, &count, &freeData);
517 PyErr_SetString(PyExc_KeyError, "unknown header tag");
521 if (!rpmPackageGetEntry(NULL, s->sigs, s->h, tag, &type, &data, &count))
529 case RPMTAG_OLDFILENAMES:
530 case RPMTAG_FILESIZES:
531 case RPMTAG_FILESTATES:
532 case RPMTAG_FILEMODES:
533 case RPMTAG_FILEUIDS:
534 case RPMTAG_FILEGIDS:
535 case RPMTAG_FILERDEVS:
536 case RPMTAG_FILEMTIMES:
537 case RPMTAG_FILEMD5S:
538 case RPMTAG_FILELINKTOS:
539 case RPMTAG_FILEFLAGS:
541 case RPMTAG_FILEUSERNAME:
542 case RPMTAG_FILEGROUPNAME:
547 case RPMTAG_DESCRIPTION:
556 o = PyString_FromStringAndSize(data, count);
560 if (count != 1 || forceArray) {
561 metao = PyList_New(0);
562 for (i = 0; i < count; i++) {
563 o = PyInt_FromLong(((int *) data)[i]);
564 PyList_Append(metao, o);
569 o = PyInt_FromLong(*((int *) data));
575 if (count != 1 || forceArray) {
576 metao = PyList_New(0);
577 for (i = 0; i < count; i++) {
578 o = PyInt_FromLong(((char *) data)[i]);
579 PyList_Append(metao, o);
584 o = PyInt_FromLong(*((char *) data));
589 if (count != 1 || forceArray) {
590 metao = PyList_New(0);
591 for (i = 0; i < count; i++) {
592 o = PyInt_FromLong(((short *) data)[i]);
593 PyList_Append(metao, o);
598 o = PyInt_FromLong(*((short *) data));
602 case RPM_STRING_ARRAY_TYPE:
605 metao = PyList_New(0);
606 for (i = 0; i < count; i++) {
607 o = PyString_FromString(stringArray[i]);
608 PyList_Append(metao, o);
615 case RPM_STRING_TYPE:
616 if (count != 1 || forceArray) {
619 metao = PyList_New(0);
620 for (i=0; i < count; i++) {
621 o = PyString_FromString(stringArray[i]);
622 PyList_Append(metao, o);
627 o = PyString_FromString(data);
634 PyErr_SetString(PyExc_TypeError, "unsupported type in header");
643 static PyMappingMethods hdrAsMapping = {
644 (inquiry) 0, /* mp_length */
645 (binaryfunc) hdrSubscript, /* mp_subscript */
646 (objobjargproc)0, /* mp_ass_subscript */
651 static PyTypeObject hdrType = {
652 PyObject_HEAD_INIT(&PyType_Type)
654 "header", /* tp_name */
655 sizeof(hdrObject), /* tp_size */
657 (destructor) hdrDealloc, /* tp_dealloc */
659 (getattrfunc) hdrGetAttr, /* tp_getattr */
663 0, /* tp_as_number */
664 0, /* tp_as_sequence */
665 &hdrAsMapping, /* tp_as_mapping */
671 * \class rpmdbMatchIterator
672 * \brief A python rpmdbMatchIterator object represents the result of an RPM
677 * \name Class: rpmdbMatchIterator
683 struct rpmdbObject_s {
693 struct rpmdbMIObject_s {
696 rpmdbMatchIterator mi;
702 rpmdbMINext(rpmdbMIObject * s, PyObject * args) {
703 /* XXX assume header? */
708 h = rpmdbNextIterator(s->mi);
714 ho = PyObject_NEW(hdrObject, &hdrType);
715 ho->h = headerLink(h);
717 ho->fileList = ho->linkList = ho->md5list = NULL;
718 ho->uids = ho->gids = ho->mtimes = ho->fileSizes = NULL;
719 ho->modes = ho->rdevs = NULL;
721 return (PyObject *) ho;
726 static struct PyMethodDef rpmdbMIMethods[] = {
727 {"next", (PyCFunction) rpmdbMINext, 1 },
728 {NULL, NULL} /* sentinel */
733 static PyObject * rpmdbMIGetAttr (rpmdbObject *s, char *name) {
734 return Py_FindMethod (rpmdbMIMethods, (PyObject *) s, name);
739 static void rpmdbMIDealloc(rpmdbMIObject * s) {
741 rpmdbFreeIterator(s->mi);
749 static PyTypeObject rpmdbMIType = {
750 PyObject_HEAD_INIT(&PyType_Type)
752 "rpmdbMatchIterator", /* tp_name */
753 sizeof(rpmdbMIObject), /* tp_size */
755 (destructor) rpmdbMIDealloc, /* tp_dealloc */
757 (getattrfunc) rpmdbMIGetAttr, /* tp_getattr */
761 0, /* tp_as_number */
762 0, /* tp_as_sequence */
763 0, /* tp_as_mapping */
770 * \brief A python rpmdb object represents an RPM database.
772 * Instances of the rpmdb object provide access to the records of a
773 * RPM database. The records are accessed by index number. To
774 * retrieve the header data in the RPM database, the rpmdb object is
775 * subscripted as you would access members of a list.
777 * The rpmdb class contains the following methods:
779 * - firstkey() Returns the index of the first record in the database.
780 * @deprecated Legacy, use rpmdbMatchIterator instead.
782 * - nextkey(index) Returns the index of the next record after "index" in the
784 * @param index current rpmdb location
785 * @deprecated Legacy, use rpmdbMatchIterator instead.
787 * - findbyfile(file) Returns a list of the indexes to records that own file
789 * @param file absolute path to file
791 * - findbyname(name) Returns a list of the indexes to records for packages
793 * @param name package name
795 * - findbyprovides(dep) Returns a list of the indexes to records for packages
796 * that provide "dep".
797 * @param dep provided dependency string
799 * To obtain a rpmdb object, the opendb function in the rpm module
800 * must be called. The opendb function takes two optional arguments.
801 * The first optional argument is a boolean flag that specifies if the
802 * database is to be opened for read/write access or read-only access.
803 * The second argument specifies an alternate root directory for RPM
806 * An example of opening a database and retrieving the first header in
807 * the database, then printing the name of the package that the header
811 * rpmdb = rpm.opendb()
812 * index = rpmdb.firstkey()
813 * header = rpmdb[index]
814 * print header[rpm.RPMTAG_NAME]
816 * To print all of the packages in the database that match a package
817 * name, the code will look like this:
820 * rpmdb = rpm.opendb()
821 * indexes = rpmdb.findbyname("foo")
822 * for index in indexes:
823 * header = rpmdb[index]
824 * print "%s-%s-%s" % (header[rpm.RPMTAG_NAME],
825 * header[rpm.RPMTAG_VERSION],
826 * header[rpm.RPMTAG_RELEASE])
837 static PyObject * rpmdbFirst(rpmdbObject * s, PyObject * args) {
840 if (!PyArg_ParseTuple (args, "")) return NULL;
842 /* Acquire all offsets in one fell swoop. */
843 if (s->offsets == NULL || s->noffs <= 0) {
844 rpmdbMatchIterator mi;
851 mi = rpmdbInitIterator(s->db, RPMDBI_PACKAGES, NULL, 0);
852 while ((h = rpmdbNextIterator(mi)) != NULL) {
854 s->offsets = realloc(s->offsets, s->noffs * sizeof(s->offsets[0]));
855 s->offsets[s->noffs-1] = rpmdbGetIteratorOffset(mi);
857 rpmdbFreeIterator(mi);
861 if (s->offsets != NULL && s->offx < s->noffs)
862 first = s->offsets[s->offx++];
867 PyErr_SetString(pyrpmError, "cannot find first entry in database\n");
871 return Py_BuildValue("i", first);
876 static PyObject * rpmdbNext(rpmdbObject * s, PyObject * args) {
879 if (!PyArg_ParseTuple (args, "i", &where)) return NULL;
881 if (s->offsets == NULL || s->offx >= s->noffs) {
886 where = s->offsets[s->offx++];
893 return Py_BuildValue("i", where);
898 static PyObject * handleDbResult(rpmdbMatchIterator mi) {
901 list = PyList_New(0);
903 /* XXX FIXME: unnecessary header mallocs are side effect here */
905 while (rpmdbNextIterator(mi)) {
906 PyList_Append(list, o=PyInt_FromLong(rpmdbGetIteratorOffset(mi)));
909 rpmdbFreeIterator(mi);
917 static PyObject * rpmdbByFile(rpmdbObject * s, PyObject * args) {
920 if (!PyArg_ParseTuple(args, "s", &str)) return NULL;
922 return handleDbResult(rpmdbInitIterator(s->db, RPMTAG_BASENAMES, str, 0));
927 static PyObject * rpmdbByName(rpmdbObject * s, PyObject * args) {
930 if (!PyArg_ParseTuple(args, "s", &str)) return NULL;
932 return handleDbResult(rpmdbInitIterator(s->db, RPMTAG_NAME, str, 0));
937 static PyObject * rpmdbByProvides(rpmdbObject * s, PyObject * args) {
940 if (!PyArg_ParseTuple(args, "s", &str)) return NULL;
942 return handleDbResult(rpmdbInitIterator(s->db, RPMTAG_PROVIDENAME, str, 0));
947 static rpmdbMIObject *
948 py_rpmdbInitIterator (rpmdbObject * s, PyObject * args) {
949 PyObject *index = NULL;
951 int len = 0, tag = -1;
954 if (!PyArg_ParseTuple(args, "|Ozi", &index, &key, &len))
959 else if ((tag = tagNumFromPyObject (index)) == -1) {
960 PyErr_SetString(PyExc_TypeError, "unknown tag type");
964 mio = (rpmdbMIObject *) PyObject_NEW(rpmdbMIObject, &rpmdbMIType);
966 PyErr_SetString(pyrpmError, "out of memory creating rpmdbMIObject");
970 mio->mi = rpmdbInitIterator(s->db, tag, key, len);
979 static struct PyMethodDef rpmdbMethods[] = {
980 {"firstkey", (PyCFunction) rpmdbFirst, 1 },
981 {"nextkey", (PyCFunction) rpmdbNext, 1 },
982 {"findbyfile", (PyCFunction) rpmdbByFile, 1 },
983 {"findbyname", (PyCFunction) rpmdbByName, 1 },
984 {"findbyprovides", (PyCFunction) rpmdbByProvides, 1 },
985 {"match", (PyCFunction) py_rpmdbInitIterator, 1 },
986 {NULL, NULL} /* sentinel */
991 static PyObject * rpmdbGetAttr(rpmdbObject * s, char * name) {
992 return Py_FindMethod(rpmdbMethods, (PyObject * ) s, name);
997 static void rpmdbDealloc(rpmdbObject * s) {
1011 rpmdbLength(rpmdbObject * s) {
1014 { rpmdbMatchIterator mi;
1016 /* RPMDBI_PACKAGES */
1017 mi = rpmdbInitIterator(s->db, RPMDBI_PACKAGES, NULL, 0);
1018 /* XXX FIXME: unnecessary header mallocs are side effect here */
1019 while (rpmdbNextIterator(mi) != NULL)
1021 rpmdbFreeIterator(mi);
1030 rpmdbSubscript(rpmdbObject * s, PyObject * key) {
1034 if (!PyInt_Check(key)) {
1035 PyErr_SetString(PyExc_TypeError, "integer expected");
1039 offset = (int) PyInt_AsLong(key);
1041 h = PyObject_NEW(hdrObject, &hdrType);
1044 { rpmdbMatchIterator mi;
1045 mi = rpmdbInitIterator(s->db, RPMDBI_PACKAGES, &offset, sizeof(offset));
1046 if ((h->h = rpmdbNextIterator(mi)) != NULL)
1047 h->h = headerLink(h->h);
1048 rpmdbFreeIterator(mi);
1050 h->fileList = h->linkList = h->md5list = NULL;
1051 h->uids = h->gids = h->mtimes = h->fileSizes = NULL;
1052 h->modes = h->rdevs = NULL;
1055 PyErr_SetString(pyrpmError, "cannot read rpmdb entry");
1064 static PyMappingMethods rpmdbAsMapping = {
1065 (inquiry) rpmdbLength, /* mp_length */
1066 (binaryfunc) rpmdbSubscript, /* mp_subscript */
1067 (objobjargproc)0, /* mp_ass_subscript */
1073 static PyTypeObject rpmdbType = {
1074 PyObject_HEAD_INIT(&PyType_Type)
1076 "rpmdb", /* tp_name */
1077 sizeof(rpmdbObject), /* tp_size */
1078 0, /* tp_itemsize */
1079 (destructor) rpmdbDealloc, /* tp_dealloc */
1081 (getattrfunc) rpmdbGetAttr, /* tp_getattr */
1085 0, /* tp_as_number */
1086 0, /* tp_as_sequence */
1088 &rpmdbAsMapping, /* tp_as_mapping */
1097 * \name Class: rpmtrans
1099 * \brief A python rpmtrans object represents an RPM transaction set.
1101 * The transaction set is the workhorse of RPM. It performs the
1102 * installation and upgrade of packages. The rpmtrans object is
1103 * instantiated by the TransactionSet function in the rpm module.
1105 * The TransactionSet function takes two optional arguments. The first
1106 * argument is the root path, the second is an open database to perform
1107 * the transaction set upon.
1109 * A rpmtrans object has the following methods:
1111 * - add(header,data,mode) Add a binary package to a transaction set.
1112 * @param header the header to be added
1113 * @param data user data that will be passed to the transaction callback
1114 * during transaction execution
1115 * @param mode optional argument that specifies if this package should
1116 * be installed ('i'), upgraded ('u'), or if it is just
1117 * available to the transaction when computing
1118 * dependencies but no action should be performed with it
1123 * - depcheck() Perform a dependency and conflict check on the
1124 * transaction set. After headers have been added to a
1125 * transaction set, a dependency check can be performed
1126 * to make sure that all package dependencies are
1128 * @return None If there are no unresolved dependencies
1129 * Otherwise a list of complex tuples is returned, one tuple per
1130 * unresolved dependency, with
1131 * The format of the dependency tuple is:
1132 * ((packageName, packageVersion, packageRelease),
1133 * (reqName, reqVersion),
1137 * packageName, packageVersion, packageRelease are the name,
1138 * version, and release of the package that has the unresolved
1139 * dependency or conflict.
1140 * The reqName and reqVersion are the name and version of the
1141 * requirement or conflict.
1142 * The needsFlags is a bitfield that describes the versioned
1143 * nature of a requirement or conflict. The constants
1144 * rpm.RPMDEP_SENSE_LESS, rpm.RPMDEP_SENSE_GREATER, and
1145 * rpm.RPMDEP_SENSE_EQUAL can be logical ANDed with the needsFlags
1146 * to get versioned dependency information.
1147 * suggestedPackage is a tuple if the dependency check was aware
1148 * of a package that solves this dependency problem when the
1149 * dependency check was run. Packages that are added to the
1150 * transaction set as "available" are examined during the
1151 * dependency check as possible dependency solvers. The tuple
1152 * contains two values, (header, suggestedName). These are set to
1153 * the header of the suggested package and its name, respectively.
1154 * If there is no known package to solve the dependency problem,
1155 * suggestedPackage is None.
1156 * The constants rpm.RPMDEP_SENSE_CONFLICTS and
1157 * rpm.RPMDEP_SENSE_REQUIRES are set to show a dependency as a
1158 * requirement or a conflict.
1160 * - run(flags,problemSetFilter,callback,data) Attempt to execute a
1161 * transaction set. After the transaction set has been populated
1162 * with install and upgrade actions, it can be executed by invoking
1164 * @param flags - modifies the behavior of the transaction set as it is
1165 * processed. The following values can be locical ORed
1167 * - rpm.RPMTRANS_FLAG_TEST - test mode, do not modify the RPM
1168 * database, change any files, or run any package scripts
1169 * - rpm.RPMTRANS_FLAG_BUILD_PROBS - only build a list of
1170 * problems encountered when attempting to run this transaction
1172 * - rpm.RPMTRANS_FLAG_NOSCRIPTS - do not execute package scripts
1173 * - rpm.RPMTRANS_FLAG_JUSTDB - only make changes to the rpm
1174 * database, do not modify files.
1175 * - rpm.RPMTRANS_FLAG_NOTRIGGERS - do not run trigger scripts
1176 * - rpm.RPMTRANS_FLAG_NODOCS - do not install files marked as %doc
1177 * - rpm.RPMTRANS_FLAG_ALLFILES - create all files, even if a
1178 * file is marked %config(missingok) and an upgrade is
1180 * - rpm.RPMTRANS_FLAG_KEEPOBSOLETE - do not remove obsoleted
1182 * @param problemSetFilter - control bit(s) to ignore classes of problems,
1184 * - rpm.RPMPROB_FILTER_IGNOREOS -
1185 * - rpm.RPMPROB_FILTER_IGNOREARCH -
1186 * - rpm.RPMPROB_FILTER_REPLACEPKG -
1187 * - rpm.RPMPROB_FILTER_FORCERELOCATE -
1188 * - rpm.RPMPROB_FILTER_REPLACENEWFILES -
1189 * - rpm.RPMPROB_FILTER_REPLACEOLDFILES -
1190 * - rpm.RPMPROB_FILTER_OLDPACKAGE -
1191 * - rpm.RPMPROB_FILTER_DISKSPACE -
1195 * \name Class: rpmtrans
1201 struct rpmtransObject_s {
1204 rpmTransactionSet ts;
1205 PyObject * keyList; /* keeps reference counts correct */
1211 static PyObject * rpmtransAdd(rpmtransObject * s, PyObject * args) {
1217 if (!PyArg_ParseTuple(args, "OO|s", &h, &key, &how)) return NULL;
1218 if (h->ob_type != &hdrType) {
1219 PyErr_SetString(PyExc_TypeError, "bad type for header argument");
1223 if (how && strcmp(how, "a") && strcmp(how, "u") && strcmp(how, "i")) {
1224 PyErr_SetString(PyExc_TypeError, "how argument must be \"u\", \"a\", or \"i\"");
1226 } else if (how && !strcmp(how, "u"))
1229 if (how && !strcmp(how, "a"))
1230 rpmtransAvailablePackage(s->ts, h->h, key);
1232 rpmtransAddPackage(s->ts, h->h, NULL, key, isUpgrade, NULL);
1234 /* This should increment the usage count for me */
1236 PyList_Append(s->keyList, key);
1245 static PyObject * rpmtransRemove(rpmtransObject * s, PyObject * args) {
1248 rpmdbMatchIterator mi;
1250 if (!PyArg_ParseTuple(args, "s", &name))
1253 /* XXX: Copied hack from ../lib/rpminstall.c, rpmErase() */
1254 mi = rpmdbInitIterator(s->dbo->db, RPMDBI_LABEL, name, 0);
1255 count = rpmdbGetIteratorCount(mi);
1257 PyErr_SetString(pyrpmError, "package not installed");
1259 } else { /* XXX: Note that we automatically choose to remove all matches */
1261 while ((h = rpmdbNextIterator(mi)) != NULL) {
1262 unsigned int recOffset = rpmdbGetIteratorOffset(mi);
1264 rpmtransRemovePackage(s->ts, recOffset);
1268 rpmdbFreeIterator(mi);
1276 static PyObject * rpmtransDepCheck(rpmtransObject * s, PyObject * args) {
1277 struct rpmDependencyConflict_s * conflicts;
1279 PyObject * list, * cf;
1282 if (!PyArg_ParseTuple(args, "")) return NULL;
1284 rpmdepCheck(s->ts, &conflicts, &numConflicts);
1286 list = PyList_New(0);
1288 /* XXX TODO: rpmlib-4.0.3 can return multiple suggested packages. */
1289 for (i = 0; i < numConflicts; i++) {
1290 cf = Py_BuildValue("((sss)(ss)iOi)", conflicts[i].byName,
1291 conflicts[i].byVersion, conflicts[i].byRelease,
1293 conflicts[i].needsName,
1294 conflicts[i].needsVersion,
1296 conflicts[i].needsFlags,
1297 conflicts[i].suggestedPackages ?
1298 conflicts[i].suggestedPackages[0] : Py_None,
1299 conflicts[i].sense);
1300 PyList_Append(list, (PyObject *) cf);
1304 conflicts = rpmdepFreeConflicts(conflicts, numConflicts);
1315 static PyObject * rpmtransOrder(rpmtransObject * s, PyObject * args) {
1316 if (!PyArg_ParseTuple(args, "")) return NULL;
1326 static PyObject * py_rpmtransGetKeys(rpmtransObject * s, PyObject * args) {
1327 const void **data = NULL;
1331 rpmtransGetKeys(s->ts, &data, &num);
1337 tuple = PyTuple_New(num);
1339 for (i = 0; i < num; i++) {
1340 PyObject *obj = (PyObject *) data[i];
1342 PyTuple_SetItem(tuple, i, obj);
1352 struct tsCallbackType {
1360 static Header transactionSetHeader = NULL;
1364 static void * tsCallback(const void * hd, const rpmCallbackType what,
1365 const unsigned long amount, const unsigned long total,
1366 const void * pkgKey, rpmCallbackData data) {
1367 struct tsCallbackType * cbInfo = data;
1368 PyObject * args, * result;
1371 const Header h = (Header) hd;
1373 if (cbInfo->pythonError) return NULL;
1375 if (!pkgKey) pkgKey = Py_None;
1376 transactionSetHeader = h;
1378 args = Py_BuildValue("(illOO)", what, amount, total, pkgKey, cbInfo->data);
1379 result = PyEval_CallObject(cbInfo->cb, args);
1383 cbInfo->pythonError = 1;
1387 if (what == RPMCALLBACK_INST_OPEN_FILE) {
1388 if (!PyArg_Parse(result, "i", &fd)) {
1389 cbInfo->pythonError = 1;
1398 if (what == RPMCALLBACK_INST_CLOSE_FILE) {
1409 static PyObject * rpmtransRun(rpmtransObject * s, PyObject * args) {
1410 int flags, ignoreSet;
1412 PyObject * list, * prob;
1413 rpmProblemSet probs;
1414 struct tsCallbackType cbInfo;
1416 if (!PyArg_ParseTuple(args, "iiOO", &flags, &ignoreSet, &cbInfo.cb,
1420 cbInfo.pythonError = 0;
1422 rc = rpmRunTransactions(s->ts, tsCallback, &cbInfo, NULL, &probs, flags,
1425 if (cbInfo.pythonError) {
1427 rpmProblemSetFree(probs);
1432 list = PyList_New(0);
1439 list = PyList_New(0);
1440 for (i = 0; i < probs->numProblems; i++) {
1441 rpmProblem myprob = probs->probs + i;
1442 prob = Py_BuildValue("s(isi)", rpmProblemString(myprob),
1446 PyList_Append(list, prob);
1450 rpmProblemSetFree(probs);
1457 static struct PyMethodDef rpmtransMethods[] = {
1458 {"add", (PyCFunction) rpmtransAdd, 1 },
1459 {"remove", (PyCFunction) rpmtransRemove, 1 },
1460 {"depcheck", (PyCFunction) rpmtransDepCheck, 1 },
1461 {"order", (PyCFunction) rpmtransOrder, 1 },
1462 {"getKeys", (PyCFunction) py_rpmtransGetKeys, 1 },
1463 {"run", (PyCFunction) rpmtransRun, 1 },
1464 {NULL, NULL} /* sentinel */
1469 static PyObject * rpmtransGetAttr(rpmtransObject * o, char * name) {
1470 return Py_FindMethod(rpmtransMethods, (PyObject *) o, name);
1475 static void rpmtransDealloc(PyObject * o) {
1476 rpmtransObject * trans = (void *) o;
1478 rpmtransFree(trans->ts);
1480 Py_DECREF(trans->dbo);
1482 if (trans->scriptFd) Fclose(trans->scriptFd);
1483 /* this will free the keyList, and decrement the ref count of all
1484 the items on the list as well :-) */
1485 Py_DECREF(trans->keyList);
1491 static int rpmtransSetAttr(rpmtransObject * o, char * name,
1495 if (!strcmp(name, "scriptFd")) {
1496 if (!PyArg_Parse(val, "i", &i)) return 0;
1498 PyErr_SetString(PyExc_TypeError, "bad file descriptor");
1501 o->scriptFd = fdDup(i);
1502 rpmtransSetScriptFd(o->ts, o->scriptFd);
1505 PyErr_SetString(PyExc_AttributeError, name);
1514 static PyTypeObject rpmtransType = {
1515 PyObject_HEAD_INIT(&PyType_Type)
1517 "rpmtrans", /* tp_name */
1518 sizeof(rpmtransObject), /* tp_size */
1519 0, /* tp_itemsize */
1520 (destructor) rpmtransDealloc, /* tp_dealloc */
1522 (getattrfunc) rpmtransGetAttr, /* tp_getattr */
1523 (setattrfunc) rpmtransSetAttr, /* tp_setattr */
1526 0, /* tp_as_number */
1527 0, /* tp_as_sequence */
1528 0, /* tp_as_mapping */
1540 static PyObject * rpmtransCreate(PyObject * self, PyObject * args) {
1542 rpmdbObject * db = NULL;
1543 char * rootPath = "/";
1545 if (!PyArg_ParseTuple(args, "|sO", &rootPath, &db)) return NULL;
1546 if (db && db->ob_type != &rpmdbType) {
1547 PyErr_SetString(PyExc_TypeError, "bad type for database argument");
1551 o = (void *) PyObject_NEW(rpmtransObject, &rpmtransType);
1556 o->ts = rpmtransCreateSet(db ? db->db : NULL, rootPath);
1557 o->keyList = PyList_New(0);
1564 static PyObject * doAddMacro(PyObject * self, PyObject * args) {
1567 if (!PyArg_ParseTuple(args, "ss", &name, &val))
1570 addMacro(NULL, name, NULL, val, RMIL_DEFAULT);
1578 static PyObject * doDelMacro(PyObject * self, PyObject * args) {
1581 if (!PyArg_ParseTuple(args, "s", &name))
1584 delMacro(NULL, name);
1592 static PyObject * archScore(PyObject * self, PyObject * args) {
1596 if (!PyArg_ParseTuple(args, "s", &arch))
1599 score = rpmMachineScore(RPM_MACHTABLE_INSTARCH, arch);
1601 return Py_BuildValue("i", score);
1606 static int psGetArchScore(Header h) {
1610 if (!headerGetEntry(h, RPMTAG_ARCH, &type, (void **) &pkgArch, &count) ||
1611 type == RPM_INT8_TYPE)
1614 return rpmMachineScore(RPM_MACHTABLE_INSTARCH, pkgArch);
1619 static int pkgCompareVer(void * first, void * second) {
1620 struct packageInfo ** a = first;
1621 struct packageInfo ** b = second;
1622 int ret, score1, score2;
1624 /* put packages w/o names at the end */
1625 if (!(*a)->name) return 1;
1626 if (!(*b)->name) return -1;
1628 ret = xstrcasecmp((*a)->name, (*b)->name);
1629 if (ret) return ret;
1630 score1 = psGetArchScore((*a)->h);
1631 if (!score1) return 1;
1632 score2 = psGetArchScore((*b)->h);
1633 if (!score2) return -1;
1634 if (score1 < score2) return -1;
1635 if (score1 > score2) return 1;
1636 return rpmVersionCompare((*b)->h, (*a)->h);
1641 static void pkgSort(struct pkgSet * psp) {
1645 qsort(psp->packages, psp->numPackages, sizeof(*psp->packages),
1646 (void *) pkgCompareVer);
1648 name = psp->packages[0]->name;
1650 psp->numPackages = 0;
1653 for (i = 1; i < psp->numPackages; i++) {
1654 if (!psp->packages[i]->name) break;
1655 if (!strcmp(psp->packages[i]->name, name))
1656 psp->packages[i]->name = NULL;
1658 name = psp->packages[i]->name;
1661 qsort(psp->packages, psp->numPackages, sizeof(*psp->packages),
1662 (void *) pkgCompareVer);
1664 for (i = 0; i < psp->numPackages; i++)
1665 if (!psp->packages[i]->name) break;
1666 psp->numPackages = i;
1671 static PyObject * findUpgradeSet(PyObject * self, PyObject * args) {
1672 PyObject * hdrList, * result;
1678 if (!PyArg_ParseTuple(args, "O|s", &hdrList, &root)) return NULL;
1680 if (!PyList_Check(hdrList)) {
1681 PyErr_SetString(PyExc_TypeError, "list of headers expected");
1685 list.numPackages = PyList_Size(hdrList);
1686 list.packages = alloca(sizeof(list.packages) * list.numPackages);
1687 for (i = 0; i < list.numPackages; i++) {
1688 hdr = (hdrObject *) PyList_GetItem(hdrList, i);
1689 if (hdr->ob_type != &hdrType) {
1690 PyErr_SetString(PyExc_TypeError, "list of headers expected");
1693 list.packages[i] = alloca(sizeof(struct packageInfo));
1694 list.packages[i]->h = hdr->h;
1695 list.packages[i]->selected = 0;
1696 list.packages[i]->data = hdr;
1698 headerGetEntry(hdr->h, RPMTAG_NAME, NULL,
1699 (void **) &list.packages[i]->name, NULL);
1704 if (ugFindUpgradePackages(&list, root)) {
1705 PyErr_SetString(pyrpmError, "error during upgrade check");
1709 result = PyList_New(0);
1710 for (i = 0; i < list.numPackages; i++) {
1711 if (list.packages[i]->selected) {
1712 PyList_Append(result, list.packages[i]->data);
1713 /* Py_DECREF(list.packages[i]->data); */
1722 static PyObject * rpmHeaderFromPackage(PyObject * self, PyObject * args) {
1731 if (!PyArg_ParseTuple(args, "i", &rawFd)) return NULL;
1734 rc = rpmReadPackageInfo(fd, &sigs, &header);
1740 h = (hdrObject *) PyObject_NEW(PyObject, &hdrType);
1743 h->fileList = h->linkList = h->md5list = NULL;
1744 h->uids = h->gids = h->mtimes = h->fileSizes = NULL;
1745 h->modes = h->rdevs = NULL;
1746 if (headerIsEntry(header, RPMTAG_SOURCEPACKAGE))
1750 case RPMRC_BADMAGIC:
1752 h = (hdrObject *) Py_None;
1756 case RPMRC_SHORTREAD:
1758 PyErr_SetString(pyrpmError, "error reading package");
1762 return Py_BuildValue("(Ni)", h, isSource);
1767 static PyObject * hdrLoad(PyObject * self, PyObject * args) {
1768 char * obj, * copy=NULL;
1773 if (!PyArg_ParseTuple(args, "s#", &obj, &len)) return NULL;
1777 PyErr_SetString(pyrpmError, "out of memory");
1781 memcpy (copy, obj, len);
1783 hdr = headerLoad(copy);
1785 PyErr_SetString(pyrpmError, "bad header");
1788 compressFilelist (hdr);
1789 providePackageNVR (hdr);
1791 h = (hdrObject *) PyObject_NEW(PyObject, &hdrType);
1794 h->fileList = h->linkList = h->md5list = NULL;
1795 h->uids = h->gids = h->mtimes = h->fileSizes = NULL;
1796 h->modes = h->rdevs = NULL;
1798 return (PyObject *) h;
1803 static PyObject * rpmInitDB(PyObject * self, PyObject * args) {
1807 if (!PyArg_ParseTuple(args, "i|s", &forWrite, &root)) return NULL;
1809 if (rpmdbInit(root, forWrite ? O_RDWR | O_CREAT: O_RDONLY)) {
1810 char * errmsg = "cannot initialize database in %s";
1811 char * errstr = NULL;
1814 errsize = strlen(errmsg) + strlen(root);
1815 errstr = alloca(errsize);
1816 snprintf(errstr, errsize, errmsg, root);
1817 PyErr_SetString(pyrpmError, errstr);
1827 static rpmdbObject * rpmOpenDB(PyObject * self, PyObject * args) {
1832 if (!PyArg_ParseTuple(args, "|is", &forWrite, &root)) return NULL;
1834 o = PyObject_NEW(rpmdbObject, &rpmdbType);
1840 if (rpmdbOpen(root, &o->db, forWrite ? O_RDWR | O_CREAT: O_RDONLY, 0644)) {
1841 char * errmsg = "cannot open database in %s";
1842 char * errstr = NULL;
1846 /* PyErr_SetString should take varargs... */
1847 errsize = strlen(errmsg) + *root == '\0' ? 15 /* "/var/lib/rpm" */ : strlen(root);
1848 errstr = alloca(errsize);
1849 snprintf(errstr, errsize, errmsg, *root == '\0' ? "/var/lib/rpm" : root);
1850 PyErr_SetString(pyrpmError, errstr);
1859 static PyObject * rebuildDB (PyObject * self, PyObject * args) {
1862 if (!PyArg_ParseTuple(args, "s", &root)) return NULL;
1864 return Py_BuildValue("i", rpmdbRebuild(root));
1869 static PyObject * rpmReadHeaders (FD_t fd) {
1875 PyErr_SetFromErrno(pyrpmError);
1879 list = PyList_New(0);
1880 Py_BEGIN_ALLOW_THREADS
1881 header = headerRead(fd, HEADER_MAGIC_YES);
1883 Py_END_ALLOW_THREADS
1885 compressFilelist (header);
1886 providePackageNVR (header);
1887 h = (hdrObject *) PyObject_NEW(PyObject, &hdrType);
1890 h->fileList = h->linkList = h->md5list = NULL;
1891 h->uids = h->gids = h->mtimes = h->fileSizes = NULL;
1892 h->modes = h->rdevs = NULL;
1893 if (PyList_Append(list, (PyObject *) h)) {
1901 Py_BEGIN_ALLOW_THREADS
1902 header = headerRead(fd, HEADER_MAGIC_YES);
1903 Py_END_ALLOW_THREADS
1911 static PyObject * rpmHeaderFromFD(PyObject * self, PyObject * args) {
1916 if (!PyArg_ParseTuple(args, "i", &fileno)) return NULL;
1919 list = rpmReadHeaders (fd);
1927 static PyObject * rpmHeaderFromFile(PyObject * self, PyObject * args) {
1932 if (!PyArg_ParseTuple(args, "s", &filespec)) return NULL;
1933 fd = Fopen(filespec, "r.fdio");
1936 PyErr_SetFromErrno(pyrpmError);
1940 list = rpmReadHeaders (fd);
1947 * This assumes the order of list matches the order of the new headers, and
1948 * throws an exception if that isn't true.
1950 static int rpmMergeHeaders(PyObject * list, FD_t fd, int matchTag) {
1952 HeaderIterator iter;
1953 int_32 * newMatch, * oldMatch;
1959 Py_BEGIN_ALLOW_THREADS
1960 newH = headerRead(fd, HEADER_MAGIC_YES);
1962 Py_END_ALLOW_THREADS
1964 if (!headerGetEntry(newH, matchTag, NULL, (void **) &newMatch, NULL)) {
1965 PyErr_SetString(pyrpmError, "match tag missing in new header");
1969 ho = (hdrObject *) PyList_GetItem(list, count++);
1972 if (!headerGetEntry(ho->h, matchTag, NULL, (void **) &oldMatch, NULL)) {
1973 PyErr_SetString(pyrpmError, "match tag missing in new header");
1977 if (*newMatch != *oldMatch) {
1978 PyErr_SetString(pyrpmError, "match tag mismatch");
1982 if (ho->sigs) headerFree(ho->sigs);
1983 if (ho->md5list) free(ho->md5list);
1984 if (ho->fileList) free(ho->fileList);
1985 if (ho->linkList) free(ho->linkList);
1989 ho->fileList = NULL;
1990 ho->linkList = NULL;
1992 iter = headerInitIterator(newH);
1994 while (headerNextIterator(iter, &tag, &type, (void *) &p, &c)) {
1995 /* could be dupes */
1996 headerRemoveEntry(ho->h, tag);
1997 headerAddEntry(ho->h, tag, type, p, c);
1998 headerFreeData(p, type);
2001 headerFreeIterator(iter);
2003 Py_BEGIN_ALLOW_THREADS
2004 newH = headerRead(fd, HEADER_MAGIC_YES);
2005 Py_END_ALLOW_THREADS
2011 static PyObject * rpmMergeHeadersFromFD(PyObject * self, PyObject * args) {
2018 if (!PyArg_ParseTuple(args, "Oii", &list, &fileno, &matchTag)) return NULL;
2020 if (!PyList_Check(list)) {
2021 PyErr_SetString(PyExc_TypeError, "first parameter must be a list");
2027 rc = rpmMergeHeaders (list, fd, matchTag);
2040 static PyObject * errorCB = NULL, * errorData = NULL;
2044 static void errorcb (void)
2046 PyObject * result, * args = NULL;
2049 args = Py_BuildValue("(O)", errorData);
2051 result = PyEval_CallObject(errorCB, args);
2054 if (result == NULL) {
2063 static PyObject * errorSetCallback (PyObject * self, PyObject * args) {
2064 if (errorCB != NULL) {
2065 Py_DECREF (errorCB);
2069 if (errorData != NULL) {
2070 Py_DECREF (errorData);
2074 if (!PyArg_ParseTuple(args, "O|O", &errorCB, &errorData)) return NULL;
2076 /* if we're getting a void*, set the error callback to this. */
2077 /* also, we can possibly decref any python callbacks we had */
2078 /* and set them to NULL. */
2079 if (PyCObject_Check (errorCB)) {
2080 rpmErrorSetCallback (PyCObject_AsVoidPtr(errorCB));
2082 Py_XDECREF (errorCB);
2083 Py_XDECREF (errorData);
2092 if (!PyCallable_Check (errorCB)) {
2093 PyErr_SetString(PyExc_TypeError, "parameter must be callable");
2097 Py_INCREF (errorCB);
2098 Py_XINCREF (errorData);
2100 return PyCObject_FromVoidPtr(rpmErrorSetCallback (errorcb), NULL);
2105 static PyObject * errorString (PyObject * self, PyObject * args) {
2106 return PyString_FromString(rpmErrorString ());
2111 static PyObject * versionCompare (PyObject * self, PyObject * args) {
2112 hdrObject * h1, * h2;
2114 if (!PyArg_ParseTuple(args, "O!O!", &hdrType, &h1, &hdrType, &h2)) return NULL;
2116 return Py_BuildValue("i", rpmVersionCompare(h1->h, h2->h));
2121 static PyObject * labelCompare (PyObject * self, PyObject * args) {
2122 char *v1, *r1, *e1, *v2, *r2, *e2;
2125 if (!PyArg_ParseTuple(args, "(zzz)(zzz)",
2127 &e2, &v2, &r2)) return NULL;
2130 return Py_BuildValue("i", 1);
2132 return Py_BuildValue("i", -1);
2133 else if (e1 && e2) {
2138 return Py_BuildValue("i", -1);
2140 return Py_BuildValue("i", 1);
2143 rc = rpmvercmp(v1, v2);
2145 return Py_BuildValue("i", rc);
2147 return Py_BuildValue("i", rpmvercmp(r1, r2));
2152 static PyObject * checkSig (PyObject * self, PyObject * args) {
2157 if (PyArg_ParseTuple(args, "si", &filename, &flags)) {
2161 rc = rpmCheckSig(flags, av);
2163 return Py_BuildValue("i", rc);
2166 /* hack to get the current header that's in the transaction set */
2169 static PyObject * getTsHeader (PyObject * self, PyObject * args) {
2172 if (transactionSetHeader) {
2173 h = (hdrObject *) PyObject_NEW(PyObject, &hdrType);
2174 h->h = headerLink(transactionSetHeader);
2176 h->fileList = h->linkList = h->md5list = NULL;
2177 h->uids = h->gids = h->mtimes = h->fileSizes = NULL;
2178 h->modes = h->rdevs = NULL;
2179 return (PyObject *) h;
2182 return (PyObject *) Py_None;
2187 typedef struct FDlist_t FDlist;
2200 static FDlist *fdhead = NULL;
2204 static FDlist *fdtail = NULL;
2208 static int closeCallback(FILE * f) {
2209 FDlist *node, *last;
2211 printf ("close callback on %p\n", f);
2223 last->next = node->next;
2225 fdhead = node->next;
2226 printf ("closing %s %p\n", node->note, node->fd);
2228 node->fd = fdLink(node->fd, "closeCallback");
2231 node->fd = fdFree(node->fd, "closeCallback");
2239 static PyObject * doFopen(PyObject * self, PyObject * args) {
2240 char * path, * mode;
2243 if (!PyArg_ParseTuple(args, "ss", &path, &mode))
2246 node = malloc (sizeof(FDlist));
2248 node->fd = Fopen(path, mode);
2249 node->fd = fdLink(node->fd, "doFopen");
2250 node->note = strdup (path);
2253 PyErr_SetFromErrno(pyrpmError);
2258 if (Ferror(node->fd)) {
2259 const char *err = Fstrerror(node->fd);
2262 PyErr_SetString(pyrpmError, err);
2266 node->f = fdGetFp(node->fd);
2267 printf ("opening %s fd = %p f = %p\n", node->note, node->fd, node->f);
2269 PyErr_SetString(pyrpmError, "FD_t has no FILE*");
2276 fdhead = fdtail = node;
2277 } else if (fdtail) {
2278 fdtail->next = node;
2284 return PyFile_FromFile (node->f, path, mode, closeCallback);
2289 static PyMethodDef rpmModuleMethods[] = {
2290 { "TransactionSet", (PyCFunction) rpmtransCreate, METH_VARARGS, NULL },
2291 { "addMacro", (PyCFunction) doAddMacro, METH_VARARGS, NULL },
2292 { "delMacro", (PyCFunction) doDelMacro, METH_VARARGS, NULL },
2293 { "archscore", (PyCFunction) archScore, METH_VARARGS, NULL },
2294 { "findUpgradeSet", (PyCFunction) findUpgradeSet, METH_VARARGS, NULL },
2295 { "headerFromPackage", (PyCFunction) rpmHeaderFromPackage, METH_VARARGS, NULL },
2296 { "headerLoad", (PyCFunction) hdrLoad, METH_VARARGS, NULL },
2297 { "initdb", (PyCFunction) rpmInitDB, METH_VARARGS, NULL },
2298 { "opendb", (PyCFunction) rpmOpenDB, METH_VARARGS, NULL },
2299 { "rebuilddb", (PyCFunction) rebuildDB, METH_VARARGS, NULL },
2300 { "mergeHeaderListFromFD", (PyCFunction) rpmMergeHeadersFromFD, METH_VARARGS, NULL },
2301 { "readHeaderListFromFD", (PyCFunction) rpmHeaderFromFD, METH_VARARGS, NULL },
2302 { "readHeaderListFromFile", (PyCFunction) rpmHeaderFromFile, METH_VARARGS, NULL },
2303 { "errorSetCallback", (PyCFunction) errorSetCallback, METH_VARARGS, NULL },
2304 { "errorString", (PyCFunction) errorString, METH_VARARGS, NULL },
2305 { "versionCompare", (PyCFunction) versionCompare, METH_VARARGS, NULL },
2306 { "labelCompare", (PyCFunction) labelCompare, METH_VARARGS, NULL },
2307 { "checksig", (PyCFunction) checkSig, METH_VARARGS, NULL },
2308 { "getTransactionCallbackHeader", (PyCFunction) getTsHeader, METH_VARARGS, NULL },
2309 /* { "Fopen", (PyCFunction) doFopen, METH_VARARGS, NULL }, */
2315 void initrpm(void) {
2316 PyObject * m, * d, *o, * tag = NULL, * dict;
2318 const struct headerSprintfExtension * extensions = rpmHeaderFormats;
2319 struct headerSprintfExtension * ext;
2321 /* _rpmio_debug = -1; */
2322 rpmReadConfigFiles(NULL, NULL);
2324 m = Py_InitModule("rpm", rpmModuleMethods);
2325 d = PyModule_GetDict(m);
2327 pyrpmError = PyString_FromString("rpm.error");
2328 PyDict_SetItemString(d, "error", pyrpmError);
2329 Py_DECREF(pyrpmError);
2331 dict = PyDict_New();
2333 for (i = 0; i < rpmTagTableSize; i++) {
2334 tag = PyInt_FromLong(rpmTagTable[i].val);
2335 PyDict_SetItemString(d, (char *) rpmTagTable[i].name, tag);
2337 PyDict_SetItem(dict, tag, o=PyString_FromString(rpmTagTable[i].name + 7));
2341 while (extensions->name) {
2342 if (extensions->type == HEADER_EXT_TAG) {
2343 (const struct headerSprintfExtension *) ext = extensions;
2344 PyDict_SetItemString(d, extensions->name, o=PyCObject_FromVoidPtr(ext, NULL));
2346 PyDict_SetItem(dict, tag, o=PyString_FromString(ext->name + 7));
2352 PyDict_SetItemString(d, "tagnames", dict);
2356 #define REGISTER_ENUM(val) \
2357 PyDict_SetItemString(d, #val, o=PyInt_FromLong( val )); \
2360 REGISTER_ENUM(RPMFILE_STATE_NORMAL);
2361 REGISTER_ENUM(RPMFILE_STATE_REPLACED);
2362 REGISTER_ENUM(RPMFILE_STATE_NOTINSTALLED);
2363 REGISTER_ENUM(RPMFILE_STATE_NETSHARED);
2365 REGISTER_ENUM(RPMFILE_CONFIG);
2366 REGISTER_ENUM(RPMFILE_DOC);
2367 REGISTER_ENUM(RPMFILE_MISSINGOK);
2368 REGISTER_ENUM(RPMFILE_NOREPLACE);
2369 REGISTER_ENUM(RPMFILE_GHOST);
2370 REGISTER_ENUM(RPMFILE_LICENSE);
2371 REGISTER_ENUM(RPMFILE_README);
2373 REGISTER_ENUM(RPMDEP_SENSE_REQUIRES);
2374 REGISTER_ENUM(RPMDEP_SENSE_CONFLICTS);
2376 REGISTER_ENUM(RPMSENSE_SERIAL);
2377 REGISTER_ENUM(RPMSENSE_LESS);
2378 REGISTER_ENUM(RPMSENSE_GREATER);
2379 REGISTER_ENUM(RPMSENSE_EQUAL);
2380 REGISTER_ENUM(RPMSENSE_PREREQ);
2381 REGISTER_ENUM(RPMSENSE_INTERP);
2382 REGISTER_ENUM(RPMSENSE_SCRIPT_PRE);
2383 REGISTER_ENUM(RPMSENSE_SCRIPT_POST);
2384 REGISTER_ENUM(RPMSENSE_SCRIPT_PREUN);
2385 REGISTER_ENUM(RPMSENSE_SCRIPT_POSTUN);
2386 REGISTER_ENUM(RPMSENSE_SCRIPT_VERIFY);
2387 REGISTER_ENUM(RPMSENSE_FIND_REQUIRES);
2388 REGISTER_ENUM(RPMSENSE_FIND_PROVIDES);
2389 REGISTER_ENUM(RPMSENSE_TRIGGERIN);
2390 REGISTER_ENUM(RPMSENSE_TRIGGERUN);
2391 REGISTER_ENUM(RPMSENSE_TRIGGERPOSTUN);
2392 REGISTER_ENUM(RPMSENSE_MULTILIB);
2393 REGISTER_ENUM(RPMSENSE_SCRIPT_PREP);
2394 REGISTER_ENUM(RPMSENSE_SCRIPT_BUILD);
2395 REGISTER_ENUM(RPMSENSE_SCRIPT_INSTALL);
2396 REGISTER_ENUM(RPMSENSE_SCRIPT_CLEAN);
2397 REGISTER_ENUM(RPMSENSE_RPMLIB);
2398 REGISTER_ENUM(RPMSENSE_TRIGGERPREIN);
2400 REGISTER_ENUM(RPMTRANS_FLAG_TEST);
2401 REGISTER_ENUM(RPMTRANS_FLAG_BUILD_PROBS);
2402 REGISTER_ENUM(RPMTRANS_FLAG_NOSCRIPTS);
2403 REGISTER_ENUM(RPMTRANS_FLAG_JUSTDB);
2404 REGISTER_ENUM(RPMTRANS_FLAG_NOTRIGGERS);
2405 REGISTER_ENUM(RPMTRANS_FLAG_NODOCS);
2406 REGISTER_ENUM(RPMTRANS_FLAG_ALLFILES);
2407 REGISTER_ENUM(RPMTRANS_FLAG_KEEPOBSOLETE);
2408 REGISTER_ENUM(RPMTRANS_FLAG_MULTILIB);
2410 REGISTER_ENUM(RPMPROB_FILTER_IGNOREOS);
2411 REGISTER_ENUM(RPMPROB_FILTER_IGNOREARCH);
2412 REGISTER_ENUM(RPMPROB_FILTER_REPLACEPKG);
2413 REGISTER_ENUM(RPMPROB_FILTER_FORCERELOCATE);
2414 REGISTER_ENUM(RPMPROB_FILTER_REPLACENEWFILES);
2415 REGISTER_ENUM(RPMPROB_FILTER_REPLACEOLDFILES);
2416 REGISTER_ENUM(RPMPROB_FILTER_OLDPACKAGE);
2417 REGISTER_ENUM(RPMPROB_FILTER_DISKSPACE);
2418 REGISTER_ENUM(RPMPROB_FILTER_DISKNODES);
2420 REGISTER_ENUM(RPMCALLBACK_INST_PROGRESS);
2421 REGISTER_ENUM(RPMCALLBACK_INST_START);
2422 REGISTER_ENUM(RPMCALLBACK_INST_OPEN_FILE);
2423 REGISTER_ENUM(RPMCALLBACK_INST_CLOSE_FILE);
2424 REGISTER_ENUM(RPMCALLBACK_TRANS_PROGRESS);
2425 REGISTER_ENUM(RPMCALLBACK_TRANS_START);
2426 REGISTER_ENUM(RPMCALLBACK_TRANS_STOP);
2427 REGISTER_ENUM(RPMCALLBACK_UNINST_PROGRESS);
2428 REGISTER_ENUM(RPMCALLBACK_UNINST_START);
2429 REGISTER_ENUM(RPMCALLBACK_UNINST_STOP);
2431 REGISTER_ENUM(RPMPROB_BADARCH);
2432 REGISTER_ENUM(RPMPROB_BADOS);
2433 REGISTER_ENUM(RPMPROB_PKG_INSTALLED);
2434 REGISTER_ENUM(RPMPROB_BADRELOCATE);
2435 REGISTER_ENUM(RPMPROB_REQUIRES);
2436 REGISTER_ENUM(RPMPROB_CONFLICT);
2437 REGISTER_ENUM(RPMPROB_NEW_FILE_CONFLICT);
2438 REGISTER_ENUM(RPMPROB_FILE_CONFLICT);
2439 REGISTER_ENUM(RPMPROB_OLDPACKAGE);
2440 REGISTER_ENUM(RPMPROB_DISKSPACE);
2441 REGISTER_ENUM(RPMPROB_DISKNODES);
2442 REGISTER_ENUM(RPMPROB_BADPRETRANS);
2444 REGISTER_ENUM(CHECKSIG_PGP);
2445 REGISTER_ENUM(CHECKSIG_GPG);
2446 REGISTER_ENUM(CHECKSIG_MD5);