rpm  4.5
rpmts.c
Go to the documentation of this file.
1 
5 #include "system.h"
6 
7 #include "rpmio_internal.h" /* XXX for pgp and beecrypt */
8 #include <rpmlib.h>
9 #include <rpmmacro.h> /* XXX rpmtsOpenDB() needs rpmGetPath */
10 
11 #define _RPMDB_INTERNAL /* XXX almost opaque sigh */
12 #include "rpmdb.h" /* XXX stealing db->db_mode. */
13 
14 #define _RPMEVR_INTERNAL /* XXX RPMSENSE_KEYRING */
15 #include "rpmevr.h"
16 
17 #include "rpmal.h"
18 #include "rpmds.h"
19 #include "rpmfi.h"
20 #include "rpmlock.h"
21 #include "rpmns.h"
22 
23 #define _RPMTE_INTERNAL /* XXX te->h */
24 #include "rpmte.h"
25 
26 #define _RPMTS_INTERNAL
27 #include "rpmts.h"
28 
29 #include "fs.h"
30 
31 /* XXX FIXME: merge with existing (broken?) tests in system.h */
32 /* portability fiddles */
33 #if STATFS_IN_SYS_STATVFS
34 /*@-incondefs@*/
35 #if defined(__LCLINT__)
36 /*@-declundef -exportheader -protoparammatch @*/ /* LCL: missing annotation */
37 extern int statvfs (const char * file, /*@out@*/ struct statvfs * buf)
38  /*@globals fileSystem @*/
39  /*@modifies *buf, fileSystem @*/;
40 /*@=declundef =exportheader =protoparammatch @*/
41 /*@=incondefs@*/
42 #else
43 # include <sys/statvfs.h>
44 #endif
45 #else
46 # if STATFS_IN_SYS_VFS
47 # include <sys/vfs.h>
48 # else
49 # if STATFS_IN_SYS_MOUNT
50 # include <sys/mount.h>
51 # else
52 # if STATFS_IN_SYS_STATFS
53 # include <sys/statfs.h>
54 # endif
55 # endif
56 # endif
57 #endif
58 
59 #include "debug.h"
60 
61 /*@access rpmdb @*/ /* XXX db->db_chrootDone, NULL */
62 
63 /*@access rpmps @*/
64 /*@access rpmDiskSpaceInfo @*/
65 /*@access rpmsx @*/
66 /*@access rpmte @*/
67 /*@access rpmtsi @*/
68 /*@access fnpyKey @*/
69 /*@access pgpDig @*/
70 /*@access pgpDigParams @*/
71 
72 /*@unchecked@*/
73 int _rpmts_debug = 0;
74 
75 /*@unchecked@*/
76 int _rpmts_stats = 0;
77 
78 rpmts XrpmtsUnlink(rpmts ts, const char * msg, const char * fn, unsigned ln)
79 {
80 /*@-modfilesys@*/
81 if (_rpmts_debug)
82 fprintf(stderr, "--> ts %p -- %d %s at %s:%u\n", ts, ts->nrefs, msg, fn, ln);
83 /*@=modfilesys@*/
84  ts->nrefs--;
85  return NULL;
86 }
87 
88 rpmts XrpmtsLink(rpmts ts, const char * msg, const char * fn, unsigned ln)
89 {
90  ts->nrefs++;
91 /*@-modfilesys@*/
92 if (_rpmts_debug)
93 fprintf(stderr, "--> ts %p ++ %d %s at %s:%u\n", ts, ts->nrefs, msg, fn, ln);
94 /*@=modfilesys@*/
95  /*@-refcounttrans@*/ return ts; /*@=refcounttrans@*/
96 }
97 
99 {
100  int rc = 0;
101 
102  if (ts->rdb != NULL) {
103  (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBGET), &ts->rdb->db_getops);
104  (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBPUT), &ts->rdb->db_putops);
105  (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBDEL), &ts->rdb->db_delops);
106  rc = rpmdbClose(ts->rdb);
107  ts->rdb = NULL;
108  }
109  return rc;
110 }
111 
112 int rpmtsOpenDB(rpmts ts, int dbmode)
113 {
114  int rc = 0;
115 
116  if (ts->rdb != NULL && ts->dbmode == dbmode)
117  return 0;
118 
119  (void) rpmtsCloseDB(ts);
120 
121  /* XXX there's a potential db lock race here. */
122 
123  ts->dbmode = dbmode;
124  rc = rpmdbOpen(ts->rootDir, &ts->rdb, ts->dbmode, 0644);
125  if (rc) {
126  const char * dn;
127  dn = rpmGetPath(ts->rootDir, "%{_dbpath}", NULL);
129  _("cannot open Packages database in %s\n"), dn);
130  dn = _free(dn);
131  }
132  return rc;
133 }
134 
135 int rpmtsInitDB(rpmts ts, int dbmode)
136 {
137  void *lock = rpmtsAcquireLock(ts);
138  int rc = rpmdbInit(ts->rootDir, dbmode);
139  lock = rpmtsFreeLock(lock);
140  return rc;
141 }
142 
144 {
145  void *lock = rpmtsAcquireLock(ts);
146  int rc;
147  if (!(ts->vsflags & RPMVSF_NOHDRCHK))
148  rc = rpmdbRebuild(ts->rootDir, ts, headerCheck);
149  else
150  rc = rpmdbRebuild(ts->rootDir, NULL, NULL);
151  lock = rpmtsFreeLock(lock);
152  return rc;
153 }
154 
156 {
157  return rpmdbVerify(ts->rootDir);
158 }
159 
160 /*@-compdef@*/ /* keyp might no be defined. */
162  const void * keyp, size_t keylen)
163 {
165  const char * arch = NULL;
166  int xx;
167 
168  if (ts->rdb == NULL && rpmtsOpenDB(ts, ts->dbmode))
169  return NULL;
170 
171  /* Parse out "N(EVR).A" tokens from a label key. */
172 /*@-bounds -branchstate@*/
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++ = c;
186  /*@switchbreak@*/ break;
187  case '(':
188  /* XXX Fail if nested parens. */
189  if (level++ != 0) {
190  rpmError(RPMERR_QFMT, _("extra '(' in package label: %s\n"), 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  rpmError(RPMERR_QFMT, _("missing '(' in package label: %s\n"), keyp);
209  return NULL;
210  }
211  /* Don't copy trailing ')' */
212  /*@switchbreak@*/ break;
213  }
214  }
215  if (level) {
216  rpmError(RPMERR_QFMT, _("missing ')' in package label: %s\n"), 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 /*@=bounds =branchstate@*/
229 
230  mi = rpmdbInitIterator(ts->rdb, rpmtag, keyp, keylen);
231 
232  /* Verify header signature/digest during retrieve (if not disabled). */
233  if (mi && !(ts->vsflags & RPMVSF_NOHDRCHK))
234  (void) rpmdbSetHdrChk(mi, ts, headerCheck);
235 
236  /* Select specified arch only. */
237  if (arch != NULL)
238  xx = rpmdbSetIteratorRE(mi, RPMTAG_ARCH, RPMMIRE_DEFAULT, arch);
239  return mi;
240 }
241 /*@=compdef@*/
242 
244 {
245  const void * sig = rpmtsSig(ts);
246  pgpDig dig = rpmtsDig(ts);
247  pgpDigParams sigp = rpmtsSignature(ts);
248  pgpDigParams pubp = rpmtsPubkey(ts);
249  rpmRC res = RPMRC_NOKEY;
250  const char * pubkeysource = NULL;
251  int xx;
252 
253  if (sig == NULL || dig == NULL || sigp == NULL || pubp == NULL)
254  goto exit;
255 
256 #if 0
257 fprintf(stderr, "==> find sig id %08x %08x ts pubkey id %08x %08x\n",
258 pgpGrab(sigp->signid, 4), pgpGrab(sigp->signid+4, 4),
259 pgpGrab(ts->pksignid, 4), pgpGrab(ts->pksignid+4, 4));
260 #endif
261 
262  /* Lazy free of previous pubkey if pubkey does not match this signature. */
263  if (memcmp(sigp->signid, ts->pksignid, sizeof(ts->pksignid))) {
264 #if 0
265 fprintf(stderr, "*** free pkt %p[%d] id %08x %08x\n", ts->pkpkt, ts->pkpktlen, pgpGrab(ts->pksignid, 4), pgpGrab(ts->pksignid+4, 4));
266 #endif
267  ts->pkpkt = _free(ts->pkpkt);
268  ts->pkpktlen = 0;
269  memset(ts->pksignid, 0, sizeof(ts->pksignid));
270  }
271 
272  /* Try rpmdb keyring lookup. */
273  if (ts->pkpkt == NULL) {
274  int hx = -1;
275  int ix = -1;
277  Header h;
278 
279  /* Retrieve the pubkey that matches the signature. */
280  mi = rpmtsInitIterator(ts, RPMTAG_PUBKEYS, sigp->signid, sizeof(sigp->signid));
281  while ((h = rpmdbNextIterator(mi)) != NULL) {
282  const char ** pubkeys;
283  int_32 pt, pc;
284 
285  if (!headerGetEntry(h, RPMTAG_PUBKEYS, &pt, &pubkeys, &pc))
286  continue;
287  hx = rpmdbGetIteratorOffset(mi);
288  ix = rpmdbGetIteratorFileNum(mi);
289 /*@-boundsread@*/
290  if (ix >= pc
291  || b64decode(pubkeys[ix], (void **) &ts->pkpkt, &ts->pkpktlen))
292  ix = -1;
293 /*@=boundsread@*/
294  pubkeys = headerFreeData(pubkeys, pt);
295  break;
296  }
297  mi = rpmdbFreeIterator(mi);
298 
299 /*@-branchstate@*/
300  if (ix >= 0) {
301  char hnum[32];
302  sprintf(hnum, "h#%d", hx);
303  pubkeysource = xstrdup(hnum);
304  } else {
305  ts->pkpkt = _free(ts->pkpkt);
306  ts->pkpktlen = 0;
307  }
308 /*@=branchstate@*/
309  }
310 
311  /* Try keyserver lookup. */
312  if (ts->pkpkt == NULL) {
313  const char * fn = rpmExpand("%{_hkp_keyserver_query}",
314  pgpHexStr(sigp->signid, sizeof(sigp->signid)), NULL);
315 
316  xx = 0;
317  if (fn && *fn != '%') {
318  xx = (pgpReadPkts(fn,&ts->pkpkt,&ts->pkpktlen) != PGPARMOR_PUBKEY);
319  }
320  fn = _free(fn);
321 /*@-branchstate@*/
322  if (xx) {
323  ts->pkpkt = _free(ts->pkpkt);
324  ts->pkpktlen = 0;
325  } else {
326  /* Save new pubkey in local ts keyring for delayed import. */
327  pubkeysource = xstrdup("keyserver");
328  }
329 /*@=branchstate@*/
330  }
331 
332 #ifdef NOTNOW
333  /* Try filename from macro lookup. */
334  if (ts->pkpkt == NULL) {
335  const char * fn = rpmExpand("%{_gpg_pubkey}", NULL);
336 
337  xx = 0;
338  if (fn && *fn != '%')
339  xx = (pgpReadPkts(fn,&ts->pkpkt,&ts->pkpktlen) != PGPARMOR_PUBKEY);
340  fn = _free(fn);
341  if (xx) {
342  ts->pkpkt = _free(ts->pkpkt);
343  ts->pkpktlen = 0;
344  } else {
345  pubkeysource = xstrdup("macro");
346  }
347  }
348 #endif
349 
350  /* Was a matching pubkey found? */
351  if (ts->pkpkt == NULL || ts->pkpktlen == 0)
352  goto exit;
353 
354  /* Retrieve parameters from pubkey packet(s). */
355  xx = pgpPrtPkts(ts->pkpkt, ts->pkpktlen, dig, 0);
356 
357  /* Do the parameters match the signature? */
358  if (sigp->pubkey_algo == pubp->pubkey_algo
359 #ifdef NOTYET
360  && sigp->hash_algo == pubp->hash_algo
361 #endif
362  && !memcmp(sigp->signid, pubp->signid, sizeof(sigp->signid)) )
363  {
364 
365  /* XXX Verify any pubkey signatures. */
366 
367  /* Pubkey packet looks good, save the signer id. */
368 /*@-boundsread@*/
369  memcpy(ts->pksignid, pubp->signid, sizeof(ts->pksignid));
370 /*@=boundsread@*/
371 
372  if (pubkeysource)
373  rpmMessage(RPMMESS_DEBUG, "========== %s pubkey id %08x %08x (%s)\n",
374  (sigp->pubkey_algo == PGPPUBKEYALGO_DSA ? "DSA" :
375  (sigp->pubkey_algo == PGPPUBKEYALGO_RSA ? "RSA" : "???")),
376  pgpGrab(sigp->signid, 4), pgpGrab(sigp->signid+4, 4),
377  pubkeysource);
378 
379  res = RPMRC_OK;
380  }
381 
382 exit:
383  pubkeysource = _free(pubkeysource);
384  if (res != RPMRC_OK) {
385  ts->pkpkt = _free(ts->pkpkt);
386  ts->pkpktlen = 0;
387  }
388  return res;
389 }
390 
392 {
393  int rc = 0;
394 
395  if (ts->sdb != NULL) {
396  (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBGET), &ts->sdb->db_getops);
397  (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBPUT), &ts->sdb->db_putops);
398  (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBDEL), &ts->sdb->db_delops);
399  rc = rpmdbClose(ts->sdb);
400  ts->sdb = NULL;
401  }
402  return rc;
403 }
404 
405 int rpmtsOpenSDB(rpmts ts, int dbmode)
406 {
407  static int has_sdbpath = -1;
408  int rc = 0;
409 
410  if (ts->sdb != NULL && ts->sdbmode == dbmode)
411  return 0;
412 
413  if (has_sdbpath < 0)
414  has_sdbpath = rpmExpandNumeric("%{?_solve_dbpath:1}");
415 
416  /* If not configured, don't try to open. */
417  if (has_sdbpath <= 0)
418  return 1;
419 
420  addMacro(NULL, "_dbpath", NULL, "%{_solve_dbpath}", RMIL_DEFAULT);
421 
422  rc = rpmdbOpen(ts->rootDir, &ts->sdb, ts->sdbmode, 0644);
423  if (rc) {
424  const char * dn;
425  dn = rpmGetPath(ts->rootDir, "%{_dbpath}", NULL);
427  _("cannot open Solve database in %s\n"), dn);
428  dn = _free(dn);
429  /* XXX only try to open the solvedb once. */
430  has_sdbpath = 0;
431  }
432  delMacro(NULL, "_dbpath");
433 
434  return rc;
435 }
436 
443 static int sugcmp(const void * a, const void * b)
444  /*@*/
445 {
446 /*@-boundsread@*/
447  const char * astr = *(const char **)a;
448  const char * bstr = *(const char **)b;
449 /*@=boundsread@*/
450  return strcmp(astr, bstr);
451 }
452 
453 /*@-bounds@*/
454 int rpmtsSolve(rpmts ts, rpmds ds, /*@unused@*/ const void * data)
455 {
456  const char * errstr;
457  const char * str = NULL;
458  const char * qfmt;
460  Header bh = NULL;
461  Header h = NULL;
462  size_t bhnamelen = 0;
463  time_t bhtime = 0;
464  rpmTag rpmtag;
465  const char * keyp;
466  size_t keylen = 0;
467  int rc = 1; /* assume not found */
468  int xx;
469 
470  /* Make suggestions only for installing Requires: */
471  if (ts->goal != TSM_INSTALL)
472  return rc;
473 
474  switch (rpmdsTagN(ds)) {
475  case RPMTAG_CONFLICTNAME:
476  default:
477  return rc;
478  /*@notreached@*/ break;
479  case RPMTAG_DIRNAMES: /* XXX perhaps too many wrong answers */
480  case RPMTAG_REQUIRENAME:
481  case RPMTAG_FILELINKTOS:
482  break;
483  }
484 
485  keyp = rpmdsN(ds);
486  if (keyp == NULL)
487  return rc;
488 
489  if (ts->sdb == NULL) {
490  xx = rpmtsOpenSDB(ts, ts->sdbmode);
491  if (xx) return rc;
492  }
493 
494  /* Look for a matching Provides: in suggested universe. */
495  rpmtag = (*keyp == '/' ? RPMTAG_BASENAMES : RPMTAG_PROVIDENAME);
496  mi = rpmdbInitIterator(ts->sdb, rpmtag, keyp, keylen);
497  while ((h = rpmdbNextIterator(mi)) != NULL) {
498  const char * hname;
499  size_t hnamelen;
500  time_t htime;
501  int_32 * ip;
502 
503  if (rpmtag == RPMTAG_PROVIDENAME && !rpmdsAnyMatchesDep(h, ds, 1))
504  continue;
505 
506  hname = NULL;
507  hnamelen = 0;
508  if (headerGetEntry(h, RPMTAG_NAME, NULL, &hname, NULL)) {
509  if (hname)
510  hnamelen = strlen(hname);
511  }
512 
513  /* XXX Prefer the shortest pkg N for basenames/provides resp. */
514  if (bhnamelen > 0)
515  if (hnamelen > bhnamelen)
516  continue;
517 
518  /* XXX Prefer the newest build if given alternatives. */
519  htime = 0;
520  if (headerGetEntry(h, RPMTAG_BUILDTIME, NULL, &ip, NULL))
521  htime = (time_t)*ip;
522 
523  if (htime <= bhtime)
524  continue;
525 
526  /* Save new "best" candidate. */
527  bh = headerFree(bh);
528  bh = headerLink(h);
529  bhtime = htime;
530  bhnamelen = hnamelen;
531  }
532  mi = rpmdbFreeIterator(mi);
533 
534  /* Is there a suggested resolution? */
535  if (bh == NULL)
536  goto exit;
537 
538  /* Format the suggested resolution path. */
539  qfmt = rpmExpand("%{?_solve_name_fmt}", NULL);
540  if (qfmt == NULL || *qfmt == '\0')
541  goto exit;
542  str = headerSprintf(bh, qfmt, rpmTagTable, rpmHeaderFormats, &errstr);
543  bh = headerFree(bh);
544  qfmt = _free(qfmt);
545  if (str == NULL) {
546  rpmError(RPMERR_QFMT, _("incorrect solve path format: %s\n"), errstr);
547  goto exit;
548  }
549 
550  if (ts->depFlags & RPMDEPS_FLAG_ADDINDEPS) {
551  FD_t fd;
552  rpmRC rpmrc;
553 
554  fd = Fopen(str, "r");
555  if (fd == NULL || Ferror(fd)) {
556  rpmError(RPMERR_OPEN, _("open of %s failed: %s\n"), str,
557  Fstrerror(fd));
558  if (fd != NULL) {
559  xx = Fclose(fd);
560  fd = NULL;
561  }
562  str = _free(str);
563  goto exit;
564  }
565  rpmrc = rpmReadPackageFile(ts, fd, str, &h);
566  xx = Fclose(fd);
567  switch (rpmrc) {
568  default:
569  break;
570  case RPMRC_NOTTRUSTED:
571  case RPMRC_NOKEY:
572  case RPMRC_OK:
573  if (h != NULL &&
574  !rpmtsAddInstallElement(ts, h, (fnpyKey)str, 1, NULL))
575  {
576  rpmMessage(RPMMESS_DEBUG, D_("Adding: %s\n"), str);
577  rc = -1; /* XXX restart unsatisfiedDepends() */
578  break;
579  }
580  break;
581  }
582  str = _free(str);
583  h = headerFree(h);
584  goto exit;
585  }
586 
587  rpmMessage(RPMMESS_DEBUG, D_("Suggesting: %s\n"), str);
588  /* If suggestion is already present, don't bother. */
589  if (ts->suggests != NULL && ts->nsuggests > 0) {
590  if (bsearch(&str, ts->suggests, ts->nsuggests,
591  sizeof(*ts->suggests), sugcmp))
592  {
593  str = _free(str);
594  goto exit;
595  }
596  }
597 
598  /* Add a new (unique) suggestion. */
599  ts->suggests = xrealloc(ts->suggests,
600  sizeof(*ts->suggests) * (ts->nsuggests + 2));
601  ts->suggests[ts->nsuggests] = str;
602  ts->nsuggests++;
603  ts->suggests[ts->nsuggests] = NULL;
604 
605  if (ts->nsuggests > 1)
606  qsort(ts->suggests, ts->nsuggests, sizeof(*ts->suggests), sugcmp);
607 
608 exit:
609 /*@-nullstate@*/ /* FIX: ts->suggests[] may be NULL */
610  return rc;
611 /*@=nullstate@*/
612 }
613 /*@=bounds@*/
614 
615 int rpmtsAvailable(rpmts ts, const rpmds ds)
616 {
617  fnpyKey * sugkey;
618  int rc = 1; /* assume not found */
619 
620  if (ts->availablePackages == NULL)
621  return rc;
622  sugkey = rpmalAllSatisfiesDepend(ts->availablePackages, ds, NULL);
623  if (sugkey == NULL)
624  return rc;
625 
626  /* XXX no alternatives yet */
627  if (sugkey[0] != NULL) {
628  ts->suggests = xrealloc(ts->suggests,
629  sizeof(*ts->suggests) * (ts->nsuggests + 2));
630  ts->suggests[ts->nsuggests] = sugkey[0];
631  sugkey[0] = NULL;
632  ts->nsuggests++;
633  ts->suggests[ts->nsuggests] = NULL;
634  }
635  sugkey = _free(sugkey);
636 /*@-nullstate@*/ /* FIX: ts->suggests[] may be NULL */
637  return rc;
638 /*@=nullstate@*/
639 }
640 
642  int (*solve) (rpmts ts, rpmds key, const void * data),
643  const void * solveData)
644 {
645  int rc = 0;
646 
647 /*@-branchstate@*/
648  if (ts) {
649 /*@-assignexpose -temptrans @*/
650  ts->solve = solve;
651  ts->solveData = solveData;
652 /*@=assignexpose =temptrans @*/
653  }
654 /*@=branchstate@*/
655  return rc;
656 }
657 
659 {
660  rpmps ps = NULL;
661  if (ts) {
662  if (ts->probs)
663  ps = rpmpsLink(ts->probs, __FUNCTION__);
664  }
665  return ps;
666 }
667 
669 {
670  ts->sig = headerFreeData(ts->sig, ts->sigtype);
671  ts->dig = pgpFreeDig(ts->dig);
672 }
673 
675 {
676  rpmtsi pi; rpmte p;
677 
678  if (ts == NULL)
679  return;
680 
681  /* Clean up after dependency checks. */
682  pi = rpmtsiInit(ts);
683  while ((p = rpmtsiNext(pi, 0)) != NULL)
684  rpmteCleanDS(p);
685  pi = rpmtsiFree(pi);
686 
687  ts->addedPackages = rpmalFree(ts->addedPackages);
688  ts->numAddedPackages = 0;
689 
690  ts->erasedPackages = rpmalFree(ts->erasedPackages);
691  ts->numErasedPackages = 0;
692 
693  ts->suggests = _free(ts->suggests);
694  ts->nsuggests = 0;
695 
696  ts->probs = rpmpsFree(ts->probs);
697 
698  rpmtsCleanDig(ts);
699 }
700 
702 {
703  rpmtsi pi; rpmte p;
704  int oc;
705 
706  if (ts == NULL)
707  return;
708 
709 /*@-nullstate@*/ /* FIX: partial annotations */
710  rpmtsClean(ts);
711 /*@=nullstate@*/
712 
713  for (pi = rpmtsiInit(ts), oc = 0; (p = rpmtsiNext(pi, 0)) != NULL; oc++) {
714 /*@-type -unqualifiedtrans @*/
715  ts->order[oc] = rpmteFree(ts->order[oc]);
716 /*@=type =unqualifiedtrans @*/
717  }
718  pi = rpmtsiFree(pi);
719 
720  ts->orderCount = 0;
721  ts->ntrees = 0;
722  ts->maxDepth = 0;
723 
724  ts->numRemovedPackages = 0;
725 /*@-nullstate@*/ /* FIX: partial annotations */
726  return;
727 /*@=nullstate@*/
728 }
729 
730 static void rpmtsPrintStat(const char * name, /*@null@*/ struct rpmop_s * op)
731  /*@globals fileSystem @*/
732  /*@modifies fileSystem @*/
733 {
734  static unsigned int scale = (1000 * 1000);
735  if (op != NULL && op->count > 0)
736  fprintf(stderr, " %s %8d %6lu.%06lu MB %6lu.%06lu secs\n",
737  name, op->count,
738  (unsigned long)op->bytes/scale, (unsigned long)op->bytes%scale,
739  op->usecs/scale, op->usecs%scale);
740 }
741 
742 static void rpmtsPrintStats(rpmts ts)
743  /*@globals fileSystem, internalState @*/
744  /*@modifies fileSystem, internalState @*/
745 {
746  (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_TOTAL), 0);
747 
748  rpmtsPrintStat("total: ", rpmtsOp(ts, RPMTS_OP_TOTAL));
749  rpmtsPrintStat("check: ", rpmtsOp(ts, RPMTS_OP_CHECK));
750  rpmtsPrintStat("order: ", rpmtsOp(ts, RPMTS_OP_ORDER));
751  rpmtsPrintStat("fingerprint: ", rpmtsOp(ts, RPMTS_OP_FINGERPRINT));
752  rpmtsPrintStat("repackage: ", rpmtsOp(ts, RPMTS_OP_REPACKAGE));
753  rpmtsPrintStat("install: ", rpmtsOp(ts, RPMTS_OP_INSTALL));
754  rpmtsPrintStat("erase: ", rpmtsOp(ts, RPMTS_OP_ERASE));
755  rpmtsPrintStat("scriptlets: ", rpmtsOp(ts, RPMTS_OP_SCRIPTLETS));
756  rpmtsPrintStat("compress: ", rpmtsOp(ts, RPMTS_OP_COMPRESS));
757  rpmtsPrintStat("uncompress: ", rpmtsOp(ts, RPMTS_OP_UNCOMPRESS));
758  rpmtsPrintStat("digest: ", rpmtsOp(ts, RPMTS_OP_DIGEST));
759  rpmtsPrintStat("signature: ", rpmtsOp(ts, RPMTS_OP_SIGNATURE));
760  rpmtsPrintStat("dbadd: ", rpmtsOp(ts, RPMTS_OP_DBADD));
761  rpmtsPrintStat("dbremove: ", rpmtsOp(ts, RPMTS_OP_DBREMOVE));
762  rpmtsPrintStat("dbget: ", rpmtsOp(ts, RPMTS_OP_DBGET));
763  rpmtsPrintStat("dbput: ", rpmtsOp(ts, RPMTS_OP_DBPUT));
764  rpmtsPrintStat("dbdel: ", rpmtsOp(ts, RPMTS_OP_DBDEL));
765  rpmtsPrintStat("readhdr: ", rpmtsOp(ts, RPMTS_OP_READHDR));
766 }
767 
769 {
770  if (ts == NULL)
771  return NULL;
772 
773  if (ts->nrefs > 1)
774  return rpmtsUnlink(ts, "tsCreate");
775 
776 /*@-nullstate@*/ /* FIX: partial annotations */
777  rpmtsEmpty(ts);
778 /*@=nullstate@*/
779 
780  ts->PRCO = rpmdsFreePRCO(ts->PRCO);
781 
782  (void) rpmtsCloseDB(ts);
783 
784  (void) rpmtsCloseSDB(ts);
785 
786  ts->sx = rpmsxFree(ts->sx);
787 
788  ts->removedPackages = _free(ts->removedPackages);
789 
790  ts->availablePackages = rpmalFree(ts->availablePackages);
791  ts->numAvailablePackages = 0;
792 
793  ts->dsi = _free(ts->dsi);
794 
795  if (ts->scriptFd != NULL) {
796  ts->scriptFd = fdFree(ts->scriptFd, "rpmtsFree");
797  ts->scriptFd = NULL;
798  }
799  ts->rootDir = _free(ts->rootDir);
800  ts->currDir = _free(ts->currDir);
801 
802 /*@-type +voidabstract @*/ /* FIX: double indirection */
803  ts->order = _free(ts->order);
804 /*@=type =voidabstract @*/
805  ts->orderAlloced = 0;
806 
807  if (ts->pkpkt != NULL)
808  ts->pkpkt = _free(ts->pkpkt);
809  ts->pkpktlen = 0;
810  memset(ts->pksignid, 0, sizeof(ts->pksignid));
811 
812  if (_rpmts_stats)
813  rpmtsPrintStats(ts);
814 
815  (void) rpmtsUnlink(ts, "tsCreate");
816 
817  /*@-refcounttrans -usereleased @*/
818  ts = _free(ts);
819  /*@=refcounttrans =usereleased @*/
820 
821  return NULL;
822 }
823 
825 {
826  rpmVSFlags vsflags = 0;
827  if (ts != NULL)
828  vsflags = ts->vsflags;
829  return vsflags;
830 }
831 
833 {
834  rpmVSFlags ovsflags = 0;
835  if (ts != NULL) {
836  ovsflags = ts->vsflags;
837  ts->vsflags = vsflags;
838  }
839  return ovsflags;
840 }
841 
842 /*
843  * This allows us to mark transactions as being of a certain type.
844  * The three types are:
845  *
846  * RPM_TRANS_NORMAL
847  * RPM_TRANS_ROLLBACK
848  * RPM_TRANS_AUTOROLLBACK
849  *
850  * ROLLBACK and AUTOROLLBACK transactions should always be ran as
851  * a best effort. In particular this is important to the autorollback
852  * feature to avoid rolling back a rollback (otherwise known as
853  * dueling rollbacks (-;). AUTOROLLBACK's additionally need instance
854  * counts passed to scriptlets to be altered.
855  */
856 /* Let them know what type of transaction we are */
858 {
859  return ((ts != NULL) ? ts->type : 0);
860 }
861 
863 {
864  if (ts != NULL)
865  ts->type = type;
866 }
867 
869 {
870  return ((ts != NULL) ? ts->arbgoal : 0);
871 }
872 
874 {
875  if (ts != NULL)
876  ts->arbgoal = goal;
877 }
878 
879 int rpmtsUnorderedSuccessors(rpmts ts, int first)
880 {
881  int unorderedSuccessors = 0;
882  if (ts != NULL) {
883  unorderedSuccessors = ts->unorderedSuccessors;
884  if (first >= 0)
885  ts->unorderedSuccessors = first;
886  }
887  return unorderedSuccessors;
888 }
889 
890 const char * rpmtsRootDir(rpmts ts)
891 {
892  const char * rootDir = NULL;
893 
894 /*@-branchstate@*/
895  if (ts != NULL && ts->rootDir != NULL) {
896  urltype ut = urlPath(ts->rootDir, &rootDir);
897  switch (ut) {
898  case URL_IS_UNKNOWN:
899  case URL_IS_PATH:
900  break;
901  case URL_IS_HTTPS:
902  case URL_IS_HTTP:
903  case URL_IS_HKP:
904  case URL_IS_FTP:
905  case URL_IS_DASH:
906  default:
907  rootDir = "/";
908  break;
909  }
910  }
911 /*@=branchstate@*/
912  return rootDir;
913 }
914 
915 void rpmtsSetRootDir(rpmts ts, const char * rootDir)
916 {
917  if (ts != NULL) {
918  size_t rootLen;
919 
920  ts->rootDir = _free(ts->rootDir);
921 
922  if (rootDir == NULL) {
923 #ifndef DYING
924  ts->rootDir = xstrdup("");
925 #endif
926  return;
927  }
928  rootLen = strlen(rootDir);
929 
930 /*@-branchstate@*/
931  /* Make sure that rootDir has trailing / */
932  if (!(rootLen && rootDir[rootLen - 1] == '/')) {
933  char * t = alloca(rootLen + 2);
934  *t = '\0';
935  (void) stpcpy( stpcpy(t, rootDir), "/");
936  rootDir = t;
937  }
938 /*@=branchstate@*/
939  ts->rootDir = xstrdup(rootDir);
940  }
941 }
942 
943 const char * rpmtsCurrDir(rpmts ts)
944 {
945  const char * currDir = NULL;
946  if (ts != NULL) {
947  currDir = ts->currDir;
948  }
949  return currDir;
950 }
951 
952 void rpmtsSetCurrDir(rpmts ts, const char * currDir)
953 {
954  if (ts != NULL) {
955  ts->currDir = _free(ts->currDir);
956  if (currDir)
957  ts->currDir = xstrdup(currDir);
958  }
959 }
960 
962 {
963  FD_t scriptFd = NULL;
964  if (ts != NULL) {
965  scriptFd = ts->scriptFd;
966  }
967 /*@-compdef -refcounttrans -usereleased@*/
968  return scriptFd;
969 /*@=compdef =refcounttrans =usereleased@*/
970 }
971 
972 void rpmtsSetScriptFd(rpmts ts, FD_t scriptFd)
973 {
974 
975  if (ts != NULL) {
976  if (ts->scriptFd != NULL) {
977  ts->scriptFd = fdFree(ts->scriptFd, "rpmtsSetScriptFd");
978  ts->scriptFd = NULL;
979  }
980 /*@+voidabstract@*/
981  if (scriptFd != NULL)
982  ts->scriptFd = fdLink((void *)scriptFd, "rpmtsSetScriptFd");
983 /*@=voidabstract@*/
984  }
985 }
986 
988 {
989  return (ts != NULL ? (ts->selinuxEnabled > 0) : 0);
990 }
991 
993 {
994  return (ts != NULL ? ts->chrootDone : 0);
995 }
996 
997 int rpmtsSetChrootDone(rpmts ts, int chrootDone)
998 {
999  int ochrootDone = 0;
1000  if (ts != NULL) {
1001  ochrootDone = ts->chrootDone;
1002  if (ts->rdb != NULL)
1003  ts->rdb->db_chrootDone = chrootDone;
1004  ts->chrootDone = chrootDone;
1005  }
1006  return ochrootDone;
1007 }
1008 
1010 {
1011  return ( (ts && ts->sx ? rpmsxLink(ts->sx, __func__) : NULL) );
1012 }
1013 
1015 {
1016  int rc = -1;
1017  if (ts != NULL) {
1018  ts->sx = rpmsxFree(ts->sx);
1019  ts->sx = rpmsxLink(sx, __func__);
1020  if (ts->sx != NULL)
1021  rc = 0;
1022  }
1023  return rc;
1024 }
1025 
1027 {
1028  int_32 tid = -1; /* XXX -1 is time(2) error return. */
1029  if (ts != NULL) {
1030  tid = ts->tid;
1031  }
1032  return tid;
1033 }
1034 
1036 {
1037  int_32 otid = -1; /* XXX -1 is time(2) error return. */
1038  if (ts != NULL) {
1039  otid = ts->tid;
1040  ts->tid = tid;
1041  }
1042  return otid;
1043 }
1044 
1046 {
1047  int_32 sigtag = 0;
1048  if (ts != NULL)
1049  sigtag = ts->sigtag;
1050  return sigtag;
1051 }
1052 
1054 {
1055  int_32 sigtype = 0;
1056  if (ts != NULL)
1057  sigtype = ts->sigtype;
1058  return sigtype;
1059 }
1060 
1061 const void * rpmtsSig(const rpmts ts)
1062 {
1063  const void * sig = NULL;
1064  if (ts != NULL)
1065  sig = ts->sig;
1066  return sig;
1067 }
1068 
1070 {
1071  int_32 siglen = 0;
1072  if (ts != NULL)
1073  siglen = ts->siglen;
1074  return siglen;
1075 }
1076 
1078  int_32 sigtag, int_32 sigtype, const void * sig, int_32 siglen)
1079 {
1080  if (ts != NULL) {
1081  if (ts->sig && ts->sigtype)
1082  ts->sig = headerFreeData(ts->sig, ts->sigtype);
1083  ts->sigtag = sigtag;
1084  ts->sigtype = (sig ? sigtype : 0);
1085 /*@-assignexpose -kepttrans@*/
1086  ts->sig = sig;
1087 /*@=assignexpose =kepttrans@*/
1088  ts->siglen = siglen;
1089  }
1090  return 0;
1091 }
1092 
1094 {
1095 /*@-mods@*/ /* FIX: hide lazy malloc for now */
1096  if (ts->dig == NULL)
1097  ts->dig = pgpNewDig();
1098 /*@=mods@*/
1099  if (ts->dig == NULL)
1100  return NULL;
1101  return ts->dig;
1102 }
1103 
1105 {
1106  pgpDig dig = rpmtsDig(ts);
1107  if (dig == NULL) return NULL;
1108 /*@-immediatetrans@*/
1109  return &dig->signature;
1110 /*@=immediatetrans@*/
1111 }
1112 
1114 {
1115  pgpDig dig = rpmtsDig(ts);
1116  if (dig == NULL) return NULL;
1117 /*@-immediatetrans@*/
1118  return &dig->pubkey;
1119 /*@=immediatetrans@*/
1120 }
1121 
1123 {
1124  rpmdb rdb = NULL;
1125  if (ts != NULL) {
1126  rdb = ts->rdb;
1127  }
1128 /*@-compdef -refcounttrans -usereleased @*/
1129  return rdb;
1130 /*@=compdef =refcounttrans =usereleased @*/
1131 }
1132 
1134 {
1135 /*@-compdef -retexpose -usereleased @*/
1136  return (ts != NULL ? ts->PRCO : NULL);
1137 /*@=compdef =retexpose =usereleased @*/
1138 }
1139 
1140 int rpmtsInitDSI(const rpmts ts)
1141 {
1142  rpmDiskSpaceInfo dsi;
1143  struct stat sb;
1144  int rc;
1145  int i;
1146 
1148  return 0;
1149  if (ts->filesystems != NULL)
1150  return 0;
1151 
1152  rpmMessage(RPMMESS_DEBUG, D_("mounted filesystems:\n"));
1154  D_(" i dev bsize bavail iavail mount point\n"));
1155 
1156  rc = rpmGetFilesystemList(&ts->filesystems, &ts->filesystemCount);
1157  if (rc || ts->filesystems == NULL || ts->filesystemCount <= 0)
1158  return rc;
1159 
1160  /* Get available space on mounted file systems. */
1161 
1162  ts->dsi = _free(ts->dsi);
1163  ts->dsi = xcalloc((ts->filesystemCount + 1), sizeof(*ts->dsi));
1164 
1165  dsi = ts->dsi;
1166 
1167  if (dsi != NULL)
1168  for (i = 0; (i < ts->filesystemCount) && dsi; i++, dsi++) {
1169 #if STATFS_IN_SYS_STATVFS
1170  struct statvfs sfb;
1171  memset(&sfb, 0, sizeof(sfb));
1172  rc = statvfs(ts->filesystems[i], &sfb);
1173 #else
1174  struct statfs sfb;
1175  memset(&sfb, 0, sizeof(sfb));
1176 # if STAT_STATFS4
1177 /* This platform has the 4-argument version of the statfs call. The last two
1178  * should be the size of struct statfs and 0, respectively. The 0 is the
1179  * filesystem type, and is always 0 when statfs is called on a mounted
1180  * filesystem, as we're doing.
1181  */
1182  rc = statfs(ts->filesystems[i], &sfb, sizeof(sfb), 0);
1183 # else
1184  rc = statfs(ts->filesystems[i], &sfb);
1185 # endif
1186 #endif
1187  if (rc)
1188  break;
1189 
1190  rc = stat(ts->filesystems[i], &sb);
1191  if (rc)
1192  break;
1193  dsi->dev = sb.st_dev;
1194 /* XXX figger out how to get this info for non-statvfs systems. */
1195 #if STATFS_IN_SYS_STATVFS
1196  dsi->f_frsize = sfb.f_frsize;
1197  dsi->f_fsid = sfb.f_fsid;
1198  dsi->f_flag = sfb.f_flag;
1199  dsi->f_favail = sfb.f_favail;
1200  dsi->f_namemax = sfb.f_namemax;
1201 #else
1202  dsi->f_fsid = sfb.f_fsid;
1203  dsi->f_namemax = sfb.f_namelen;
1204 #endif
1205 
1206  dsi->f_bsize = sfb.f_bsize;
1207  dsi->f_blocks = sfb.f_blocks;
1208  dsi->f_bfree = sfb.f_bfree;
1209  dsi->f_files = sfb.f_files;
1210  dsi->f_ffree = sfb.f_ffree;
1211 
1212  dsi->bneeded = 0;
1213  dsi->ineeded = 0;
1214 #ifdef STATFS_HAS_F_BAVAIL
1215  dsi->f_bavail = sfb.f_bavail ? sfb.f_bavail : 1;
1216  if (sfb.f_ffree > 0 && sfb.f_files > 0 && sfb.f_favail > 0)
1217  dsi->f_favail = sfb.f_favail;
1218  else /* XXX who knows what evil lurks here? */
1219  dsi->f_favail = !(sfb.f_ffree == 0 && sfb.f_files == 0)
1220  ? sfb.f_ffree : -1;
1221 #else
1222 /* FIXME: the statfs struct doesn't have a member to tell how many blocks are
1223  * available for non-superusers. f_blocks - f_bfree is probably too big, but
1224  * it's about all we can do.
1225  */
1226  dsi->f_bavail = sfb.f_blocks - sfb.f_bfree;
1227  /* XXX Avoid FAT and other file systems that have not inodes. */
1228  dsi->f_favail = !(sfb.f_ffree == 0 && sfb.f_files == 0)
1229  ? sfb.f_ffree : -1;
1230 #endif
1231 
1232 #if !defined(ST_RDONLY)
1233 #define ST_RDONLY 1
1234 #endif
1235  rpmMessage(RPMMESS_DEBUG, "%5d 0x%08x %8u %12ld %12ld %s %s\n",
1236  i, (unsigned) dsi->dev, (unsigned) dsi->f_bsize,
1237  (signed long) dsi->f_bavail, (signed long) dsi->f_favail,
1238  ((dsi->f_flag & ST_RDONLY) ? "ro" : "rw"),
1239  ts->filesystems[i]);
1240  }
1241  return rc;
1242 }
1243 
1244 void rpmtsUpdateDSI(const rpmts ts, dev_t dev,
1245  uint_32 fileSize, uint_32 prevSize, uint_32 fixupSize,
1246  fileAction action)
1247 {
1248  rpmDiskSpaceInfo dsi;
1249  unsigned long long bneeded;
1250 
1251  dsi = ts->dsi;
1252  if (dsi) {
1253  while (dsi->f_bsize && dsi->dev != dev)
1254  dsi++;
1255  if (dsi->f_bsize == 0)
1256  dsi = NULL;
1257  }
1258  if (dsi == NULL)
1259  return;
1260 
1261  bneeded = BLOCK_ROUND(fileSize, dsi->f_bsize);
1262 
1263  switch (action) {
1264  case FA_BACKUP:
1265  case FA_SAVE:
1266  case FA_ALTNAME:
1267  dsi->ineeded++;
1268  dsi->bneeded += bneeded;
1269  /*@switchbreak@*/ break;
1270 
1271  /*
1272  * FIXME: If two packages share a file (same md5sum), and
1273  * that file is being replaced on disk, will dsi->bneeded get
1274  * adjusted twice? Quite probably!
1275  */
1276  case FA_CREATE:
1277  dsi->bneeded += bneeded;
1278  dsi->bneeded -= BLOCK_ROUND(prevSize, dsi->f_bsize);
1279  /*@switchbreak@*/ break;
1280 
1281  case FA_ERASE:
1282  dsi->ineeded--;
1283  dsi->bneeded -= bneeded;
1284  /*@switchbreak@*/ break;
1285 
1286  default:
1287  /*@switchbreak@*/ break;
1288  }
1289 
1290  if (fixupSize)
1291  dsi->bneeded -= BLOCK_ROUND(fixupSize, dsi->f_bsize);
1292 }
1293 
1294 void rpmtsCheckDSIProblems(const rpmts ts, const rpmte te)
1295 {
1296  rpmDiskSpaceInfo dsi;
1297  rpmps ps;
1298  int fc;
1299  int i;
1300 
1301  if (ts->filesystems == NULL || ts->filesystemCount <= 0)
1302  return;
1303 
1304  dsi = ts->dsi;
1305  if (dsi == NULL)
1306  return;
1307  fc = rpmfiFC( rpmteFI(te, RPMTAG_BASENAMES) );
1308  if (fc <= 0)
1309  return;
1310 
1311  ps = rpmtsProblems(ts);
1312  for (i = 0; i < ts->filesystemCount; i++, dsi++) {
1313 
1314  if (dsi->f_bavail > 0 && adj_fs_blocks(dsi->bneeded) > dsi->f_bavail) {
1316  rpmteNEVR(te), rpmteKey(te),
1317  ts->filesystems[i], NULL, NULL,
1318  (adj_fs_blocks(dsi->bneeded) - dsi->f_bavail) * dsi->f_bsize);
1319  }
1320 
1321  if (dsi->f_favail > 0 && adj_fs_blocks(dsi->ineeded) > dsi->f_favail) {
1323  rpmteNEVR(te), rpmteKey(te),
1324  ts->filesystems[i], NULL, NULL,
1325  (adj_fs_blocks(dsi->ineeded) - dsi->f_favail));
1326  }
1327 
1328  if ((dsi->bneeded || dsi->ineeded) && (dsi->f_flag & ST_RDONLY)) {
1330  rpmteNEVR(te), rpmteKey(te),
1331  ts->filesystems[i], NULL, NULL, 0);
1332  }
1333  }
1334  ps = rpmpsFree(ps);
1335 }
1336 
1337 void * rpmtsNotify(rpmts ts, rpmte te,
1338  rpmCallbackType what, unsigned long long amount, unsigned long long total)
1339 {
1340  void * ptr = NULL;
1341  if (ts && ts->notify && te) {
1342 assert(!(te->type == TR_ADDED && te->h == NULL));
1343  /*@-type@*/ /* FIX: cast? */
1344  /*@-noeffectuncon @*/ /* FIX: check rc */
1345  ptr = ts->notify(te->h, what, amount, total,
1346  rpmteKey(te), ts->notifyData);
1347  /*@=noeffectuncon @*/
1348  /*@=type@*/
1349  }
1350  return ptr;
1351 }
1352 
1354 {
1355  int nelements = 0;
1356  if (ts != NULL && ts->order != NULL) {
1357  nelements = ts->orderCount;
1358  }
1359  return nelements;
1360 }
1361 
1363 {
1364  rpmte te = NULL;
1365  if (ts != NULL && ts->order != NULL) {
1366  if (ix >= 0 && ix < ts->orderCount)
1367  te = ts->order[ix];
1368  }
1369  /*@-compdef@*/
1370  return te;
1371  /*@=compdef@*/
1372 }
1373 
1375 {
1376  return (ts != NULL ? ts->ignoreSet : 0);
1377 }
1378 
1380 {
1381  return (ts != NULL ? ts->transFlags : 0);
1382 }
1383 
1385 {
1386  rpmtransFlags otransFlags = 0;
1387  if (ts != NULL) {
1388  otransFlags = ts->transFlags;
1389  ts->transFlags = transFlags;
1390  }
1391  return otransFlags;
1392 }
1393 
1395 {
1396  return (ts != NULL ? ts->depFlags : 0);
1397 }
1398 
1400 {
1401  rpmdepFlags odepFlags = 0;
1402  if (ts != NULL) {
1403  odepFlags = ts->depFlags;
1404  ts->depFlags = depFlags;
1405  }
1406  return odepFlags;
1407 }
1408 
1410 {
1411 /*@-compdef -retexpose -usereleased@*/
1412  return ts->spec;
1413 /*@=compdef =retexpose =usereleased@*/
1414 }
1415 
1417 {
1418  Spec ospec = ts->spec;
1419 /*@-assignexpose -temptrans@*/
1420  ts->spec = spec;
1421 /*@=assignexpose =temptrans@*/
1422  return ospec;
1423 }
1424 
1426 {
1427 /*@-compdef -retexpose -usereleased@*/
1428  return ts->relocateElement;
1429 /*@=compdef =retexpose =usereleased@*/
1430 }
1431 
1433 {
1434  rpmte orelocateElement = ts->relocateElement;
1435 /*@-assignexpose -temptrans@*/
1436  ts->relocateElement = relocateElement;
1437 /*@=assignexpose =temptrans@*/
1438  return orelocateElement;
1439 }
1440 
1442 {
1443  return (ts != NULL ? ts->color : 0);
1444 }
1445 
1447 {
1448  uint_32 ocolor = 0;
1449  if (ts != NULL) {
1450  ocolor = ts->color;
1451  ts->color = color;
1452  }
1453  return ocolor;
1454 }
1455 
1457 {
1458  return (ts != NULL ? ts->prefcolor : 0);
1459 }
1460 
1462 {
1463  rpmop op = NULL;
1464 
1465  if (ts != NULL && opx >= 0 && opx < RPMTS_OP_MAX)
1466  op = ts->ops + opx;
1467 /*@-usereleased -compdef @*/
1468  return op;
1469 /*@=usereleased =compdef @*/
1470 }
1471 
1473  rpmCallbackFunction notify, rpmCallbackData notifyData)
1474 {
1475  if (ts != NULL) {
1476  ts->notify = notify;
1477  ts->notifyData = notifyData;
1478  }
1479  return 0;
1480 }
1481 
1483 {
1484  rpmts ts;
1485  int xx;
1486 
1487  ts = xcalloc(1, sizeof(*ts));
1488  memset(&ts->ops, 0, sizeof(ts->ops));
1489  (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_TOTAL), -1);
1490  ts->type = RPMTRANS_TYPE_NORMAL;
1491  ts->goal = TSM_UNKNOWN;
1492  ts->filesystemCount = 0;
1493  ts->filesystems = NULL;
1494  ts->dsi = NULL;
1495 
1496  ts->solve = rpmtsSolve;
1497  ts->solveData = NULL;
1498  ts->nsuggests = 0;
1499  ts->suggests = NULL;
1500 
1501  ts->PRCO = rpmdsNewPRCO(NULL);
1502  { const char * fn = rpmGetPath("%{?_rpmds_sysinfo_path}", NULL);
1503  if (fn && *fn != '\0' && !rpmioAccess(fn, NULL, R_OK))
1504  xx = rpmdsSysinfo(ts->PRCO, NULL);
1505  fn = _free(fn);
1506  }
1507 
1508  ts->sdb = NULL;
1509  ts->sdbmode = O_RDONLY;
1510 
1511  ts->rdb = NULL;
1512  ts->dbmode = O_RDONLY;
1513 
1514  ts->scriptFd = NULL;
1515  ts->tid = (int_32) time(NULL);
1516  ts->delta = 5;
1517 
1518  ts->color = rpmExpandNumeric("%{?_transaction_color}");
1519  ts->prefcolor = rpmExpandNumeric("%{?_prefer_color}");
1520  if (!ts->prefcolor) ts->prefcolor = 0x2;
1521 
1522  ts->numRemovedPackages = 0;
1523  ts->allocedRemovedPackages = ts->delta;
1524  ts->removedPackages = xcalloc(ts->allocedRemovedPackages,
1525  sizeof(*ts->removedPackages));
1526 
1527  ts->rootDir = NULL;
1528  ts->currDir = NULL;
1529  ts->chrootDone = 0;
1530 
1531  ts->selinuxEnabled = is_selinux_enabled();
1532 
1533  ts->numAddedPackages = 0;
1534  ts->addedPackages = NULL;
1535 
1536  ts->numErasedPackages = 0;
1537  ts->erasedPackages = NULL;
1538 
1539  ts->numAvailablePackages = 0;
1540  ts->availablePackages = NULL;
1541 
1542  ts->orderAlloced = 0;
1543  ts->orderCount = 0;
1544  ts->order = NULL;
1545  ts->ntrees = 0;
1546  ts->maxDepth = 0;
1547 
1548  ts->probs = NULL;
1549 
1550  ts->sig = NULL;
1551  ts->pkpkt = NULL;
1552  ts->pkpktlen = 0;
1553  memset(ts->pksignid, 0, sizeof(ts->pksignid));
1554  ts->dig = NULL;
1555 
1556  /* Set autorollback goal to the end of time. */
1557  ts->arbgoal = 0xffffffff;
1558 
1559  ts->nrefs = 0;
1560 
1561  return rpmtsLink(ts, "tsCreate");
1562 }