"Fossies" - the Fresh Open Source Software Archive

Member "rpm-4.15.1/python/rpmts-py.c" (4 Nov 2019, 32677 Bytes) of package /linux/misc/rpm-4.15.1.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "rpmts-py.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 4.14.2.1_vs_4.15.0-rc1.

    1 #include "rpmsystem-py.h"
    2 
    3 #include <fcntl.h>
    4 
    5 #include <rpm/rpmlib.h> /* rpmReadPackageFile, headerCheck */
    6 #include <rpm/rpmtag.h>
    7 #include <rpm/rpmpgp.h>
    8 #include <rpm/rpmdb.h>
    9 #include <rpm/rpmbuild.h>
   10 
   11 #include "header-py.h"
   12 #include "rpmds-py.h"   /* XXX for rpmdsNew */
   13 #include "rpmfd-py.h"
   14 #include "rpmkeyring-py.h"
   15 #include "rpmfi-py.h"   /* XXX for rpmfiNew */
   16 #include "rpmmi-py.h"
   17 #include "rpmii-py.h"
   18 #include "rpmps-py.h"
   19 #include "rpmte-py.h"
   20 #include "rpmts-py.h"
   21 
   22 /** \ingroup python
   23  * \name Class: Rpmts
   24  * \class Rpmts
   25  * \brief A python rpm.ts object represents an RPM transaction set.
   26  *
   27  * The transaction set is the workhorse of RPM.  It performs the
   28  * installation and upgrade of packages.  The rpm.ts object is
   29  * instantiated by the TransactionSet function in the rpm module.
   30  *
   31  * The TransactionSet function takes two optional arguments. The first
   32  * argument is the root path. The second is the verify signature disable flags,
   33  * a set of the following bits:
   34  *
   35  * -    rpm.RPMVSF_NOHDRCHK if set, don't check rpmdb headers
   36  * -    rpm.RPMVSF_NEEDPAYLOAD  if not set, check header+payload (if possible)
   37  * -    rpm.RPMVSF_NOSHA1HEADER if set, don't check header SHA1 digest
   38  * -    rpm.RPMVSF_NODSAHEADER  if set, don't check header DSA signature
   39  * -    rpm.RPMVSF_NOMD5    if set, don't check header+payload MD5 digest
   40  * -    rpm.RPMVSF_NODSA    if set, don't check header+payload DSA signature
   41  * -    rpm.RPMVSF_NORSA    if set, don't check header+payload RSA signature
   42  *
   43  * For convenience, there are the following masks:
   44  * -    rpm.RPMVSF_MASK_NODIGESTS       if set, don't check digest(s).
   45  * -    rpm.RPMVSF_MASK_NOSIGNATURES    if set, don't check signature(s).
   46  *
   47  * A rpm.ts object has the following methods:
   48  *
   49  * - addInstall(hdr,data,mode)  Add an install element to a transaction set.
   50  * @param hdr   the header to be added
   51  * @param data  user data that will be passed to the transaction callback
   52  *      during transaction execution
   53  * @param mode  optional argument that specifies if this package should
   54  *      be installed ('i'), upgraded ('u').
   55  *
   56  * - addErase(name) Add an erase element to a transaction set.
   57  * @param name  the package name to be erased
   58  *
   59  * - check()    Perform a dependency check on the transaction set. After
   60  *      headers have been added to a transaction set, a dependency
   61  *      check can be performed to make sure that all package
   62  *      dependencies are satisfied.
   63  * @return  None If there are no unresolved dependencies
   64  *      Otherwise a list of complex tuples is returned, one tuple per
   65  *      unresolved dependency, with
   66  * The format of the dependency tuple is:
   67  *     ((packageName, packageVersion, packageRelease),
   68  *      (reqName, reqVersion),
   69  *      needsFlags,
   70  *      suggestedPackage,
   71  *      sense)
   72  *     packageName, packageVersion, packageRelease are the name,
   73  *     version, and release of the package that has the unresolved
   74  *     dependency or conflict.
   75  *     The reqName and reqVersion are the name and version of the
   76  *     requirement or conflict.
   77  *     The needsFlags is a bitfield that describes the versioned
   78  *     nature of a requirement or conflict.  The constants
   79  *     rpm.RPMSENSE_LESS, rpm.RPMSENSE_GREATER, and
   80  *     rpm.RPMSENSE_EQUAL can be logical ANDed with the needsFlags
   81  *     to get versioned dependency information.
   82  *     suggestedPackage is a tuple if the dependency check was aware
   83  *     of a package that solves this dependency problem when the
   84  *     dependency check was run.  Packages that are added to the
   85  *     transaction set as "available" are examined during the
   86  *     dependency check as possible dependency solvers. The tuple
   87  *     contains two values, (header, suggestedName).  These are set to
   88  *     the header of the suggested package and its name, respectively.
   89  *     If there is no known package to solve the dependency problem,
   90  *     suggestedPackage is None.
   91  *     The constants rpm.RPMDEP_SENSE_CONFLICTS and
   92  *     rpm.RPMDEP_SENSE_REQUIRES are set to show a dependency as a
   93  *     requirement or a conflict.
   94  *
   95  * - ts.order() Do a topological sort of added element relations.
   96  * @return  None
   97  *
   98  * - ts.setFlags(transFlags) Set transaction set flags.
   99  * @param transFlags - bit(s) to control transaction operations. The
  100  *      following values can be logically OR'ed together:
  101  *  - rpm.RPMTRANS_FLAG_TEST - test mode, do not modify the RPM
  102  *      database, change any files, or run any package scripts
  103  *  - rpm.RPMTRANS_FLAG_BUILD_PROBS - only build a list of
  104  *      problems encountered when attempting to run this transaction
  105  *      set
  106  *  - rpm.RPMTRANS_FLAG_JUSTDB - only make changes to the rpm
  107  *      database, do not modify files.
  108  *  - rpm.RPMTRANS_FLAG_NOSCRIPTS - do not execute package scripts
  109  *  - rpm.RPMTRANS_FLAG_NOTRIGGERS - do not run trigger scripts
  110  *  - rpm.RPMTRANS_FLAG_NO* - disable specific scripts and triggers
  111  *  - rpm.RPMTRANS_FLAG_NODOCS - do not install files marked as %doc
  112  *  - rpm.RPMTRANS_FLAG_NOPLUGINS - do not run plugins
  113  *  - rpm.RPMTRANS_FLAG_NOFILEDIGEST - disable checking checksums
  114  *  - rpm.RPMTRANS_FLAG_ALLFILES - create all files, even if a
  115  *      file is marked %config(missingok) and an upgrade is
  116  *      being performed.
  117  *  - rpm.RPMTRANS_FLAG_NOCONFIGS - skip config files
  118  *  - rpm.RPMTRANS_FLAG_DEPLOOPS - enable debugging for dependency loops
  119  * @return  previous transFlags
  120  *
  121  * - ts.setProbFilter(ignoreSet) Set transaction set problem filter.
  122  * @param problemSetFilter - control bit(s) to ignore classes of problems,
  123  *      a logical or of one or more of the following bit(s):
  124  *  - rpm.RPMPROB_FILTER_IGNOREOS -
  125  *  - rpm.RPMPROB_FILTER_IGNOREARCH -
  126  *  - rpm.RPMPROB_FILTER_REPLACEPKG -
  127  *  - rpm.RPMPROB_FILTER_FORCERELOCATE -
  128  *  - rpm.RPMPROB_FILTER_REPLACENEWFILES -
  129  *  - rpm.RPMPROB_FILTER_REPLACEOLDFILES -
  130  *  - rpm.RPMPROB_FILTER_OLDPACKAGE -
  131  *  - rpm.RPMPROB_FILTER_DISKSPACE -
  132  * @return  previous ignoreSet
  133  *
  134  * - ts.run(callback,data) Attempt to execute a transaction set.
  135  *  After the transaction set has been populated with install/upgrade or
  136  *  erase actions, the transaction set can be executed by invoking
  137  *  the ts.run() method.
  138  */
  139 
  140 struct rpmtsObject_s {
  141     PyObject_HEAD
  142     PyObject *md_dict;      /*!< to look like PyModuleObject */
  143     rpmfdObject *scriptFd;
  144     PyObject *keyList;
  145     rpmts   ts;
  146     rpmtsi tsi;
  147 };
  148 
  149 struct rpmtsCallbackType_s {
  150     PyObject * cb;
  151     PyObject * data;
  152     rpmtsObject * tso;
  153     PyThreadState *_save;
  154 };
  155 
  156 RPM_GNUC_NORETURN
  157 static void die(PyObject *cb)
  158 {
  159     char *pyfn = NULL;
  160     PyObject *r;
  161 
  162     if (PyErr_Occurred()) {
  163     PyErr_Print();
  164     }
  165     if ((r = PyObject_Repr(cb)) != NULL) { 
  166     pyfn = PyBytes_AsString(r);
  167     }
  168     fprintf(stderr, "FATAL ERROR: python callback %s failed, aborting!\n", 
  169                   pyfn ? pyfn : "???");
  170     exit(EXIT_FAILURE);
  171 }
  172 
  173 int rpmtsFromPyObject(PyObject *item, rpmts *ts)
  174 {
  175     if (rpmtsObject_Check(item)) {
  176     *ts = ((rpmtsObject *) item)->ts;
  177     return 1;
  178     }
  179     PyErr_SetString(PyExc_TypeError, "TransactionSet object expected");
  180     return 0;
  181 }
  182 
  183 
  184 static PyObject *
  185 rpmts_AddInstall(rpmtsObject * s, PyObject * args)
  186 {
  187     Header h = NULL;
  188     PyObject * key;
  189     int how = 0;
  190     int rc;
  191 
  192     if (!PyArg_ParseTuple(args, "O&Oi:AddInstall", 
  193               hdrFromPyObject, &h, &key, &how))
  194     return NULL;
  195 
  196     rc = rpmtsAddInstallElement(s->ts, h, key, how, NULL);
  197     if (key && rc == 0) {
  198     PyList_Append(s->keyList, key);
  199     }
  200     return PyBool_FromLong((rc == 0));
  201 }
  202 
  203 static PyObject *
  204 rpmts_AddReinstall(rpmtsObject * s, PyObject * args)
  205 {
  206     Header h = NULL;
  207     PyObject * key;
  208     int rc;
  209 
  210     if (!PyArg_ParseTuple(args, "O&O:AddReinstall", 
  211               hdrFromPyObject, &h, &key))
  212     return NULL;
  213 
  214     rc = rpmtsAddReinstallElement(s->ts, h, key);
  215     if (key && rc == 0) {
  216     PyList_Append(s->keyList, key);
  217     }
  218     return PyBool_FromLong((rc == 0));
  219 }
  220 
  221 static PyObject *
  222 rpmts_AddErase(rpmtsObject * s, PyObject * args)
  223 {
  224     Header h;
  225 
  226     if (!PyArg_ParseTuple(args, "O&:AddErase", hdrFromPyObject, &h))
  227         return NULL;
  228 
  229     return PyBool_FromLong(rpmtsAddEraseElement(s->ts, h, -1) == 0);
  230 }
  231 
  232 static int
  233 rpmts_SolveCallback(rpmts ts, rpmds ds, const void * data)
  234 {
  235     struct rpmtsCallbackType_s * cbInfo = (struct rpmtsCallbackType_s *) data;
  236     PyObject * args, * result;
  237     int res = 1;
  238 
  239     if (cbInfo->tso == NULL) return res;
  240     if (cbInfo->cb == Py_None) return res;
  241 
  242     PyEval_RestoreThread(cbInfo->_save);
  243 
  244     args = Py_BuildValue("(OiNNi)", cbInfo->tso,
  245         rpmdsTagN(ds), utf8FromString(rpmdsN(ds)),
  246         utf8FromString(rpmdsEVR(ds)), rpmdsFlags(ds));
  247     result = PyEval_CallObject(cbInfo->cb, args);
  248     Py_DECREF(args);
  249 
  250     if (!result) {
  251     die(cbInfo->cb);
  252     } else {
  253     if (PyInt_Check(result))
  254         res = PyInt_AsLong(result);
  255     Py_DECREF(result);
  256     }
  257 
  258     cbInfo->_save = PyEval_SaveThread();
  259 
  260     return res;
  261 }
  262 
  263 static PyObject *
  264 rpmts_Check(rpmtsObject * s, PyObject * args, PyObject * kwds)
  265 {
  266     struct rpmtsCallbackType_s cbInfo;
  267     int rc;
  268     char * kwlist[] = {"callback", NULL};
  269 
  270     memset(&cbInfo, 0, sizeof(cbInfo));
  271     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:Check", kwlist,
  272         &cbInfo.cb))
  273     return NULL;
  274 
  275     if (cbInfo.cb != NULL) {
  276     if (!PyCallable_Check(cbInfo.cb)) {
  277         PyErr_SetString(PyExc_TypeError, "expected a callable");
  278         return NULL;
  279     }
  280     rc = rpmtsSetSolveCallback(s->ts, rpmts_SolveCallback, (void *)&cbInfo);
  281     }
  282 
  283     cbInfo.tso = s;
  284     cbInfo._save = PyEval_SaveThread();
  285 
  286     rc = rpmtsCheck(s->ts);
  287 
  288     PyEval_RestoreThread(cbInfo._save);
  289 
  290     return PyBool_FromLong((rc == 0));
  291 }
  292 
  293 static PyObject *
  294 rpmts_Order(rpmtsObject * s)
  295 {
  296     int rc;
  297 
  298     Py_BEGIN_ALLOW_THREADS
  299     rc = rpmtsOrder(s->ts);
  300     Py_END_ALLOW_THREADS
  301 
  302     return Py_BuildValue("i", rc);
  303 }
  304 
  305 static PyObject *
  306 rpmts_Clean(rpmtsObject * s)
  307 {
  308     rpmtsClean(s->ts);
  309 
  310     Py_RETURN_NONE;
  311 }
  312 
  313 static PyObject *
  314 rpmts_Clear(rpmtsObject * s)
  315 {
  316     rpmtsEmpty(s->ts);
  317 
  318     Py_RETURN_NONE;
  319 }
  320 
  321 static PyObject *
  322 rpmts_OpenDB(rpmtsObject * s)
  323 {
  324     int dbmode;
  325 
  326     dbmode = rpmtsGetDBMode(s->ts);
  327     if (dbmode == -1)
  328     dbmode = O_RDONLY;
  329 
  330     return Py_BuildValue("i", rpmtsOpenDB(s->ts, dbmode));
  331 }
  332 
  333 static PyObject *
  334 rpmts_CloseDB(rpmtsObject * s)
  335 {
  336     int rc;
  337 
  338     rc = rpmtsCloseDB(s->ts);
  339     rpmtsSetDBMode(s->ts, -1);  /* XXX disable lazy opens */
  340 
  341     return Py_BuildValue("i", rc);
  342 }
  343 
  344 static PyObject *
  345 rpmts_InitDB(rpmtsObject * s)
  346 {
  347     int rc;
  348 
  349     rc = rpmtsInitDB(s->ts, O_RDONLY);
  350     if (rc == 0)
  351     rc = rpmtsCloseDB(s->ts);
  352 
  353     return Py_BuildValue("i", rc);
  354 }
  355 
  356 static PyObject *
  357 rpmts_RebuildDB(rpmtsObject * s)
  358 {
  359     int rc;
  360 
  361     Py_BEGIN_ALLOW_THREADS
  362     rc = rpmtsRebuildDB(s->ts);
  363     Py_END_ALLOW_THREADS
  364 
  365     return Py_BuildValue("i", rc);
  366 }
  367 
  368 static PyObject *
  369 rpmts_VerifyDB(rpmtsObject * s)
  370 {
  371     int rc;
  372 
  373     Py_BEGIN_ALLOW_THREADS
  374     rc = rpmtsVerifyDB(s->ts);
  375     Py_END_ALLOW_THREADS
  376 
  377     return Py_BuildValue("i", rc);
  378 }
  379 
  380 static PyObject *
  381 rpmts_dbCookie(rpmtsObject * s)
  382 {
  383     PyObject *ret = NULL;
  384     char *cookie = NULL;
  385 
  386     Py_BEGIN_ALLOW_THREADS
  387     cookie = rpmdbCookie(rpmtsGetRdb(s->ts));
  388     Py_END_ALLOW_THREADS
  389 
  390     ret = utf8FromString(cookie);
  391     free(cookie);
  392     return ret;
  393 }
  394 
  395 static PyObject *
  396 rpmts_HdrFromFdno(rpmtsObject * s, PyObject *arg)
  397 {
  398     PyObject *ho = NULL;
  399     rpmfdObject *fdo = NULL;
  400     Header h;
  401     rpmRC rpmrc;
  402 
  403     if (!PyArg_Parse(arg, "O&:HdrFromFdno", rpmfdFromPyObject, &fdo))
  404         return NULL;
  405 
  406     Py_BEGIN_ALLOW_THREADS;
  407     rpmrc = rpmReadPackageFile(s->ts, rpmfdGetFd(fdo), NULL, &h);
  408     Py_END_ALLOW_THREADS;
  409     Py_XDECREF(fdo);
  410 
  411     if (rpmrc == RPMRC_OK) {
  412     ho = hdr_Wrap(&hdr_Type, h);
  413     } else {
  414     Py_INCREF(Py_None);
  415     ho = Py_None;
  416     }
  417     return Py_BuildValue("(iN)", rpmrc, ho);
  418 }
  419 
  420 static PyObject *
  421 rpmts_HdrCheck(rpmtsObject * s, PyObject *obj)
  422 {
  423     PyObject * blob;
  424     char * msg = NULL;
  425     const void * uh;
  426     int uc;
  427     rpmRC rpmrc;
  428 
  429     if (!PyArg_Parse(obj, "S:HdrCheck", &blob))
  430         return NULL;
  431 
  432     uh = PyBytes_AsString(blob);
  433     uc = PyBytes_Size(blob);
  434 
  435     Py_BEGIN_ALLOW_THREADS;
  436     rpmrc = headerCheck(s->ts, uh, uc, &msg);
  437     Py_END_ALLOW_THREADS;
  438 
  439     return Py_BuildValue("(iN)", rpmrc, utf8FromString(msg));
  440 }
  441 
  442 static PyObject *
  443 rpmts_PgpPrtPkts(rpmtsObject * s, PyObject * args, PyObject * kwds)
  444 {
  445     PyObject * blob;
  446     unsigned char * pkt;
  447     unsigned int pktlen;
  448     int rc;
  449     char * kwlist[] = {"octets", NULL};
  450 
  451     if (!PyArg_ParseTupleAndKeywords(args, kwds, "S:PgpPrtPkts", kwlist, &blob))
  452         return NULL;
  453 
  454     pkt = (unsigned char *)PyBytes_AsString(blob);
  455     pktlen = PyBytes_Size(blob);
  456 
  457     rc = pgpPrtPkts(pkt, pktlen, NULL, 1);
  458 
  459     return Py_BuildValue("i", rc);
  460 }
  461 
  462 static PyObject *
  463 rpmts_PgpImportPubkey(rpmtsObject * s, PyObject * args, PyObject * kwds)
  464 {
  465     PyObject * blob;
  466     unsigned char * pkt;
  467     unsigned int pktlen;
  468     int rc;
  469     char * kwlist[] = {"pubkey", NULL};
  470 
  471     if (!PyArg_ParseTupleAndKeywords(args, kwds, "S:PgpImportPubkey",
  472             kwlist, &blob))
  473     return NULL;
  474 
  475     pkt = (unsigned char *)PyBytes_AsString(blob);
  476     pktlen = PyBytes_Size(blob);
  477 
  478     rc = rpmtsImportPubkey(s->ts, pkt, pktlen);
  479 
  480     return Py_BuildValue("i", rc);
  481 }
  482 
  483 static PyObject *rpmts_setKeyring(rpmtsObject *s, PyObject *arg)
  484 {
  485     rpmKeyring keyring = NULL;
  486     if (arg == Py_None || rpmKeyringFromPyObject(arg, &keyring)) {
  487     return PyBool_FromLong(rpmtsSetKeyring(s->ts, keyring) == 0);
  488     } else {
  489     PyErr_SetString(PyExc_TypeError, "rpm.keyring or None expected");
  490     return NULL;
  491     }
  492 }
  493 
  494 static PyObject *rpmts_getKeyring(rpmtsObject *s, PyObject *args, PyObject *kwds)
  495 {
  496     rpmKeyring keyring = NULL;
  497     int autoload = 1;
  498     char * kwlist[] = { "autoload", NULL };
  499 
  500     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i:getKeyring",
  501                      kwlist, &autoload))
  502     return NULL;
  503 
  504     keyring = rpmtsGetKeyring(s->ts, autoload);
  505     if (keyring) {
  506     return rpmKeyring_Wrap(&rpmKeyring_Type, keyring);
  507     } else {
  508     Py_RETURN_NONE;
  509     }
  510 }
  511 
  512 static void *
  513 rpmtsCallback(const void * hd, const rpmCallbackType what,
  514                  const rpm_loff_t amount, const rpm_loff_t total,
  515                      const void * pkgKey, rpmCallbackData data)
  516 {
  517     Header h = (Header) hd;
  518     struct rpmtsCallbackType_s * cbInfo = data;
  519     PyObject * pkgObj = (PyObject *) pkgKey;
  520     PyObject * args, * result;
  521     static FD_t fd;
  522 
  523     if (cbInfo->cb == Py_None) return NULL;
  524 
  525     PyEval_RestoreThread(cbInfo->_save);
  526 
  527     /* Synthesize a python object for callback (if necessary). */
  528     if (pkgObj == NULL) {
  529     if (h) {
  530         pkgObj = utf8FromString(headerGetString(h, RPMTAG_NAME));
  531     } else {
  532         pkgObj = Py_None;
  533         Py_INCREF(pkgObj);
  534     }
  535     } else
  536     Py_INCREF(pkgObj);
  537 
  538     args = Py_BuildValue("(iLLOO)", what, amount, total, pkgObj, cbInfo->data);
  539     result = PyEval_CallObject(cbInfo->cb, args);
  540     Py_DECREF(args);
  541     Py_DECREF(pkgObj);
  542 
  543     if (!result) {
  544     die(cbInfo->cb);
  545     }
  546 
  547     if (what == RPMCALLBACK_INST_OPEN_FILE) {
  548     int fdno;
  549 
  550         if (!PyArg_Parse(result, "i", &fdno)) {
  551         die(cbInfo->cb);
  552     }
  553     Py_DECREF(result);
  554     cbInfo->_save = PyEval_SaveThread();
  555 
  556     fd = fdDup(fdno);
  557     fcntl(Fileno(fd), F_SETFD, FD_CLOEXEC);
  558 
  559     return fd;
  560     } else
  561     if (what == RPMCALLBACK_INST_CLOSE_FILE) {
  562     Fclose (fd);
  563     }
  564 
  565     Py_DECREF(result);
  566     cbInfo->_save = PyEval_SaveThread();
  567 
  568     return NULL;
  569 }
  570 
  571 static PyObject *
  572 rpmts_Problems(rpmtsObject * s)
  573 {
  574     rpmps ps = rpmtsProblems(s->ts);
  575     PyObject *problems = rpmps_AsList(ps);
  576     rpmpsFree(ps);
  577     return problems;
  578 }
  579 
  580 static PyObject *
  581 rpmts_Run(rpmtsObject * s, PyObject * args, PyObject * kwds)
  582 {
  583     int rc;
  584     struct rpmtsCallbackType_s cbInfo;
  585     rpmprobFilterFlags ignoreSet;
  586     char * kwlist[] = {"callback", "data", "ignoreSet", NULL};
  587 
  588     if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOi:Run", kwlist,
  589         &cbInfo.cb, &cbInfo.data, &ignoreSet))
  590     return NULL;
  591 
  592     cbInfo.tso = s;
  593     cbInfo._save = PyEval_SaveThread();
  594 
  595     if (cbInfo.cb != NULL) {
  596     if (!PyCallable_Check(cbInfo.cb)) {
  597         PyErr_SetString(PyExc_TypeError, "expected a callable");
  598         return NULL;
  599     }
  600     (void) rpmtsSetNotifyCallback(s->ts, rpmtsCallback, (void *) &cbInfo);
  601     }
  602 
  603     rc = rpmtsRun(s->ts, NULL, ignoreSet);
  604 
  605     if (cbInfo.cb)
  606     (void) rpmtsSetNotifyCallback(s->ts, NULL, NULL);
  607 
  608     PyEval_RestoreThread(cbInfo._save);
  609 
  610     return Py_BuildValue("i", rc);
  611 }
  612 
  613 static PyObject *
  614 rpmts_iternext(rpmtsObject * s)
  615 {
  616     PyObject * result = NULL;
  617     rpmte te;
  618 
  619     /* Reset iterator on 1st entry. */
  620     if (s->tsi == NULL) {
  621     s->tsi = rpmtsiInit(s->ts);
  622     if (s->tsi == NULL)
  623         return NULL;
  624     }
  625 
  626     te = rpmtsiNext(s->tsi, 0);
  627     if (te != NULL) {
  628     result = rpmte_Wrap(&rpmte_Type, te);
  629     } else {
  630     s->tsi = rpmtsiFree(s->tsi);
  631     }
  632 
  633     return result;
  634 }
  635 
  636 static PyObject *
  637 rpmts_Match(rpmtsObject * s, PyObject * args, PyObject * kwds)
  638 {
  639     PyObject *Key = NULL;
  640     PyObject *str = NULL;
  641     PyObject *mio = NULL;
  642     char *key = NULL;
  643 /* XXX lkey *must* be a 32 bit integer, int "works" on all known platforms. */
  644     int lkey = 0;
  645     int len = 0;
  646     rpmDbiTagVal tag = RPMDBI_PACKAGES;
  647     char * kwlist[] = {"tagNumber", "key", NULL};
  648 
  649     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&O:Match", kwlist,
  650         tagNumFromPyObject, &tag, &Key))
  651     return NULL;
  652 
  653     if (Key) {
  654     if (PyInt_Check(Key)) {
  655         lkey = PyInt_AsLong(Key);
  656         key = (char *)&lkey;
  657         len = sizeof(lkey);
  658     } else if (PyLong_Check(Key)) {
  659         lkey = PyLong_AsLong(Key);
  660         key = (char *)&lkey;
  661         len = sizeof(lkey);
  662     } else if (utf8FromPyObject(Key, &str)) {
  663         key = PyBytes_AsString(str);
  664         len = PyBytes_Size(str);
  665     } else {
  666         PyErr_SetString(PyExc_TypeError, "unknown key type");
  667         return NULL;
  668     }
  669     /* One of the conversions above failed, exception is set already */
  670     if (PyErr_Occurred()) goto exit;
  671     }
  672 
  673     /* XXX If not already opened, open the database O_RDONLY now. */
  674     /* XXX FIXME: lazy default rdonly open also done by rpmtsInitIterator(). */
  675     if (rpmtsGetRdb(s->ts) == NULL) {
  676     int rc = rpmtsOpenDB(s->ts, O_RDONLY);
  677     if (rc || rpmtsGetRdb(s->ts) == NULL) {
  678         PyErr_SetString(pyrpmError, "rpmdb open failed");
  679         goto exit;
  680     }
  681     }
  682 
  683     mio = rpmmi_Wrap(&rpmmi_Type, rpmtsInitIterator(s->ts, tag, key, len), (PyObject*)s);
  684 
  685 exit:
  686     Py_XDECREF(str);
  687     return mio;
  688 }
  689 static PyObject *
  690 rpmts_index(rpmtsObject * s, PyObject * args, PyObject * kwds)
  691 {
  692     rpmDbiTagVal tag;
  693     PyObject *mio = NULL;
  694     char * kwlist[] = {"tag", NULL};
  695 
  696     if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:Keys", kwlist,
  697               tagNumFromPyObject, &tag))
  698     return NULL;
  699 
  700     /* XXX If not already opened, open the database O_RDONLY now. */
  701     if (rpmtsGetRdb(s->ts) == NULL) {
  702     int rc = rpmtsOpenDB(s->ts, O_RDONLY);
  703     if (rc || rpmtsGetRdb(s->ts) == NULL) {
  704         PyErr_SetString(pyrpmError, "rpmdb open failed");
  705         goto exit;
  706     }
  707     }
  708 
  709     rpmdbIndexIterator ii = rpmdbIndexIteratorInit(rpmtsGetRdb(s->ts), tag);
  710     if (ii == NULL) {
  711         PyErr_SetString(PyExc_KeyError, "No index for this tag");
  712         return NULL;
  713     }
  714     mio = rpmii_Wrap(&rpmii_Type, ii, (PyObject*)s);
  715 
  716 exit:
  717     return mio;
  718 }
  719 
  720 static struct PyMethodDef rpmts_methods[] = {
  721  {"addInstall", (PyCFunction) rpmts_AddInstall, METH_VARARGS,
  722   "ts.addInstall(hdr, data, mode) --  Add transaction element(s)\n"
  723   "representing an installation or update of a package.\n\n"
  724   "Args:\n"
  725   "  hdr : the header to be added\n"
  726   "  data : user data that will be passed to the transaction callback\n\t\tduring transaction execution\n"
  727   "  mode : optional argument that specifies if this package should be\n\t\tinstalled ('i'), upgraded ('u')"},
  728  {"addReinstall",   (PyCFunction) rpmts_AddReinstall,   METH_VARARGS,
  729   "ts.addReinstall(hdr, data) -- Adds transaction elements\nrepresenting a reinstall of an already installed package.\n\nSee addInstall for details."},
  730  {"addErase",   (PyCFunction) rpmts_AddErase,   METH_VARARGS|METH_KEYWORDS,
  731   "addErase(name) -- Add a transaction element representing an erase\nof an installed package.\n\n"
  732   "  name: the package name to be erased"},
  733  {"check",  (PyCFunction) rpmts_Check,  METH_VARARGS|METH_KEYWORDS,
  734   "ts.check( )-- Perform a dependency check on the transaction set.\n"
  735   "     After headers have been added to a transaction set,\n"
  736   "     a dependencycheck can be performed to make sure that\n"
  737   "     all package dependencies are satisfied.\n"
  738   "Return   None If there are no unresolved dependencies\n"
  739   "     Otherwise a list of complex tuples is returned,\n"
  740   "     one tuple per unresolved dependency, with\n"
  741   "The format of the dependency tuple is:\n"
  742   "    ((packageName, packageVersion, packageRelease),\n"
  743   "     (reqName, reqVersion),\n"
  744   "     needsFlags,\n"
  745   "     suggestedPackage,\n"
  746   "     sense)\n"
  747   "  packageName, packageVersion, packageRelease are the name,\n"
  748   "    version, and release of the package that has the unresolved\n"
  749   "    dependency or conflict.\n"
  750   "  The reqName and reqVersion are the name and version of the\n"
  751   "    requirement or conflict.\n"
  752   "  The needsFlags is a bitfield that describes the versioned\n"
  753   "    nature of a requirement or conflict.  The constants\n"
  754   "    rpm.RPMSENSE_LESS, rpm.RPMSENSE_GREATER, and\n"
  755   "    rpm.RPMSENSE_EQUAL can be logical ANDed with the needsFlags\n"
  756   "    to get versioned dependency information.\n"
  757   "  suggestedPackage is a tuple if the dependency check was aware\n"
  758   "    of a package that solves this dependency problem when the\n"
  759   "    dependency check was run.  Packages that are added to the\n"
  760   "    transaction set as \"available\" are examined during the\n"
  761   "    dependency check as possible dependency solvers. The tuple\n"
  762   "    contains two values, (header, suggestedName).  These are set to\n"
  763   "    the header of the suggested package and its name, respectively.\n"
  764   "    If there is no known package to solve the dependency problem,\n"
  765   "    suggestedPackage is None.\n"
  766   "  The constants rpm.RPMDEP_SENSE_CONFLICTS and\n"
  767   "    rpm.RPMDEP_SENSE_REQUIRES are set to show a dependency as a\n"
  768   "    requirement or a conflict.\n"},
  769  {"order",  (PyCFunction) rpmts_Order,  METH_NOARGS,
  770   "ts.order() Do a topological sort of added element relations." },
  771  {"problems",   (PyCFunction) rpmts_Problems,   METH_NOARGS,
  772 "ts.problems() -> ps\n\
  773 - Return current problem set.\n" },
  774  {"run",    (PyCFunction) rpmts_Run,    METH_VARARGS|METH_KEYWORDS,
  775 "ts.run(callback, data) -> (problems)\n\
  776 - Run a transaction set, returning list of problems found.\n\
  777   Note: The callback may not be None.\n" },
  778  {"clean",  (PyCFunction) rpmts_Clean,  METH_NOARGS,
  779   "ts.clean()-- Free memory needed only for dependency checks\nand ordering. Should not be needed in normal operation." },
  780  {"clear",  (PyCFunction) rpmts_Clear,  METH_NOARGS,
  781 "ts.clear() -> None\n\
  782 Remove all elements from the transaction set\n" },
  783  {"openDB", (PyCFunction) rpmts_OpenDB, METH_NOARGS,
  784 "ts.openDB() -> None -- Open the default transaction rpmdb.\n\n\
  785   Note: The transaction rpmdb is lazily opened,\n  so ts.openDB() is seldom needed.\n" },
  786  {"closeDB",    (PyCFunction) rpmts_CloseDB,    METH_NOARGS,
  787 "ts.closeDB() -> None\n\
  788 - Close the default transaction rpmdb.\n\
  789   Note: ts.closeDB() disables lazy opens,\n\
  790   and should hardly ever be used.\n" },
  791  {"initDB", (PyCFunction) rpmts_InitDB, METH_NOARGS,
  792 "ts.initDB() -> None\n\
  793 - Initialize the default transaction rpmdb.\n\
  794  Note: ts.initDB() is seldom needed anymore.\n" },
  795  {"rebuildDB",  (PyCFunction) rpmts_RebuildDB,  METH_NOARGS,
  796 "ts.rebuildDB() -> None\n\
  797 - Rebuild the default transaction rpmdb.\n" },
  798  {"verifyDB",   (PyCFunction) rpmts_VerifyDB,   METH_NOARGS,
  799 "ts.verifyDB() -> None\n\
  800 - Verify the default transaction rpmdb.\n" },
  801  {"hdrFromFdno",(PyCFunction) rpmts_HdrFromFdno,METH_O,
  802 "ts.hdrFromFdno(fdno) -> hdr\n\
  803 - Read a package header from a file descriptor.\n" },
  804  {"hdrCheck",   (PyCFunction) rpmts_HdrCheck,   METH_O,
  805   "ts.hdrCheck(hdrblob) -- Check header consistency,\nperforming headerGetEntry() the hard way.\n\n"
  806   "Sanity checks on the header are performed while looking for a\n"
  807   "header-only digest or signature to verify the blob. If found,\n"
  808   "the digest or signature is verified.\n\n"
  809   "\thdrblob : unloaded header blob\n"
  810   "Return tuple (int status, message string)"},
  811  {"pgpPrtPkts", (PyCFunction) rpmts_PgpPrtPkts, METH_VARARGS|METH_KEYWORDS,
  812   "pgpPrtPkts(octets) -- Print/parse a OpenPGP packet(s).\n\nReturn 0 on success." },
  813  {"pgpImportPubkey",    (PyCFunction) rpmts_PgpImportPubkey,    METH_VARARGS|METH_KEYWORDS,
  814   "pgpImportPubkey(pubkey) -- Import public key packet." },
  815  {"getKeyring", (PyCFunction) rpmts_getKeyring, METH_VARARGS|METH_KEYWORDS, 
  816   "ts.getKeyring(autoload=False) -- Return key ring object." },
  817  {"setKeyring", (PyCFunction) rpmts_setKeyring, METH_O, 
  818   "ts.setKeyring(keyring) -- Set key ring used for checking signatures\n\n"
  819   "Pass None for an empty key ring." },
  820  {"dbMatch",    (PyCFunction) rpmts_Match,  METH_VARARGS|METH_KEYWORDS,
  821 "ts.dbMatch([TagN, [key]]) -> mi\n\
  822 - Create a match iterator for the default transaction rpmdb.\n" },
  823  {"dbIndex",     (PyCFunction) rpmts_index, METH_VARARGS|METH_KEYWORDS,
  824 "ts.dbIndex(TagN) -> ii\n\
  825 - Create a key iterator for the default transaction rpmdb.\n" },
  826  {"dbCookie",   (PyCFunction) rpmts_dbCookie,   METH_NOARGS,
  827 "dbCookie -> cookie\n\
  828 - Return a cookie string for determining if database has changed\n" },
  829     {NULL,      NULL}       /* sentinel */
  830 };
  831 
  832 static void rpmts_dealloc(rpmtsObject * s)
  833 {
  834 
  835     s->ts = rpmtsFree(s->ts);
  836     Py_XDECREF(s->scriptFd);
  837     Py_XDECREF(s->keyList);
  838     Py_TYPE(s)->tp_free((PyObject *)s);
  839 }
  840 
  841 static PyObject * rpmts_new(PyTypeObject * subtype, PyObject *args, PyObject *kwds)
  842 {
  843     rpmtsObject * s = (rpmtsObject *)subtype->tp_alloc(subtype, 0);
  844     if (s == NULL) return NULL;
  845 
  846     s->ts = rpmtsCreate();
  847     s->scriptFd = NULL;
  848     s->tsi = NULL;
  849     s->keyList = PyList_New(0);
  850     return (PyObject *) s;
  851 }
  852 
  853 static int rpmts_init(rpmtsObject *s, PyObject *args, PyObject *kwds)
  854 {
  855     const char * rootDir = "/";
  856     rpmVSFlags vsflags = rpmExpandNumeric("%{?__vsflags}");
  857     char * kwlist[] = {"rootdir", "vsflags", 0};
  858 
  859     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|si:rpmts_new", kwlist,
  860         &rootDir, &vsflags))
  861     return -1;
  862 
  863     (void) rpmtsSetRootDir(s->ts, rootDir);
  864     /* XXX: make this use common code with rpmts_SetVSFlags() to check the
  865      *      python objects */
  866     (void) rpmtsSetVSFlags(s->ts, vsflags);
  867 
  868     return 0;
  869 }
  870 
  871 static PyObject *rpmts_get_tid(rpmtsObject *s, void *closure)
  872 {
  873     return Py_BuildValue("i", rpmtsGetTid(s->ts));
  874 }
  875 
  876 static PyObject *rpmts_get_rootDir(rpmtsObject *s, void *closure)
  877 {
  878     return utf8FromString(rpmtsRootDir(s->ts));
  879 }
  880 
  881 static int rpmts_set_scriptFd(rpmtsObject *s, PyObject *value, void *closure)
  882 {
  883     rpmfdObject *fdo = NULL;
  884     int rc = 0;
  885     if (PyArg_Parse(value, "O&", rpmfdFromPyObject, &fdo)) {
  886     Py_XDECREF(s->scriptFd);
  887     s->scriptFd = fdo;
  888     rpmtsSetScriptFd(s->ts, rpmfdGetFd(s->scriptFd));
  889     } else if (value == Py_None) {
  890     Py_XDECREF(s->scriptFd);
  891     s->scriptFd = NULL;
  892     rpmtsSetScriptFd(s->ts, NULL);
  893     } else {
  894     rc = -1;
  895     }
  896     return rc;
  897 }
  898 
  899 static PyObject *rpmts_get_color(rpmtsObject *s, void *closure)
  900 {
  901     return Py_BuildValue("i", rpmtsColor(s->ts));
  902 }
  903 
  904 static PyObject *rpmts_get_prefcolor(rpmtsObject *s, void *closure)
  905 {
  906     return Py_BuildValue("i", rpmtsPrefColor(s->ts));
  907 }
  908 
  909 static int rpmts_set_color(rpmtsObject *s, PyObject *value, void *closure)
  910 {
  911     rpm_color_t color;
  912     if (!PyArg_Parse(value, "i", &color)) return -1;
  913 
  914     /* TODO: validate the bits */
  915     rpmtsSetColor(s->ts, color);
  916     return 0;
  917 }
  918 
  919 static int rpmts_set_prefcolor(rpmtsObject *s, PyObject *value, void *closure)
  920 {
  921     rpm_color_t color;
  922     if (!PyArg_Parse(value, "i", &color)) return -1;
  923 
  924     /* TODO: validate the bits */
  925     rpmtsSetPrefColor(s->ts, color);
  926     return 0;
  927 }
  928 
  929 static int rpmts_set_flags(rpmtsObject *s, PyObject *value, void *closure)
  930 {
  931     rpmtransFlags flags;
  932     if (!PyArg_Parse(value, "i", &flags)) return -1;
  933 
  934     /* TODO: validate the bits */
  935     rpmtsSetFlags(s->ts, flags);
  936     return 0;
  937 }
  938 
  939 static int rpmts_set_vsflags(rpmtsObject *s, PyObject *value, void *closure)
  940 {
  941     rpmVSFlags flags;
  942     if (!PyArg_Parse(value, "i", &flags)) return -1;
  943 
  944     /* TODO: validate the bits */
  945     rpmtsSetVSFlags(s->ts, flags);
  946     return 0;
  947 }
  948 
  949 static int rpmts_set_vfyflags(rpmtsObject *s, PyObject *value, void *closure)
  950 {
  951     rpmVSFlags flags;
  952     if (!PyArg_Parse(value, "i", &flags)) return -1;
  953 
  954     /* TODO: validate the bits */
  955     rpmtsSetVfyFlags(s->ts, flags);
  956     return 0;
  957 }
  958 
  959 static int rpmts_set_vfylevel(rpmtsObject *s, PyObject *value, void *closure)
  960 {
  961     int vfylevel;
  962     if (!PyArg_Parse(value, "i", &vfylevel)) return -1;
  963     rpmtsSetVfyLevel(s->ts, vfylevel);
  964     return 0;
  965 }
  966 
  967 static PyObject *rpmts_get_flags(rpmtsObject *s, void *closure)
  968 {
  969     return Py_BuildValue("i", rpmtsFlags(s->ts));
  970 }
  971 
  972 static PyObject *rpmts_get_vsflags(rpmtsObject *s, void *closure)
  973 {
  974     return Py_BuildValue("i", rpmtsVSFlags(s->ts));
  975 }
  976 
  977 static PyObject *rpmts_get_vfyflags(rpmtsObject *s, void *closure)
  978 {
  979     return Py_BuildValue("i", rpmtsVfyFlags(s->ts));
  980 }
  981 
  982 static PyObject *rpmts_get_vfylevel(rpmtsObject *s, void *closure)
  983 {
  984     return Py_BuildValue("i", rpmtsVfyLevel(s->ts));
  985 }
  986 
  987 static char rpmts_doc[] =
  988   "A python rpm.ts object represents an RPM transaction set.\n"
  989   "\n"
  990   "The transaction set is the workhorse of RPM. It performs the\n"
  991   "installation and upgrade of packages. The rpm.ts object is\n"
  992   "instantiated by the TransactionSet function in the rpm module.\n"
  993   "\n"
  994   "The TransactionSet function takes two optional arguments. The first\n"
  995   "argument is the root path. The second is the verify signature disable\n"
  996   "flags, a set of the following bits:\n"
  997   "\n"
  998   "-    rpm.RPMVSF_NOHDRCHK if set, don't check rpmdb headers\n"
  999   "-    rpm.RPMVSF_NEEDPAYLOAD  if not set, check header+payload\n"
 1000   "             (if possible)\n"
 1001   "-    rpm.RPMVSF_NOSHA1HEADER if set, don't check header SHA1 digest\n"
 1002   "-    rpm.RPMVSF_NODSAHEADER  if set, don't check header DSA signature\n"
 1003   "-    rpm.RPMVSF_NOMD5    if set, don't check header+payload MD5 digest\n"
 1004   "-    rpm.RPMVSF_NODSA    if set, don't check header+payload DSA signature\n"
 1005   "-    rpm.RPMVSF_NORSA    if set, don't check header+payload RSA signature\n"
 1006   "\n"
 1007   "For convenience, there are the following masks:\n"
 1008   "-    rpm.RPMVSF_MASK_NODIGESTS   if set, don't check digest(s).\n"
 1009   "-    rpm.RPMVSF_MASK_NOSIGNATURES    if set, don't check signature(s).\n\n"
 1010   "The transaction set offers an read only iterable interface for the\ntransaction elements added by the .addInstall(), .addErase() and\n.addReinstall() methods.";
 1011 
 1012 static PyGetSetDef rpmts_getseters[] = {
 1013     /* only provide a setter until we have rpmfd wrappings */
 1014     {"scriptFd",    NULL,   (setter)rpmts_set_scriptFd,
 1015      "write only, file descriptor the output of script gets written to." },
 1016     {"tid",     (getter)rpmts_get_tid, NULL,
 1017      "read only, current transaction id, i.e. transaction time stamp."},
 1018     {"rootDir", (getter)rpmts_get_rootDir, NULL,
 1019      "read only, directory rpm treats as root of the file system." },
 1020     {"_color",  (getter)rpmts_get_color, (setter)rpmts_set_color, NULL},
 1021     {"_prefcolor",  (getter)rpmts_get_prefcolor, (setter)rpmts_set_prefcolor, NULL},
 1022     {"_flags",  (getter)rpmts_get_flags, (setter)rpmts_set_flags, NULL},
 1023     {"_vsflags",    (getter)rpmts_get_vsflags, (setter)rpmts_set_vsflags, NULL},
 1024     {"_vfyflags",   (getter)rpmts_get_vfyflags, (setter)rpmts_set_vfyflags, NULL},
 1025     {"_vfylevel",   (getter)rpmts_get_vfylevel, (setter)rpmts_set_vfylevel, NULL},
 1026     { NULL }
 1027 };
 1028 
 1029 PyTypeObject rpmts_Type = {
 1030     PyVarObject_HEAD_INIT(&PyType_Type, 0)
 1031     "rpm.ts",           /* tp_name */
 1032     sizeof(rpmtsObject),        /* tp_size */
 1033     0,              /* tp_itemsize */
 1034     (destructor) rpmts_dealloc,     /* tp_dealloc */
 1035     0,              /* tp_print */
 1036     (getattrfunc)0,         /* tp_getattr */
 1037     (setattrfunc)0,         /* tp_setattr */
 1038     0,              /* tp_compare */
 1039     0,              /* tp_repr */
 1040     0,              /* tp_as_number */
 1041     0,              /* tp_as_sequence */
 1042     0,              /* tp_as_mapping */
 1043     0,              /* tp_hash */
 1044     0,              /* tp_call */
 1045     0,              /* tp_str */
 1046     PyObject_GenericGetAttr,    /* tp_getattro */
 1047     PyObject_GenericSetAttr,    /* tp_setattro */
 1048     0,              /* tp_as_buffer */
 1049     Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */
 1050     rpmts_doc,          /* tp_doc */
 1051     0,              /* tp_traverse */
 1052     0,              /* tp_clear */
 1053     0,              /* tp_richcompare */
 1054     0,              /* tp_weaklistoffset */
 1055     PyObject_SelfIter,      /* tp_iter */
 1056     (iternextfunc) rpmts_iternext,  /* tp_iternext */
 1057     rpmts_methods,          /* tp_methods */
 1058     0,              /* tp_members */
 1059     rpmts_getseters,        /* tp_getset */
 1060     0,              /* tp_base */
 1061     0,              /* tp_dict */
 1062     0,              /* tp_descr_get */
 1063     0,              /* tp_descr_set */
 1064     0,              /* tp_dictoffset */
 1065     (initproc) rpmts_init,      /* tp_init */
 1066     0,              /* tp_alloc */
 1067     (newfunc) rpmts_new,        /* tp_new */
 1068     0,              /* tp_free */
 1069     0,              /* tp_is_gc */
 1070 };