rpm  5.2.1
rpmts.c
Go to the documentation of this file.
1 
5 #include "system.h"
6 
7 #include <rpmio.h>
8 #include <rpmiotypes.h> /* XXX fnpyKey */
9 #include <rpmlog.h>
10 #include <iosm.h> /* XXX iosmFileAction */
11 #include <rpmurl.h>
12 #include <rpmpgp.h>
13 #include <rpmmacro.h> /* XXX rpmtsOpenDB() needs rpmGetPath */
14 #include <rpmkeyring.h>
15 
16 #include <rpmtypes.h>
17 #include <rpmtag.h>
18 #include <pkgio.h>
19 
20 #define _RPMDB_INTERNAL /* XXX almost opaque sigh */
21 #include "rpmdb.h" /* XXX stealing db->db_mode. */
22 
23 #include "rpmal.h"
24 #include "rpmds.h"
25 #include "rpmfi.h"
26 #include "rpmlock.h"
27 #include "rpmns.h"
28 
29 #define _RPMTE_INTERNAL /* XXX te->h */
30 #include "rpmte.h"
31 
32 #define _RPMTS_INTERNAL
33 #include "rpmts.h"
34 
35 #include <rpmcli.h>
36 
37 #include "fs.h"
38 
39 /* XXX FIXME: merge with existing (broken?) tests in system.h */
40 /* portability fiddles */
41 #if STATFS_IN_SYS_STATVFS
42 /*@-incondefs@*/
43 #if defined(__LCLINT__)
44 /*@-declundef -exportheader -protoparammatch @*/ /* LCL: missing annotation */
45 extern int statvfs (const char * file, /*@out@*/ struct statvfs * buf)
46  /*@globals fileSystem @*/
47  /*@modifies *buf, fileSystem @*/;
48 /*@=declundef =exportheader =protoparammatch @*/
49 /*@=incondefs@*/
50 #else
51 # include <sys/statvfs.h>
52 #endif
53 #else
54 # if STATFS_IN_SYS_VFS
55 # include <sys/vfs.h>
56 # else
57 # if STATFS_IN_SYS_MOUNT
58 # include <sys/mount.h>
59 # else
60 # if STATFS_IN_SYS_STATFS
61 # include <sys/statfs.h>
62 # endif
63 # endif
64 # endif
65 #endif
66 
67 #include "debug.h"
68 
69 /*@access FD_t @*/ /* XXX void * arg */
70 /*@access rpmdb @*/ /* XXX db->db_chrootDone, NULL */
71 
72 /*@access rpmDiskSpaceInfo @*/
73 /*@access rpmKeyring @*/
74 /*@access rpmps @*/
75 /*@access rpmsx @*/
76 /*@access rpmte @*/
77 /*@access rpmtsi @*/
78 /*@access fnpyKey @*/
79 /*@access pgpDig @*/
80 /*@access pgpDigParams @*/
81 
82 /*@unchecked@*/
83 int _rpmts_debug = 0;
84 
85 /*@unchecked@*/
86 int _rpmts_stats = 0;
87 
88 /*@unchecked@*/
89 int _rpmts_macros = 0;
90 
92 {
93  int rc = 0;
94 
95  if (ts->rdb != NULL) {
96  (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBGET), &ts->rdb->db_getops);
97  (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBPUT), &ts->rdb->db_putops);
98  (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBDEL), &ts->rdb->db_delops);
99  rc = rpmdbClose(ts->rdb);
100  ts->rdb = NULL;
101  }
102  return rc;
103 }
104 
105 int rpmtsOpenDB(rpmts ts, int dbmode)
106 {
107  int rc = 0;
108 
109  if (ts->rdb != NULL && ts->dbmode == dbmode)
110  return 0;
111 
112  (void) rpmtsCloseDB(ts);
113 
114  /* XXX there's a db lock race here that is the callers responsibility. */
115 
116  ts->dbmode = dbmode;
117  rc = rpmdbOpen(ts->rootDir, &ts->rdb, ts->dbmode, 0644);
118  if (rc) {
119  const char * dn;
120  dn = rpmGetPath(ts->rootDir, "%{_dbpath}", NULL);
122  _("cannot open Packages database in %s\n"), dn);
123  dn = _free(dn);
124  }
125  return rc;
126 }
127 
128 int rpmtsInitDB(rpmts ts, int dbmode)
129 {
130 #if defined(SUPPORT_INITDB)
131  void *lock = rpmtsAcquireLock(ts);
132  int rc = rpmdbInit(ts->rootDir, dbmode);
133  lock = rpmtsFreeLock(lock);
134  return rc;
135 #else
136  return -1;
137 #endif
138 }
139 
141 {
142  void * lock = rpmtsAcquireLock(ts);
143  int rc = rpmtsOpenDB(ts, ts->dbmode);
144 
145  if (rc == 0)
146  rc = rpmdbRebuild(ts->rootDir,
147  (!(rpmtsVSFlags(ts) & RPMVSF_NOHDRCHK) ? ts : NULL));
148  lock = rpmtsFreeLock(lock);
149  return rc;
150 }
151 
153 {
154 #if defined(SUPPORT_VERIFYDB)
155  return rpmdbVerify(ts->rootDir);
156 #else
157  return -1;
158 #endif
159 }
160 
161 /*@-compdef@*/ /* keyp might not be defined. */
163  const void * keyp, size_t keylen)
164 {
165  rpmmi mi;
166  const char * arch = NULL;
167  int xx;
168 
169  if (ts->rdb == NULL && rpmtsOpenDB(ts, ts->dbmode))
170  return NULL;
171 
172  /* Parse out "N(EVR).A" tokens from a label key. */
173  if (rpmtag == RPMDBI_LABEL && keyp != NULL) {
174  const char * s = keyp;
175  const char *se;
176  size_t slen = strlen(s);
177  char *t = alloca(slen+1);
178  int level = 0;
179  int c;
180 
181  keyp = t;
182  while ((c = *s++) != '\0') {
183  switch (c) {
184  default:
185  *t++ = (char)c;
186  /*@switchbreak@*/ break;
187  case '(':
188  /* XXX Fail if nested parens. */
189  if (level++ != 0) {
190  rpmlog(RPMLOG_ERR, _("extra '(' in package label: %s\n"), (char *)keyp);
191  return NULL;
192  }
193  /* Parse explicit epoch. */
194  for (se = s; *se && xisdigit(*se); se++)
195  {};
196  if (*se == ':') {
197  /* XXX skip explicit epoch's (for now) */
198  *t++ = '-';
199  s = se + 1;
200  } else {
201  /* No Epoch: found. Convert '(' to '-' and chug. */
202  *t++ = '-';
203  }
204  /*@switchbreak@*/ break;
205  case ')':
206  /* XXX Fail if nested parens. */
207  if (--level != 0) {
208  rpmlog(RPMLOG_ERR, _("missing '(' in package label: %s\n"), (char *)keyp);
209  return NULL;
210  }
211  /* Don't copy trailing ')' */
212  /*@switchbreak@*/ break;
213  }
214  }
215  if (level) {
216  rpmlog(RPMLOG_ERR, _("missing ')' in package label: %s\n"), (char *)keyp);
217  return NULL;
218  }
219  *t = '\0';
220  t = (char *) keyp;
221  t = strrchr(t, '.');
222  /* Is this a valid ".arch" suffix? */
223  if (t != NULL && rpmnsArch(t+1)) {
224  *t++ = '\0';
225  arch = t;
226  }
227  }
228 
229  mi = rpmmiInit(ts->rdb, rpmtag, keyp, keylen);
230 
231  /* Verify header signature/digest during retrieve (if not disabled). */
232  if (mi && !(rpmtsVSFlags(ts) & RPMVSF_NOHDRCHK))
233  (void) rpmmiSetHdrChk(mi, ts);
234 
235  /* Select specified arch only. */
236  if (arch != NULL)
238  return mi;
239 }
240 /*@=compdef@*/
241 
243 {
244  int rc = 0;
245 
246  if (ts->sdb != NULL) {
247  (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBGET), &ts->sdb->db_getops);
248  (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBPUT), &ts->sdb->db_putops);
249  (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBDEL), &ts->sdb->db_delops);
250  rc = rpmdbClose(ts->sdb);
251  ts->sdb = NULL;
252  }
253  return rc;
254 }
255 
256 int rpmtsOpenSDB(rpmts ts, int dbmode)
257 {
258  static int has_sdbpath = -1;
259  int rc = 0;
260 
261  if (ts->sdb != NULL && ts->sdbmode == dbmode)
262  return 0;
263 
264  if (has_sdbpath < 0)
265  has_sdbpath = rpmExpandNumeric("%{?_solve_dbpath:1}");
266 
267  /* If not configured, don't try to open. */
268  if (has_sdbpath <= 0)
269  return 1;
270 
271  addMacro(NULL, "_dbpath", NULL, "%{_solve_dbpath}", RMIL_DEFAULT);
272 
273  rc = rpmdbOpen(ts->rootDir, &ts->sdb, ts->sdbmode, 0644);
274  if (rc) {
275  const char * dn;
276  dn = rpmGetPath(ts->rootDir, "%{_dbpath}", NULL);
278  _("cannot open Solve database in %s\n"), dn);
279  dn = _free(dn);
280  /* XXX only try to open the solvedb once. */
281  has_sdbpath = 0;
282  }
283  delMacro(NULL, "_dbpath");
284 
285  return rc;
286 }
287 
294 static int sugcmp(const void * a, const void * b)
295  /*@*/
296 {
297  const char * astr = *(const char **)a;
298  const char * bstr = *(const char **)b;
299  return strcmp(astr, bstr);
300 }
301 
302 int rpmtsSolve(rpmts ts, rpmds ds, /*@unused@*/ const void * data)
303 {
304  HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
305  const char * errstr;
306  const char * str = NULL;
307  const char * qfmt;
308  rpmmi mi;
309  Header bh = NULL;
310  Header h = NULL;
311  size_t bhnamelen = 0;
312  time_t bhtime = 0;
313  rpmTag rpmtag;
314  const char * keyp;
315  size_t keylen = 0;
316  int rc = 1; /* assume not found */
317  int xx;
318 
319  /* Make suggestions only for installing Requires: */
320  if (ts->goal != TSM_INSTALL)
321  return rc;
322 
323  switch (rpmdsTagN(ds)) {
324  case RPMTAG_CONFLICTNAME:
325  default:
326  return rc;
327  /*@notreached@*/ break;
328  case RPMTAG_DIRNAMES: /* XXX perhaps too many wrong answers */
329  case RPMTAG_REQUIRENAME:
330  case RPMTAG_FILELINKTOS:
331  break;
332  }
333 
334  keyp = rpmdsN(ds);
335  if (keyp == NULL)
336  return rc;
337 
338  if (ts->sdb == NULL) {
339  xx = rpmtsOpenSDB(ts, ts->sdbmode);
340  if (xx) return rc;
341  }
342 
343  /* Look for a matching Provides: in suggested universe. */
344  rpmtag = (*keyp == '/' ? RPMTAG_BASENAMES : RPMTAG_PROVIDENAME);
345  mi = rpmmiInit(ts->sdb, rpmtag, keyp, keylen);
346  while ((h = rpmmiNext(mi)) != NULL) {
347  size_t hnamelen;
348  time_t htime;
349 
350  if (rpmtag == RPMTAG_PROVIDENAME && !rpmdsAnyMatchesDep(h, ds, 1))
351  continue;
352 
353  he->tag = RPMTAG_NAME;
354  xx = headerGet(h, he, 0);
355  hnamelen = ((xx && he->p.str) ? strlen(he->p.str) : 0);
356  he->p.ptr = _free(he->p.ptr);
357 
358  /* XXX Prefer the shortest pkg N for basenames/provides resp. */
359  if (bhnamelen > 0 && hnamelen > bhnamelen)
360  continue;
361 
362  /* XXX Prefer the newest build if given alternatives. */
363  he->tag = RPMTAG_BUILDTIME;
364  xx = headerGet(h, he, 0);
365  htime = (xx && he->p.ui32p ? he->p.ui32p[0] : 0);
366  he->p.ptr = _free(he->p.ptr);
367 
368  if (htime <= bhtime)
369  continue;
370 
371  /* Save new "best" candidate. */
372  (void)headerFree(bh);
373  bh = NULL;
374  bh = headerLink(h);
375  bhtime = htime;
376  bhnamelen = hnamelen;
377  }
378  mi = rpmmiFree(mi);
379 
380  /* Is there a suggested resolution? */
381  if (bh == NULL)
382  goto exit;
383 
384  /* Format the suggested resolution path. */
385  qfmt = rpmExpand("%{?_solve_name_fmt}", NULL);
386  if (qfmt == NULL || *qfmt == '\0')
387  goto exit;
388  str = headerSprintf(bh, qfmt, NULL, rpmHeaderFormats, &errstr);
389  (void)headerFree(bh);
390  bh = NULL;
391  qfmt = _free(qfmt);
392  if (str == NULL) {
393  rpmlog(RPMLOG_ERR, _("incorrect solve path format: %s\n"), errstr);
394  goto exit;
395  }
396 
397  if (ts->depFlags & RPMDEPS_FLAG_ADDINDEPS) {
398  FD_t fd;
399  rpmRC rpmrc;
400 
401  fd = Fopen(str, "r.fdio");
402  if (fd == NULL || Ferror(fd)) {
403  rpmlog(RPMLOG_ERR, _("open of %s failed: %s\n"), str,
404  Fstrerror(fd));
405  if (fd != NULL) {
406  xx = Fclose(fd);
407  fd = NULL;
408  }
409  str = _free(str);
410  goto exit;
411  }
412  rpmrc = rpmReadPackageFile(ts, fd, str, &h);
413  xx = Fclose(fd);
414  switch (rpmrc) {
415  default:
416  break;
417  case RPMRC_NOTTRUSTED:
418  case RPMRC_NOKEY:
419  case RPMRC_OK:
420  if (h != NULL &&
421  !rpmtsAddInstallElement(ts, h, (fnpyKey)str, 1, NULL))
422  {
423  rpmlog(RPMLOG_DEBUG, D_("Adding: %s\n"), str);
424  rc = -1; /* XXX restart unsatisfiedDepends() */
425  break;
426  }
427  break;
428  }
429  str = _free(str);
430  (void)headerFree(h);
431  h = NULL;
432  goto exit;
433  }
434 
435  rpmlog(RPMLOG_DEBUG, D_("Suggesting: %s\n"), str);
436  /* If suggestion is already present, don't bother. */
437  if (ts->suggests != NULL && ts->nsuggests > 0) {
438  if (bsearch(&str, ts->suggests, ts->nsuggests,
439  sizeof(*ts->suggests), sugcmp))
440  {
441  str = _free(str);
442  goto exit;
443  }
444  }
445 
446  /* Add a new (unique) suggestion. */
447  ts->suggests = xrealloc(ts->suggests,
448  sizeof(*ts->suggests) * (ts->nsuggests + 2));
449  ts->suggests[ts->nsuggests] = str;
450  ts->nsuggests++;
451  ts->suggests[ts->nsuggests] = NULL;
452 
453  if (ts->nsuggests > 1)
454  qsort(ts->suggests, ts->nsuggests, sizeof(*ts->suggests), sugcmp);
455 
456 exit:
457 /*@-nullstate@*/ /* FIX: ts->suggests[] may be NULL */
458  return rc;
459 /*@=nullstate@*/
460 }
461 
462 int rpmtsAvailable(rpmts ts, const rpmds ds)
463 {
464  fnpyKey * sugkey;
465  int rc = 1; /* assume not found */
466 
467  if (ts->availablePackages == NULL)
468  return rc;
469  sugkey = rpmalAllSatisfiesDepend(ts->availablePackages, ds, NULL);
470  if (sugkey == NULL)
471  return rc;
472 
473  /* XXX no alternatives yet */
474  if (sugkey[0] != NULL) {
475  ts->suggests = xrealloc(ts->suggests,
476  sizeof(*ts->suggests) * (ts->nsuggests + 2));
477  ts->suggests[ts->nsuggests] = sugkey[0];
478  sugkey[0] = NULL;
479  ts->nsuggests++;
480  ts->suggests[ts->nsuggests] = NULL;
481  }
482  sugkey = _free(sugkey);
483 /*@-nullstate@*/ /* FIX: ts->suggests[] may be NULL */
484  return rc;
485 /*@=nullstate@*/
486 }
487 
489  int (*solve) (rpmts ts, rpmds key, const void * data),
490  const void * solveData)
491 {
492  int rc = 0;
493 
494  if (ts) {
495 /*@-assignexpose -temptrans @*/
496  ts->solve = solve;
497  ts->solveData = solveData;
498 /*@=assignexpose =temptrans @*/
499  }
500  return rc;
501 }
502 
504 {
505  static const char msg[] = "rpmtsProblems";
506  rpmps ps = NULL;
507  if (ts) {
508  if (ts->probs == NULL)
509  ts->probs = rpmpsCreate();
510 /*@-castexpose@*/
511  ps = rpmpsLink(ts->probs, msg);
512 /*@=castexpose@*/
513  }
514  return ps;
515 }
516 
518 {
519  rpmtsi pi; rpmte p;
520 
521  if (ts == NULL)
522  return;
523 
524  /* Clean up after dependency checks. */
525  pi = rpmtsiInit(ts);
526  while ((p = rpmtsiNext(pi, 0)) != NULL)
527  rpmteCleanDS(p);
528  pi = rpmtsiFree(pi);
529 
530  ts->addedPackages = rpmalFree(ts->addedPackages);
531  ts->numAddedPackages = 0;
532 
533  ts->erasedPackages = rpmalFree(ts->erasedPackages);
534  ts->numErasedPackages = 0;
535 
536  ts->suggests = _free(ts->suggests);
537  ts->nsuggests = 0;
538 
539  ts->probs = rpmpsFree(ts->probs);
540 
541  rpmtsCleanDig(ts);
542 }
543 
545 {
546  rpmtsi pi; rpmte p;
547  int oc;
548 
549  if (ts == NULL)
550  return;
551 
552 /*@-nullstate@*/ /* FIX: partial annotations */
553  rpmtsClean(ts);
554 /*@=nullstate@*/
555 
556  for (pi = rpmtsiInit(ts), oc = 0; (p = rpmtsiNext(pi, 0)) != NULL; oc++) {
557 /*@-type -unqualifiedtrans @*/
558  ts->order[oc] = rpmteFree(ts->order[oc]);
559 /*@=type =unqualifiedtrans @*/
560  }
561  pi = rpmtsiFree(pi);
562 
563  ts->orderCount = 0;
564  ts->ntrees = 0;
565  ts->maxDepth = 0;
566 
567  ts->numRemovedPackages = 0;
568 /*@-nullstate@*/ /* FIX: partial annotations */
569  return;
570 /*@=nullstate@*/
571 }
572 
573 static void rpmtsPrintStat(const char * name, /*@null@*/ struct rpmop_s * op)
574  /*@globals fileSystem @*/
575  /*@modifies fileSystem @*/
576 {
577  static unsigned int scale = (1000 * 1000);
578  if (op != NULL && op->count > 0)
579  fprintf(stderr, " %s %8d %6lu.%06lu MB %6lu.%06lu secs\n",
580  name, op->count,
581  (unsigned long)op->bytes/scale, (unsigned long)op->bytes%scale,
582  op->usecs/scale, op->usecs%scale);
583 }
584 
585 /*@unchecked@*/ /*@relnull@*/
586 extern rpmop _hdr_loadops;
587 /*@unchecked@*/ /*@relnull@*/
588 extern rpmop _hdr_getops;
589 
590 static void rpmtsPrintStats(rpmts ts)
591  /*@globals fileSystem, internalState @*/
592  /*@modifies fileSystem, internalState @*/
593 {
594  (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_TOTAL), 0);
595 
596  if (_hdr_loadops)
598  if (_hdr_getops)
600 
601  rpmtsPrintStat("total: ", rpmtsOp(ts, RPMTS_OP_TOTAL));
602  rpmtsPrintStat("check: ", rpmtsOp(ts, RPMTS_OP_CHECK));
603  rpmtsPrintStat("order: ", rpmtsOp(ts, RPMTS_OP_ORDER));
604  rpmtsPrintStat("fingerprint: ", rpmtsOp(ts, RPMTS_OP_FINGERPRINT));
605  rpmtsPrintStat("repackage: ", rpmtsOp(ts, RPMTS_OP_REPACKAGE));
606  rpmtsPrintStat("install: ", rpmtsOp(ts, RPMTS_OP_INSTALL));
607  rpmtsPrintStat("erase: ", rpmtsOp(ts, RPMTS_OP_ERASE));
608  rpmtsPrintStat("scriptlets: ", rpmtsOp(ts, RPMTS_OP_SCRIPTLETS));
609  rpmtsPrintStat("compress: ", rpmtsOp(ts, RPMTS_OP_COMPRESS));
610  rpmtsPrintStat("uncompress: ", rpmtsOp(ts, RPMTS_OP_UNCOMPRESS));
611  rpmtsPrintStat("digest: ", rpmtsOp(ts, RPMTS_OP_DIGEST));
612  rpmtsPrintStat("signature: ", rpmtsOp(ts, RPMTS_OP_SIGNATURE));
613  rpmtsPrintStat("dbadd: ", rpmtsOp(ts, RPMTS_OP_DBADD));
614  rpmtsPrintStat("dbremove: ", rpmtsOp(ts, RPMTS_OP_DBREMOVE));
615  rpmtsPrintStat("dbget: ", rpmtsOp(ts, RPMTS_OP_DBGET));
616  rpmtsPrintStat("dbput: ", rpmtsOp(ts, RPMTS_OP_DBPUT));
617  rpmtsPrintStat("dbdel: ", rpmtsOp(ts, RPMTS_OP_DBDEL));
618  rpmtsPrintStat("readhdr: ", rpmtsOp(ts, RPMTS_OP_READHDR));
619  rpmtsPrintStat("hdrload: ", rpmtsOp(ts, RPMTS_OP_HDRLOAD));
620  rpmtsPrintStat("hdrget: ", rpmtsOp(ts, RPMTS_OP_HDRGET));
621 /*@-globstate@*/
622  return;
623 /*@=globstate@*/
624 }
625 
626 static void rpmtsFini(void * _ts)
627  /*@modifies _ts @*/
628 {
629  rpmts ts = _ts;
630 
631 /*@-nullstate@*/ /* FIX: partial annotations */
632  /* XXX there's a recursion here ... release and reacquire the lock */
633 #ifndef BUGGY
634  yarnRelease(ts->_item.use); /* XXX hack-o-round */
635 #endif
636  rpmtsEmpty(ts);
637 #ifndef BUGGY
638  yarnPossess(ts->_item.use); /* XXX hack-o-round */
639 #endif
640 /*@=nullstate@*/
641 
642  ts->PRCO = rpmdsFreePRCO(ts->PRCO);
643 
644  (void) rpmtsCloseDB(ts);
645 
646  (void) rpmtsCloseSDB(ts);
647 
648  ts->sx = rpmsxFree(ts->sx);
649 
650  ts->removedPackages = _free(ts->removedPackages);
651 
652  ts->availablePackages = rpmalFree(ts->availablePackages);
653  ts->numAvailablePackages = 0;
654 
655  ts->dsi = _free(ts->dsi);
656 
657  if (ts->scriptFd != NULL) {
658 /*@-refcounttrans@*/ /* FIX: XfdFree annotation */
659  ts->scriptFd = fdFree(ts->scriptFd, __FUNCTION__);
660 /*@=refcounttrans@*/
661  ts->scriptFd = NULL;
662  }
663  ts->rootDir = _free(ts->rootDir);
664  ts->currDir = _free(ts->currDir);
665 
666 /*@-type +voidabstract @*/ /* FIX: double indirection */
667  ts->order = _free(ts->order);
668 /*@=type =voidabstract @*/
669  ts->orderAlloced = 0;
670 
671  ts->keyring = rpmKeyringFree(ts->keyring);
672  ts->pkpkt = _free(ts->pkpkt);
673  ts->pkpktlen = 0;
674  memset(ts->pksignid, 0, sizeof(ts->pksignid));
675 
676  if (_rpmts_stats)
677  rpmtsPrintStats(ts);
678 
679  if (_rpmts_macros) {
680  const char ** av = NULL;
681 /*@-globs@*/ /* Avoid rpmGlobalMcroContext et al. */
682  (void)rpmGetMacroEntries(NULL, NULL, 1, &av);
683 /*@=globs@*/
684  argvPrint("macros used", av, NULL);
685  av = argvFree(av);
686  }
687 }
688 
689 /*@unchecked@*/ /*@only@*/ /*@null@*/
691 
692 static rpmts rpmtsGetPool(/*@null@*/ rpmioPool pool)
693  /*@globals _rpmtsPool, fileSystem, internalState @*/
694  /*@modifies pool, _rpmtsPool, fileSystem, internalState @*/
695 {
696  rpmts ts;
697 
698  if (_rpmtsPool == NULL) {
699  _rpmtsPool = rpmioNewPool("ts", sizeof(*ts), -1, _rpmts_debug,
700  NULL, NULL, rpmtsFini);
701  pool = _rpmtsPool;
702  }
703  return (rpmts) rpmioGetPool(pool, sizeof(*ts));
704 }
705 
706 void * rpmtsGetKeyring(rpmts ts, /*@unused@*/ int autoload)
707 {
708  rpmKeyring keyring = NULL;
709  if (ts) {
710 #ifdef NOTYET
711  if (ts->keyring == NULL && autoload)
712  loadKeyring(ts);
713  keyring = rpmKeyringLink(ts->keyring);
714 #else
715  keyring = ts->keyring;
716 #endif
717  }
718 /*@-refcounttrans@*/
719  return (void *)keyring;
720 /*@=refcounttrans@*/
721 }
722 
723 int rpmtsSetKeyring(rpmts ts, void * _keyring)
724 {
725  rpmKeyring keyring = _keyring;
726 
727  if (ts == NULL)
728  return -1;
729 
730 #ifdef NOTYET
731  /*
732  * Should we permit switching keyring on the fly? For now, require
733  * rpmdb isn't open yet (fairly arbitrary limitation)...
734  */
735  if (rpmtsGetRdb(ts) != NULL)
736  return -1;
737 #endif
738 
739 /*@-modnomods@*/
740  ts->keyring = rpmKeyringFree(ts->keyring);
741 /*@=modnomods@*/
742 
743 #ifdef NOTYET
744  ts->keyring = rpmKeyringLink(keyring);
745 #else
746 /*@-assignexpose -newreftrans @*/
747 /*@i@*/ ts->keyring = keyring;
748 /*@=assignexpose =newreftrans @*/
749 #endif
750 
751  return 0;
752 }
753 
754 rpmVSFlags rpmtsVSFlags(/*@unused@*/ rpmts ts)
755 {
756  return pgpDigVSFlags;
757 }
758 
760  /*@globals pgpDigVSFlags @*/
761  /*@modifies pgpDigVSFlags @*/
762 {
763  rpmVSFlags ovsflags;
764  ovsflags = pgpDigVSFlags;
766  return ovsflags;
767 }
768 
769 /*
770  * This allows us to mark transactions as being of a certain type.
771  * The three types are:
772  *
773  * RPM_TRANS_NORMAL
774  * RPM_TRANS_ROLLBACK
775  * RPM_TRANS_AUTOROLLBACK
776  *
777  * ROLLBACK and AUTOROLLBACK transactions should always be ran as
778  * a best effort. In particular this is important to the autorollback
779  * feature to avoid rolling back a rollback (otherwise known as
780  * dueling rollbacks (-;). AUTOROLLBACK's additionally need instance
781  * counts passed to scriptlets to be altered.
782  */
783 /* Let them know what type of transaction we are */
785 {
786  return ((ts != NULL) ? ts->type : 0);
787 }
788 
790 {
791  if (ts != NULL)
792  ts->type = type;
793 }
794 
796 {
797  return ((ts != NULL) ? ts->arbgoal : 0);
798 }
799 
801 {
802  if (ts != NULL)
803  ts->arbgoal = goal;
804 }
805 
806 int rpmtsUnorderedSuccessors(rpmts ts, int first)
807 {
808  int unorderedSuccessors = 0;
809  if (ts != NULL) {
810  unorderedSuccessors = ts->unorderedSuccessors;
811  if (first >= 0)
812  ts->unorderedSuccessors = first;
813  }
814  return unorderedSuccessors;
815 }
816 
817 const char * rpmtsRootDir(rpmts ts)
818 {
819  const char * rootDir = NULL;
820 
821  if (ts != NULL && ts->rootDir != NULL) {
822  urltype ut = urlPath(ts->rootDir, &rootDir);
823  switch (ut) {
824  case URL_IS_UNKNOWN:
825  case URL_IS_PATH:
826  break;
827  case URL_IS_HTTPS:
828  case URL_IS_HTTP:
829  case URL_IS_HKP:
830  case URL_IS_FTP:
831  case URL_IS_DASH:
832  default:
833  rootDir = "/";
834  break;
835  }
836  }
837  return rootDir;
838 }
839 
840 void rpmtsSetRootDir(rpmts ts, const char * rootDir)
841 {
842  if (ts != NULL) {
843  size_t rootLen;
844 
845  ts->rootDir = _free(ts->rootDir);
846 
847  if (rootDir == NULL) {
848 #ifndef DYING
849  ts->rootDir = xstrdup("");
850 #endif
851  return;
852  }
853  rootLen = strlen(rootDir);
854 
855  /* Make sure that rootDir has trailing / */
856  if (!(rootLen && rootDir[rootLen - 1] == '/')) {
857  char * t = alloca(rootLen + 2);
858  *t = '\0';
859  (void) stpcpy( stpcpy(t, rootDir), "/");
860  rootDir = t;
861  }
862  ts->rootDir = xstrdup(rootDir);
863  }
864 }
865 
866 const char * rpmtsCurrDir(rpmts ts)
867 {
868  const char * currDir = NULL;
869  if (ts != NULL) {
870  currDir = ts->currDir;
871  }
872  return currDir;
873 }
874 
875 void rpmtsSetCurrDir(rpmts ts, const char * currDir)
876 {
877  if (ts != NULL) {
878  ts->currDir = _free(ts->currDir);
879  if (currDir)
880  ts->currDir = xstrdup(currDir);
881  }
882 }
883 
885 {
886  FD_t scriptFd = NULL;
887  if (ts != NULL) {
888  scriptFd = ts->scriptFd;
889  }
890 /*@-compdef -refcounttrans -usereleased@*/
891  return scriptFd;
892 /*@=compdef =refcounttrans =usereleased@*/
893 }
894 
895 void rpmtsSetScriptFd(rpmts ts, FD_t scriptFd)
896 {
897 
898  if (ts != NULL) {
899  if (ts->scriptFd != NULL) {
900 /*@-assignexpose@*/
901  ts->scriptFd = fdFree(ts->scriptFd, "rpmtsSetScriptFd");
902 /*@=assignexpose@*/
903  ts->scriptFd = NULL;
904  }
905 /*@-assignexpose -castexpose @*/
906  if (scriptFd != NULL)
907  ts->scriptFd = fdLink((void *)scriptFd, "rpmtsSetScriptFd");
908 /*@=assignexpose =castexpose @*/
909  }
910 }
911 
913 {
914  int selinuxEnabled = 0;
915  if (ts)
916  selinuxEnabled = (ts->selinuxEnabled > 0);
917  return selinuxEnabled;
918 }
919 
921 {
922  return (ts != NULL ? ts->chrootDone : 0);
923 }
924 
925 int rpmtsSetChrootDone(rpmts ts, int chrootDone)
926 {
927  int ochrootDone = 0;
928  if (ts != NULL) {
929  ochrootDone = ts->chrootDone;
930  if (ts->rdb != NULL)
931  ts->rdb->db_chrootDone = chrootDone;
932  ts->chrootDone = chrootDone;
933  }
934  return ochrootDone;
935 }
936 
938 {
939  rpmuint32_t tid = 0; /* XXX -1 is time(2) error return. */
940  if (ts != NULL) {
941  tid = ts->tid[0];
942  }
943  return tid;
944 }
945 
947 {
948  rpmuint32_t otid = 0; /* XXX -1 is time(2) error return. */
949  if (ts != NULL) {
950  otid = ts->tid[0];
951  ts->tid[0] = tid;
952  ts->tid[1] = 0;
953  }
954  return otid;
955 }
956 
958 {
959  rpmPRCO PRCO = NULL;
960 
961  if (ts != NULL) {
962  static int oneshot = 0;
963  if (!oneshot) {
964  const char * fn = rpmGetPath("%{?_rpmds_sysinfo_path}", NULL);
965  int xx;
966 
967  ts->PRCO = rpmdsNewPRCO(NULL);
968  if (fn && *fn != '\0' && !rpmioAccess(fn, NULL, R_OK))
969  xx = rpmdsSysinfo(ts->PRCO, NULL);
970  fn = _free(fn);
971  oneshot++;
972  }
973  PRCO = ts->PRCO;
974  }
975 /*@-compdef -retexpose -usereleased @*/
976  return PRCO;
977 /*@=compdef =retexpose =usereleased @*/
978 }
979 
980 int rpmtsInitDSI(const rpmts ts)
981 {
982  rpmDiskSpaceInfo dsi;
983  struct stat sb;
984  int rc;
985  size_t i;
986 
988  return 0;
989  if (ts->filesystems != NULL)
990  return 0;
991 
992  rpmlog(RPMLOG_DEBUG, D_("mounted filesystems:\n"));
994  D_(" i dev bsize bavail iavail mount point\n"));
995 
996  rc = rpmGetFilesystemList(&ts->filesystems, &ts->filesystemCount);
997  if (rc || ts->filesystems == NULL || ts->filesystemCount == 0)
998  return rc;
999 
1000  /* Get available space on mounted file systems. */
1001 
1002  ts->dsi = _free(ts->dsi);
1003  ts->dsi = xcalloc((ts->filesystemCount + 1), sizeof(*ts->dsi));
1004 
1005  dsi = ts->dsi;
1006 
1007  if (dsi != NULL)
1008  for (i = 0; (i < ts->filesystemCount) && dsi; i++, dsi++) {
1009 #if STATFS_IN_SYS_STATVFS
1010  struct statvfs sfb;
1011  memset(&sfb, 0, sizeof(sfb));
1012  rc = statvfs(ts->filesystems[i], &sfb);
1013 #else
1014  struct statfs sfb;
1015  memset(&sfb, 0, sizeof(sfb));
1016 # if STAT_STATFS4
1017 /* This platform has the 4-argument version of the statfs call. The last two
1018  * should be the size of struct statfs and 0, respectively. The 0 is the
1019  * filesystem type, and is always 0 when statfs is called on a mounted
1020  * filesystem, as we're doing.
1021  */
1022  rc = statfs(ts->filesystems[i], &sfb, sizeof(sfb), 0);
1023 # else
1024  rc = statfs(ts->filesystems[i], &sfb);
1025 # endif
1026 #endif
1027  if (rc)
1028  break;
1029 
1030  rc = stat(ts->filesystems[i], &sb);
1031  if (rc)
1032  break;
1033  dsi->dev = sb.st_dev;
1034 /* XXX figger out how to get this info for non-statvfs systems. */
1035 #if STATFS_IN_SYS_STATVFS
1036  dsi->f_frsize = sfb.f_frsize;
1037 #if defined(RPM_OS_AIX)
1038  dsi->f_fsid = 0; /* sfb.f_fsid is a structure on AIX */
1039 #else
1040  dsi->f_fsid = sfb.f_fsid;
1041 #endif
1042  dsi->f_flag = sfb.f_flag;
1043  dsi->f_favail = (long long) sfb.f_favail;
1044  dsi->f_namemax = sfb.f_namemax;
1045 #elif defined(__APPLE__) && defined(__MACH__) && !defined(_SYS_STATVFS_H_)
1046  dsi->f_fsid = 0; /* "Not meaningful in this implementation." */
1047  dsi->f_namemax = pathconf(ts->filesystems[i], _PC_NAME_MAX);
1048 #elif defined(__OpenBSD__)
1049  dsi->f_fsid = 0; /* sfb.f_fsid is a structure on OpenBSD */
1050  dsi->f_namemax = pathconf(ts->filesystems[i], _PC_NAME_MAX);
1051 #else
1052  dsi->f_fsid = sfb.f_fsid;
1053  dsi->f_namemax = sfb.f_namelen;
1054 #endif
1055 
1056  dsi->f_bsize = sfb.f_bsize;
1057  dsi->f_blocks = (unsigned long long)sfb.f_blocks;
1058  dsi->f_bfree = (unsigned long long)sfb.f_bfree;
1059  dsi->f_files = (unsigned long long)sfb.f_files;
1060  dsi->f_ffree = (unsigned long long)sfb.f_ffree;
1061 
1062  dsi->bneeded = 0;
1063  dsi->ineeded = 0;
1064 #ifdef STATFS_HAS_F_BAVAIL
1065  dsi->f_bavail = (long long)(sfb.f_bavail ? sfb.f_bavail : 1);
1066  if (sfb.f_ffree > 0 && sfb.f_files > 0 && sfb.f_favail > 0)
1067  dsi->f_favail = (long long)sfb.f_favail;
1068  else /* XXX who knows what evil lurks here? */
1069  dsi->f_favail = !(sfb.f_ffree == 0 && sfb.f_files == 0)
1070  ? (signed long long) sfb.f_ffree : -1;
1071 #else
1072 /* FIXME: the statfs struct doesn't have a member to tell how many blocks are
1073  * available for non-superusers. f_blocks - f_bfree is probably too big, but
1074  * it's about all we can do.
1075  */
1076  dsi->f_bavail = sfb.f_blocks - sfb.f_bfree;
1077  /* XXX Avoid FAT and other file systems that have not inodes. */
1078  dsi->f_favail = !(sfb.f_ffree == 0 && sfb.f_files == 0)
1079  ? sfb.f_ffree : -1;
1080 #endif
1081 
1082 #if !defined(ST_RDONLY)
1083 #define ST_RDONLY 1
1084 #endif
1085  rpmlog(RPMLOG_DEBUG, "%5u 0x%08x %8u %12ld %12ld %s %s\n",
1086  (unsigned)i, (unsigned) dsi->dev, (unsigned) dsi->f_bsize,
1087  (signed long) dsi->f_bavail, (signed long) dsi->f_favail,
1088  ((dsi->f_flag & ST_RDONLY) ? "ro" : "rw"),
1089  ts->filesystems[i]);
1090  }
1091  return rc;
1092 }
1093 
1094 void rpmtsUpdateDSI(const rpmts ts, dev_t dev,
1095  rpmuint32_t fileSize, rpmuint32_t prevSize, rpmuint32_t fixupSize,
1096  int _action)
1097 {
1098  iosmFileAction action = _action;
1099  rpmDiskSpaceInfo dsi;
1100  rpmuint64_t bneeded;
1101 
1102  dsi = ts->dsi;
1103  if (dsi) {
1104  while (dsi->f_bsize && dsi->dev != dev)
1105  dsi++;
1106  if (dsi->f_bsize == 0)
1107  dsi = NULL;
1108  }
1109  if (dsi == NULL)
1110  return;
1111 
1112  bneeded = BLOCK_ROUND(fileSize, dsi->f_bsize);
1113 
1114  switch (action) {
1115  case FA_BACKUP:
1116  case FA_SAVE:
1117  case FA_ALTNAME:
1118  dsi->ineeded++;
1119  dsi->bneeded += bneeded;
1120  /*@switchbreak@*/ break;
1121 
1122  /*
1123  * FIXME: If two packages share a file (same md5sum), and
1124  * that file is being replaced on disk, will dsi->bneeded get
1125  * adjusted twice? Quite probably!
1126  */
1127  case FA_CREATE:
1128  dsi->bneeded += bneeded;
1129  dsi->bneeded -= BLOCK_ROUND(prevSize, dsi->f_bsize);
1130  /*@switchbreak@*/ break;
1131 
1132  case FA_ERASE:
1133  dsi->ineeded--;
1134  dsi->bneeded -= bneeded;
1135  /*@switchbreak@*/ break;
1136 
1137  default:
1138  /*@switchbreak@*/ break;
1139  }
1140 
1141  if (fixupSize)
1142  dsi->bneeded -= BLOCK_ROUND(fixupSize, dsi->f_bsize);
1143 }
1144 
1145 void rpmtsCheckDSIProblems(const rpmts ts, const rpmte te)
1146 {
1147  rpmDiskSpaceInfo dsi;
1148  rpmps ps;
1149  int fc;
1150  size_t i;
1151 
1152  if (ts->filesystems == NULL || ts->filesystemCount == 0)
1153  return;
1154 
1155  dsi = ts->dsi;
1156  if (dsi == NULL)
1157  return;
1158  fc = rpmfiFC( rpmteFI(te, RPMTAG_BASENAMES) );
1159  if (fc <= 0)
1160  return;
1161 
1162  ps = rpmtsProblems(ts);
1163  for (i = 0; i < ts->filesystemCount; i++, dsi++) {
1164 
1165  if (dsi->f_bavail > 0 && adj_fs_blocks(dsi->bneeded) > dsi->f_bavail) {
1167  rpmteNEVR(te), rpmteKey(te),
1168  ts->filesystems[i], NULL, NULL,
1169  (adj_fs_blocks(dsi->bneeded) - dsi->f_bavail) * dsi->f_bsize);
1170  }
1171 
1172  if (dsi->f_favail > 0 && adj_fs_blocks(dsi->ineeded) > dsi->f_favail) {
1174  rpmteNEVR(te), rpmteKey(te),
1175  ts->filesystems[i], NULL, NULL,
1176  (adj_fs_blocks(dsi->ineeded) - dsi->f_favail));
1177  }
1178 
1179  if ((dsi->bneeded || dsi->ineeded) && (dsi->f_flag & ST_RDONLY)) {
1181  rpmteNEVR(te), rpmteKey(te),
1182  ts->filesystems[i], NULL, NULL, 0);
1183  }
1184  }
1185  ps = rpmpsFree(ps);
1186 }
1187 
1188 void * rpmtsNotify(rpmts ts, rpmte te,
1189  rpmCallbackType what, rpmuint64_t amount, rpmuint64_t total)
1190 {
1191  void * ptr = NULL;
1192  if (ts && ts->notify) {
1193  Header h;
1194  fnpyKey cbkey;
1195  /*@-type@*/ /* FIX: cast? */
1196  /*@-noeffectuncon @*/ /* FIX: check rc */
1197  if (te) {
1198 /*@-castexpose -mods@*/ /* XXX noisy in transaction.c */
1199  h = headerLink(te->h);
1200 /*@=castexpose =mods@*/
1201  cbkey = rpmteKey(te);
1202  } else {
1203  h = NULL;
1204  cbkey = NULL;
1205  }
1206  ptr = ts->notify(h, what, amount, total, cbkey, ts->notifyData);
1207  (void)headerFree(h);
1208  h = NULL;
1209  /*@=noeffectuncon @*/
1210  /*@=type@*/
1211  }
1212  return ptr;
1213 }
1214 
1216 {
1217  int nelements = 0;
1218  if (ts != NULL && ts->order != NULL) {
1219  nelements = ts->orderCount;
1220  }
1221  return nelements;
1222 }
1223 
1225 {
1226  rpmte te = NULL;
1227  if (ts != NULL && ts->order != NULL) {
1228  if (ix >= 0 && ix < ts->orderCount)
1229  te = ts->order[ix];
1230  }
1231  /*@-compdef@*/
1232  return te;
1233  /*@=compdef@*/
1234 }
1235 
1237 {
1238  return (ts != NULL ? ts->ignoreSet : 0);
1239 }
1240 
1242 {
1243  rpmtransFlags transFlags = 0;
1244  if (ts != NULL) {
1245  transFlags = ts->transFlags;
1246  if (rpmtsSELinuxEnabled(ts) > 0)
1247  transFlags &= ~RPMTRANS_FLAG_NOCONTEXTS;
1248  else
1249  transFlags |= RPMTRANS_FLAG_NOCONTEXTS;
1250  }
1251  return transFlags;
1252 }
1253 
1255 {
1256  rpmtransFlags otransFlags = 0;
1257  if (ts != NULL) {
1258  otransFlags = ts->transFlags;
1259  if (rpmtsSELinuxEnabled(ts) > 0)
1260  transFlags &= ~RPMTRANS_FLAG_NOCONTEXTS;
1261  else
1262  transFlags |= RPMTRANS_FLAG_NOCONTEXTS;
1263  ts->transFlags = transFlags;
1264  }
1265  return otransFlags;
1266 }
1267 
1269 {
1270  return (ts != NULL ? ts->depFlags : 0);
1271 }
1272 
1274 {
1275  rpmdepFlags odepFlags = 0;
1276  if (ts != NULL) {
1277  odepFlags = ts->depFlags;
1278  ts->depFlags = depFlags;
1279  }
1280  return odepFlags;
1281 }
1282 
1284 {
1285 /*@-compdef -retexpose -usereleased@*/
1286  return ts->spec;
1287 /*@=compdef =retexpose =usereleased@*/
1288 }
1289 
1291 {
1292  Spec ospec = ts->spec;
1293 /*@-assignexpose -temptrans@*/
1294  ts->spec = spec;
1295 /*@=assignexpose =temptrans@*/
1296  return ospec;
1297 }
1298 
1300 {
1301 /*@-compdef -retexpose -usereleased@*/
1302  return ts->relocateElement;
1303 /*@=compdef =retexpose =usereleased@*/
1304 }
1305 
1307 {
1308  rpmte orelocateElement = ts->relocateElement;
1309 /*@-assignexpose -temptrans@*/
1310  ts->relocateElement = relocateElement;
1311 /*@=assignexpose =temptrans@*/
1312  return orelocateElement;
1313 }
1314 
1316 {
1317  return (ts != NULL ? ts->goal : TSM_UNKNOWN);
1318 }
1319 
1321 {
1322  tsmStage ogoal = TSM_UNKNOWN;
1323  if (ts != NULL) {
1324  ogoal = ts->goal;
1325  ts->goal = goal;
1326  }
1327  return ogoal;
1328 }
1329 
1331 {
1332  return (ts != NULL ? ts->dbmode : 0);
1333 }
1334 
1335 int rpmtsSetDBMode(rpmts ts, int dbmode)
1336 {
1337  int odbmode = 0;
1338  if (ts != NULL) {
1339  odbmode = ts->dbmode;
1340  ts->dbmode = dbmode;
1341  }
1342  return odbmode;
1343 }
1344 
1346 {
1347  return (ts != NULL ? ts->color : 0);
1348 }
1349 
1351 {
1352  rpmuint32_t ocolor = 0;
1353  if (ts != NULL) {
1354  ocolor = ts->color;
1355  ts->color = color;
1356  }
1357  return ocolor;
1358 }
1359 
1361 {
1362  return (ts != NULL ? ts->prefcolor : 0);
1363 }
1364 
1366  rpmCallbackFunction notify, rpmCallbackData notifyData)
1367 {
1368  if (ts != NULL) {
1369  ts->notify = notify;
1370  ts->notifyData = notifyData;
1371  }
1372  return 0;
1373 }
1374 
1376 {
1377  rpmts ts = rpmtsGetPool(_rpmtsPool);
1378  int xx;
1379 
1380  memset(&ts->ops, 0, sizeof(ts->ops));
1381  (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_TOTAL), -1);
1382  ts->type = RPMTRANS_TYPE_NORMAL;
1383  ts->goal = TSM_UNKNOWN;
1384  ts->filesystemCount = 0;
1385  ts->filesystems = NULL;
1386  ts->dsi = NULL;
1387 
1388  ts->solve = rpmtsSolve;
1389  ts->solveData = NULL;
1390  ts->nsuggests = 0;
1391  ts->suggests = NULL;
1392 
1393  ts->PRCO = NULL;
1394 
1395  ts->sdb = NULL;
1396  ts->sdbmode = O_RDONLY;
1397 
1398  ts->rdb = NULL;
1399  ts->dbmode = O_RDONLY;
1400 
1401  ts->scriptFd = NULL;
1402  { struct timeval tv;
1403  xx = gettimeofday(&tv, NULL);
1404  ts->tid[0] = (rpmuint32_t) tv.tv_sec;
1405  ts->tid[1] = (rpmuint32_t) tv.tv_usec;
1406  }
1407  ts->delta = 5;
1408 
1409  ts->color = rpmExpandNumeric("%{?_transaction_color}");
1410  ts->prefcolor = rpmExpandNumeric("%{?_prefer_color}");
1411  if (!ts->prefcolor) ts->prefcolor = 0x2;
1412 
1413  ts->numRemovedPackages = 0;
1414  ts->allocedRemovedPackages = ts->delta;
1415  ts->removedPackages = xcalloc(ts->allocedRemovedPackages,
1416  sizeof(*ts->removedPackages));
1417 
1418  ts->rootDir = NULL;
1419  ts->currDir = NULL;
1420  ts->chrootDone = 0;
1421 
1422  ts->selinuxEnabled = is_selinux_enabled();
1423 
1424  ts->numAddedPackages = 0;
1425  ts->addedPackages = NULL;
1426 
1427  ts->numErasedPackages = 0;
1428  ts->erasedPackages = NULL;
1429 
1430  ts->numAvailablePackages = 0;
1431  ts->availablePackages = NULL;
1432 
1433  ts->orderAlloced = 0;
1434  ts->orderCount = 0;
1435  ts->order = NULL;
1436  ts->ntrees = 0;
1437  ts->maxDepth = 0;
1438 
1439  ts->probs = NULL;
1440 
1441  ts->keyring = NULL;
1442  ts->pkpkt = NULL;
1443  ts->pkpktlen = 0;
1444  memset(ts->pksignid, 0, sizeof(ts->pksignid));
1445  ts->dig = NULL;
1446 
1447  /* Set autorollback goal to the end of time. */
1448  ts->arbgoal = 0xffffffff;
1449 
1450  return rpmtsLink(ts, "tsCreate");
1451 }