1 /** \ingroup rpmdep
2  * \file lib/rpmte.c
3  * Routine(s) to handle an "rpmte"  transaction element.
4  */
5 #include "system.h"
6 
7 #include <rpm/rpmtypes.h>
8 #include <rpm/rpmlib.h>		/* RPM_MACHTABLE_* */
9 #include <rpm/rpmmacro.h>
10 #include <rpm/rpmds.h>
11 #include <rpm/rpmfi.h>
12 #include <rpm/rpmts.h>
13 #include <rpm/rpmdb.h>
14 #include <rpm/rpmlog.h>
15 
16 #include "lib/misc.h"
17 #include "lib/rpmplugins.h"
18 #include "lib/rpmte_internal.h"
19 /* strpool-related interfaces */
20 #include "lib/rpmfi_internal.h"
21 #include "lib/rpmds_internal.h"
22 #include "lib/rpmts_internal.h"
23 
24 #include "debug.h"
25 
26 /** \ingroup rpmte
27  * A single package instance to be installed/removed atomically.
28  */
29 struct rpmte_s {
30     rpmElementType type;	/*!< Package disposition (installed/removed). */
31 
32     Header h;			/*!< Package header. */
33     char * NEVR;		/*!< Package name-version-release. */
34     char * NEVRA;		/*!< Package name-version-release.arch. */
35     char * name;		/*!< Name: */
36     char * epoch;
37     char * version;		/*!< Version: */
38     char * release;		/*!< Release: */
39     char * arch;		/*!< Architecture hint. */
40     char * os;			/*!< Operating system hint. */
41     int isSource;		/*!< (TR_ADDED) source rpm? */
42 
43     rpmte depends;              /*!< Package updated by this package (ERASE te) */
44     rpmte parent;		/*!< Parent transaction element. */
45     unsigned int db_instance;	/*!< Database instance (of removed pkgs) */
46     tsortInfo tsi;		/*!< Dependency ordering chains. */
47 
48     rpmds thisds;		/*!< This package's provided NEVR. */
49     rpmds provides;		/*!< Provides: dependencies. */
50     rpmds requires;		/*!< Requires: dependencies. */
51     rpmds conflicts;		/*!< Conflicts: dependencies. */
52     rpmds obsoletes;		/*!< Obsoletes: dependencies. */
53     rpmds order;		/*!< Order: dependencies. */
54     rpmds recommends;		/*!< Recommends: dependencies. */
55     rpmds suggests;		/*!< Suggests: dependencies. */
56     rpmds supplements;		/*!< Supplements: dependencies. */
57     rpmds enhances;		/*!< Enhances: dependencies. */
58     rpmfiles files;		/*!< File information. */
59     rpmfi fi;			/*!< File iterator (backwards compat) */
60     rpmps probs;		/*!< Problems (relocations) */
61     rpmts ts;			/*!< Parent transaction */
62 
63     rpm_color_t color;		/*!< Color bit(s) from package dependencies. */
64     rpm_loff_t pkgFileSize;	/*!< No. of bytes in package file (approx). */
65     unsigned int headerSize;	/*!< No. of bytes in package header */
66 
67     fnpyKey key;		/*!< (TR_ADDED) Retrieval key. */
68     rpmRelocation * relocs;	/*!< (TR_ADDED) Payload file relocations. */
69     int nrelocs;		/*!< (TR_ADDED) No. of relocations. */
70     uint8_t *badrelocs;		/*!< (TR_ADDED) Bad relocations (or NULL) */
71     FD_t fd;			/*!< (TR_ADDED) Payload file descriptor. */
72     int verified;		/*!< (TR_ADDED) Verification status */
73     int addop;			/*!< (TR_ADDED) RPMTE_INSTALL/UPDATE/REINSTALL */
74 
75 #define RPMTE_HAVE_PRETRANS	(1 << 0)
76 #define RPMTE_HAVE_POSTTRANS	(1 << 1)
77     int transscripts;		/*!< pre/posttrans script existence */
78     int failed;			/*!< (parent) install/erase failed */
79 
80     rpmfs fs;
81 };
82 
83 /* forward declarations */
84 static void rpmteColorDS(rpmte te, rpmTag tag);
85 static int rpmteClose(rpmte te, int reset_fi);
86 
rpmteCleanDS(rpmte te)87 void rpmteCleanDS(rpmte te)
88 {
89     te->thisds = rpmdsFree(te->thisds);
90     te->provides = rpmdsFree(te->provides);
91     te->requires = rpmdsFree(te->requires);
92     te->conflicts = rpmdsFree(te->conflicts);
93     te->obsoletes = rpmdsFree(te->obsoletes);
94     te->recommends = rpmdsFree(te->recommends);
95     te->suggests = rpmdsFree(te->suggests);
96     te->supplements = rpmdsFree(te->supplements);
97     te->enhances = rpmdsFree(te->enhances);
98     te->order = rpmdsFree(te->order);
99 }
100 
getFiles(rpmte p,Header h)101 static rpmfiles getFiles(rpmte p, Header h)
102 {
103     /* TR_RPMDB handled as TR_ERASED for now, doesn't really matter */
104     rpmfiFlags fiflags;
105     fiflags = (p->type == TR_ADDED) ? (RPMFI_NOHEADER | RPMFI_FLAGS_INSTALL) :
106 				      (RPMFI_NOHEADER | RPMFI_FLAGS_ERASE);
107 
108     /* relocate stuff in header if necessary */
109     if (rpmteType(p) == TR_ADDED && rpmfsFC(p->fs) > 0) {
110 	if (!headerIsEntry(h, RPMTAG_ORIGBASENAMES)) {
111 	    if (rpmteIsSource(p)) {
112 		/* Unlike binary packages, source relocation can fail */
113 		if (rpmRelocateSrpmFileList(h, rpmtsRootDir(p->ts)) < 0) {
114 		    return NULL;
115 		}
116 	    } else {
117 		rpmRelocateFileList(p->relocs, p->nrelocs, p->fs, h);
118 	    }
119 	}
120     }
121     return rpmfilesNew(rpmtsPool(p->ts), h, RPMTAG_BASENAMES, fiflags);
122 }
123 
124 /**
125  * Initialize transaction element data from header.
126  * @param p		transaction element
127  * @param h		header
128  * @param key		(TR_ADDED) package retrieval key (e.g. file name)
129  * @param relocs	(TR_ADDED) package file relocations
130  */
addTE(rpmte p,Header h,fnpyKey key,rpmRelocation * relocs)131 static int addTE(rpmte p, Header h, fnpyKey key, rpmRelocation * relocs)
132 {
133     rpmstrPool tspool = rpmtsPool(p->ts);
134     struct rpmtd_s bnames;
135     int rc = 1; /* assume failure */
136 
137     p->name = headerGetAsString(h, RPMTAG_NAME);
138     p->version = headerGetAsString(h, RPMTAG_VERSION);
139     p->release = headerGetAsString(h, RPMTAG_RELEASE);
140 
141     /* name, version and release are required in all packages */
142     if (p->name == NULL || p->version == NULL || p->release == NULL)
143 	goto exit;
144 
145     p->epoch = headerGetAsString(h, RPMTAG_EPOCH);
146 
147     p->arch = headerGetAsString(h, RPMTAG_ARCH);
148     p->os = headerGetAsString(h, RPMTAG_OS);
149 
150     /* gpg-pubkey's dont have os or arch (sigh), for others they are required */
151     if (!rstreq(p->name, "gpg-pubkey") && (p->arch == NULL || p->os == NULL))
152 	goto exit;
153 
154     p->isSource = headerIsSource(h);
155 
156     p->NEVR = headerGetAsString(h, RPMTAG_NEVR);
157     p->NEVRA = headerGetAsString(h, RPMTAG_NEVRA);
158 
159     p->nrelocs = 0;
160     p->relocs = NULL;
161     p->badrelocs = NULL;
162     if (relocs != NULL)
163 	rpmRelocationBuild(h, relocs, &p->nrelocs, &p->relocs, &p->badrelocs);
164 
165     p->db_instance = headerGetInstance(h);
166     p->key = key;
167     p->fd = NULL;
168 
169     p->pkgFileSize = 0;
170     p->headerSize = headerSizeof(h, HEADER_MAGIC_NO);
171 
172     p->thisds = rpmdsThisPool(tspool, h, RPMTAG_PROVIDENAME, RPMSENSE_EQUAL);
173     p->provides = rpmdsNewPool(tspool, h, RPMTAG_PROVIDENAME, 0);
174     p->requires = rpmdsNewPool(tspool, h, RPMTAG_REQUIRENAME, 0);
175     p->conflicts = rpmdsNewPool(tspool, h, RPMTAG_CONFLICTNAME, 0);
176     p->obsoletes = rpmdsNewPool(tspool, h, RPMTAG_OBSOLETENAME, 0);
177     p->order = rpmdsNewPool(tspool, h, RPMTAG_ORDERNAME, 0);
178     p->recommends = rpmdsNewPool(tspool, h, RPMTAG_RECOMMENDNAME, 0);
179     p->suggests = rpmdsNewPool(tspool, h, RPMTAG_SUGGESTNAME, 0);
180     p->supplements = rpmdsNewPool(tspool, h, RPMTAG_SUPPLEMENTNAME, 0);
181     p->enhances = rpmdsNewPool(tspool, h, RPMTAG_ENHANCENAME, 0);
182 
183     /* Relocation needs to know file count before rpmfiNew() */
184     headerGet(h, RPMTAG_BASENAMES, &bnames, HEADERGET_MINMEM);
185     p->fs = rpmfsNew(rpmtdCount(&bnames), (p->type == TR_ADDED));
186     rpmtdFreeData(&bnames);
187 
188     p->files = getFiles(p, h);
189 
190     /* Packages with no files return an empty file info set, NULL is an error */
191     if (p->files == NULL)
192 	goto exit;
193 
194     /* See if we have pre/posttrans scripts. */
195     p->transscripts |= (headerIsEntry(h, RPMTAG_PRETRANS) ||
196 			 headerIsEntry(h, RPMTAG_PRETRANSPROG)) ?
197 			RPMTE_HAVE_PRETRANS : 0;
198     p->transscripts |= (headerIsEntry(h, RPMTAG_POSTTRANS) ||
199 			 headerIsEntry(h, RPMTAG_POSTTRANSPROG)) ?
200 			RPMTE_HAVE_POSTTRANS : 0;
201 
202     rpmteColorDS(p, RPMTAG_PROVIDENAME);
203     rpmteColorDS(p, RPMTAG_REQUIRENAME);
204 
205     if (p->type == TR_ADDED)
206 	p->pkgFileSize = headerGetNumber(h, RPMTAG_LONGSIGSIZE) + 96 + 256;
207 
208     rc = 0;
209 
210 exit:
211     return rc;
212 }
213 
rpmteFree(rpmte te)214 rpmte rpmteFree(rpmte te)
215 {
216     if (te != NULL) {
217 	if (te->relocs) {
218 	    for (int i = 0; i < te->nrelocs; i++) {
219 		free(te->relocs[i].oldPath);
220 		free(te->relocs[i].newPath);
221 	    }
222 	    free(te->relocs);
223 	    free(te->badrelocs);
224 	}
225 
226 	free(te->os);
227 	free(te->arch);
228 	free(te->epoch);
229 	free(te->name);
230 	free(te->version);
231 	free(te->release);
232 	free(te->NEVR);
233 	free(te->NEVRA);
234 
235 	fdFree(te->fd);
236 	rpmfiFree(te->fi);
237 	rpmfilesFree(te->files);
238 	headerFree(te->h);
239 	rpmfsFree(te->fs);
240 	rpmpsFree(te->probs);
241 	rpmteCleanDS(te);
242 
243 	memset(te, 0, sizeof(*te));	/* XXX trash and burn */
244 	free(te);
245     }
246     return NULL;
247 }
248 
rpmteNew(rpmts ts,Header h,rpmElementType type,fnpyKey key,rpmRelocation * relocs,int addop)249 rpmte rpmteNew(rpmts ts, Header h, rpmElementType type, fnpyKey key,
250 	       rpmRelocation * relocs, int addop)
251 {
252     rpmte p = xcalloc(1, sizeof(*p));
253     p->ts = ts;
254     p->type = type;
255     p->addop = addop;
256     p->verified = RPMSIG_UNVERIFIED_TYPE;
257 
258     if (addTE(p, h, key, relocs)) {
259 	rpmteFree(p);
260 	return NULL;
261     }
262 
263     return p;
264 }
265 
rpmteDBInstance(rpmte te)266 unsigned int rpmteDBInstance(rpmte te)
267 {
268     return (te != NULL ? te->db_instance : 0);
269 }
270 
rpmteSetDBInstance(rpmte te,unsigned int instance)271 void rpmteSetDBInstance(rpmte te, unsigned int instance)
272 {
273     if (te != NULL)
274 	te->db_instance = instance;
275 }
276 
rpmteHeader(rpmte te)277 Header rpmteHeader(rpmte te)
278 {
279     return (te != NULL && te->h != NULL ? headerLink(te->h) : NULL);
280 }
281 
rpmteSetHeader(rpmte te,Header h)282 Header rpmteSetHeader(rpmte te, Header h)
283 {
284     if (te != NULL)  {
285 	te->h = headerFree(te->h);
286 	if (h != NULL)
287 	    te->h = headerLink(h);
288     }
289     return NULL;
290 }
291 
rpmteType(rpmte te)292 rpmElementType rpmteType(rpmte te)
293 {
294     /* XXX returning negative for unsigned type */
295     return (te != NULL ? te->type : -1);
296 }
297 
rpmteN(rpmte te)298 const char * rpmteN(rpmte te)
299 {
300     return (te != NULL ? te->name : NULL);
301 }
302 
rpmteE(rpmte te)303 const char * rpmteE(rpmte te)
304 {
305     return (te != NULL ? te->epoch : NULL);
306 }
307 
rpmteV(rpmte te)308 const char * rpmteV(rpmte te)
309 {
310     return (te != NULL ? te->version : NULL);
311 }
312 
rpmteR(rpmte te)313 const char * rpmteR(rpmte te)
314 {
315     return (te != NULL ? te->release : NULL);
316 }
317 
rpmteA(rpmte te)318 const char * rpmteA(rpmte te)
319 {
320     return (te != NULL ? te->arch : NULL);
321 }
322 
rpmteO(rpmte te)323 const char * rpmteO(rpmte te)
324 {
325     return (te != NULL ? te->os : NULL);
326 }
327 
rpmteIsSource(rpmte te)328 int rpmteIsSource(rpmte te)
329 {
330     return (te != NULL ? te->isSource : 0);
331 }
332 
rpmteColor(rpmte te)333 rpm_color_t rpmteColor(rpmte te)
334 {
335     return (te != NULL ? te->color : 0);
336 }
337 
rpmteSetColor(rpmte te,rpm_color_t color)338 rpm_color_t rpmteSetColor(rpmte te, rpm_color_t color)
339 {
340     rpm_color_t ocolor = 0;
341     if (te != NULL) {
342 	ocolor = te->color;
343 	te->color = color;
344     }
345     return ocolor;
346 }
347 
rpmtePkgFileSize(rpmte te)348 rpm_loff_t rpmtePkgFileSize(rpmte te)
349 {
350     return (te != NULL ? te->pkgFileSize : 0);
351 }
352 
rpmteHeaderSize(rpmte te)353 unsigned int rpmteHeaderSize(rpmte te)
354 {
355     return (te != NULL ? te->headerSize : 0);
356 }
357 
rpmteParent(rpmte te)358 rpmte rpmteParent(rpmte te)
359 {
360     return (te != NULL ? te->parent : NULL);
361 }
362 
rpmteSetParent(rpmte te,rpmte pte)363 rpmte rpmteSetParent(rpmte te, rpmte pte)
364 {
365     rpmte opte = NULL;
366     if (te != NULL) {
367 	opte = te->parent;
368 	te->parent = pte;
369     }
370     return opte;
371 }
372 
rpmteTSI(rpmte te)373 tsortInfo rpmteTSI(rpmte te)
374 {
375     return te->tsi;
376 }
377 
rpmteSetTSI(rpmte te,tsortInfo tsi)378 void rpmteSetTSI(rpmte te, tsortInfo tsi)
379 {
380     te->tsi = tsi;
381 }
382 
rpmteSetDependsOn(rpmte te,rpmte depends)383 void rpmteSetDependsOn(rpmte te, rpmte depends)
384 {
385     te->depends = depends;
386 }
387 
rpmteDependsOn(rpmte te)388 rpmte rpmteDependsOn(rpmte te)
389 {
390     return te->depends;
391 }
392 
rpmteDBOffset(rpmte te)393 int rpmteDBOffset(rpmte te)
394 {
395     return rpmteDBInstance(te);
396 }
397 
rpmteEVR(rpmte te)398 const char * rpmteEVR(rpmte te)
399 {
400     return (te != NULL ? te->NEVR + strlen(te->name) + 1 : NULL);
401 }
402 
rpmteNEVR(rpmte te)403 const char * rpmteNEVR(rpmte te)
404 {
405     return (te != NULL ? te->NEVR : NULL);
406 }
407 
rpmteNEVRA(rpmte te)408 const char * rpmteNEVRA(rpmte te)
409 {
410     return (te != NULL ? te->NEVRA : NULL);
411 }
412 
rpmteSetFd(rpmte te,FD_t fd)413 FD_t rpmteSetFd(rpmte te, FD_t fd)
414 {
415     if (te != NULL)  {
416 	if (te->fd != NULL)
417 	    te->fd = fdFree(te->fd);
418 	if (fd != NULL)
419 	    te->fd = fdLink(fd);
420     }
421     return NULL;
422 }
423 
rpmteKey(rpmte te)424 fnpyKey rpmteKey(rpmte te)
425 {
426     return (te != NULL ? te->key : NULL);
427 }
428 
rpmteDS(rpmte te,rpmTagVal tag)429 rpmds rpmteDS(rpmte te, rpmTagVal tag)
430 {
431     if (te == NULL)
432 	return NULL;
433 
434     switch (tag) {
435     case RPMTAG_NAME:		return te->thisds;
436     case RPMTAG_PROVIDENAME:	return te->provides;
437     case RPMTAG_REQUIRENAME:	return te->requires;
438     case RPMTAG_CONFLICTNAME:	return te->conflicts;
439     case RPMTAG_OBSOLETENAME:	return te->obsoletes;
440     case RPMTAG_ORDERNAME:	return te->order;
441     case RPMTAG_RECOMMENDNAME:	return te->recommends;
442     case RPMTAG_SUGGESTNAME:	return te->suggests;
443     case RPMTAG_SUPPLEMENTNAME:	return te->supplements;
444     case RPMTAG_ENHANCENAME:	return te->enhances;
445     default:			break;
446     }
447     return NULL;
448 }
449 
rpmteCleanFiles(rpmte te)450 void rpmteCleanFiles(rpmte te)
451 {
452     if (te != NULL)  {
453 	te->fi = rpmfiFree(te->fi);
454 	te->files = rpmfilesFree(te->files);
455     }
456 }
457 
rpmteFI(rpmte te)458 rpmfi rpmteFI(rpmte te)
459 {
460     if (te == NULL)
461 	return NULL;
462 
463     if (te->fi == NULL)
464 	te->fi = rpmfilesIter(te->files, RPMFI_ITER_FWD);
465 
466     return te->fi; /* XXX take fi reference here? */
467 }
468 
rpmteFiles(rpmte te)469 rpmfiles rpmteFiles(rpmte te)
470 {
471     return (te != NULL) ? rpmfilesLink(te->files) : NULL;
472 }
473 
rpmteColorDS(rpmte te,rpmTag tag)474 static void rpmteColorDS(rpmte te, rpmTag tag)
475 {
476     rpmfi fi;
477     rpmds ds = rpmteDS(te, tag);
478     char deptype = 'R';
479     char mydt;
480     const uint32_t * ddict;
481     rpm_color_t * colors;
482     rpm_color_t val;
483     int Count;
484     unsigned ix;
485     int ndx, i;
486 
487     if (!(te && (Count = rpmdsCount(ds)) > 0 && rpmfilesFC(te->files) > 0))
488 	return;
489 
490     switch (tag) {
491     default:
492 	return;
493 	break;
494     case RPMTAG_PROVIDENAME:
495 	deptype = 'P';
496 	break;
497     case RPMTAG_REQUIRENAME:
498 	deptype = 'R';
499 	break;
500     }
501 
502     colors = xcalloc(Count, sizeof(*colors));
503 
504     /* Calculate dependency color. */
505     fi = rpmfilesIter(te->files, RPMFI_ITER_FWD);
506     while (rpmfiNext(fi) >= 0) {
507 	val = rpmfiFColor(fi);
508 	ddict = NULL;
509 	ndx = rpmfiFDepends(fi, &ddict);
510 	if (ddict != NULL)
511 	while (ndx-- > 0) {
512 	    ix = *ddict++;
513 	    mydt = ((ix >> 24) & 0xff);
514 	    if (mydt != deptype)
515 		continue;
516 	    ix &= 0x00ffffff;
517 assert (ix < Count);
518 	    colors[ix] |= val;
519 	}
520     }
521 
522     /* Set color values in dependency set. */
523     ds = rpmdsInit(ds);
524     while ((i = rpmdsNext(ds)) >= 0) {
525 	val = colors[i];
526 	te->color |= val;
527 	(void) rpmdsSetColor(ds, val);
528     }
529     free(colors);
530     rpmfiFree(fi);
531 }
532 
rpmteDBHeader(rpmte te)533 static Header rpmteDBHeader(rpmte te)
534 {
535     Header h = NULL;
536     rpmdbMatchIterator mi;
537 
538     mi = rpmtsInitIterator(te->ts, RPMDBI_PACKAGES,
539 			   &te->db_instance, sizeof(te->db_instance));
540     /* iterator returns weak refs, grab hold of header */
541     if ((h = rpmdbNextIterator(mi)))
542 	h = headerLink(h);
543     rpmdbFreeIterator(mi);
544     return h;
545 }
546 
rpmteFDHeader(rpmte te)547 static Header rpmteFDHeader(rpmte te)
548 {
549     Header h = NULL;
550     te->fd = rpmtsNotify(te->ts, te, RPMCALLBACK_INST_OPEN_FILE, 0, 0);
551     if (te->fd != NULL) {
552 	rpmVSFlags ovsflags;
553 	rpmRC pkgrc;
554 
555 	ovsflags = rpmtsSetVSFlags(te->ts,
556 				   rpmtsVSFlags(te->ts) | RPMVSF_NEEDPAYLOAD);
557 	pkgrc = rpmReadPackageFile(te->ts, te->fd, rpmteNEVRA(te), &h);
558 	rpmtsSetVSFlags(te->ts, ovsflags);
559 	switch (pkgrc) {
560 	default:
561 	    rpmteClose(te, 1);
562 	    break;
563 	case RPMRC_NOTTRUSTED:
564 	case RPMRC_NOKEY:
565 	case RPMRC_OK:
566 	    break;
567 	}
568     }
569     return h;
570 }
571 
rpmteOpen(rpmte te,int reload_fi)572 static int rpmteOpen(rpmte te, int reload_fi)
573 {
574     int rc = 0; /* assume failure */
575     Header h = NULL;
576     if (te == NULL || te->ts == NULL || rpmteFailed(te))
577 	goto exit;
578 
579     rpmteSetHeader(te, NULL);
580 
581     switch (rpmteType(te)) {
582     case TR_ADDED:
583 	h = rpmteDBInstance(te) ? rpmteDBHeader(te) : rpmteFDHeader(te);
584 	break;
585     case TR_REMOVED:
586     case TR_RPMDB:
587 	h = rpmteDBHeader(te);
588     	break;
589     }
590     if (h != NULL) {
591 	if (reload_fi) {
592 	    /* This can fail if we get a different, bad header from callback */
593 	    te->files = getFiles(te, h);
594 	    rc = (te->files != NULL);
595 	} else {
596 	    rc = 1;
597 	}
598 
599 	rpmteSetHeader(te, h);
600 	headerFree(h);
601     }
602 
603 exit:
604     return rc;
605 }
606 
rpmteClose(rpmte te,int reset_fi)607 static int rpmteClose(rpmte te, int reset_fi)
608 {
609     if (te == NULL || te->ts == NULL)
610 	return 0;
611 
612     switch (te->type) {
613     case TR_ADDED:
614 	if (te->fd) {
615 	    rpmtsNotify(te->ts, te, RPMCALLBACK_INST_CLOSE_FILE, 0, 0);
616 	    te->fd = NULL;
617 	}
618 	break;
619     case TR_REMOVED:
620     case TR_RPMDB:
621 	/* eventually we'll want notifications for erase open too */
622 	break;
623     }
624     rpmteSetHeader(te, NULL);
625     if (reset_fi) {
626 	rpmteCleanFiles(te);
627     }
628     return 1;
629 }
630 
rpmtePayload(rpmte te)631 FD_t rpmtePayload(rpmte te)
632 {
633     FD_t payload = NULL;
634     if (te->fd && te->h) {
635 	const char *compr = headerGetString(te->h, RPMTAG_PAYLOADCOMPRESSOR);
636 	char *ioflags = rstrscat(NULL, "r.", compr ? compr : "gzip", NULL);
637 	payload = Fdopen(fdDup(Fileno(te->fd)), ioflags);
638 	free(ioflags);
639     }
640     return payload;
641 }
642 
rpmteMarkFailed(rpmte te)643 static int rpmteMarkFailed(rpmte te)
644 {
645     te->failed++;
646 
647     /* No need to do this more than once, avoid recursion loops */
648     if (te->failed == 1) {
649 	rpmtsi pi = rpmtsiInit(te->ts);
650 	rpmte p;
651 
652 	/* XXX we can do a much better here than this... */
653 	while ((p = rpmtsiNext(pi, TR_REMOVED))) {
654 	    if (rpmteDependsOn(p) == te) {
655 		rpmteMarkFailed(p);
656 	    }
657 	}
658 	rpmtsiFree(pi);
659     }
660     return te->failed;
661 }
662 
rpmteFailed(rpmte te)663 int rpmteFailed(rpmte te)
664 {
665     return (te != NULL) ? te->failed : -1;
666 }
667 
rpmteHaveTransScript(rpmte te,rpmTagVal tag)668 int rpmteHaveTransScript(rpmte te, rpmTagVal tag)
669 {
670     int rc = 0;
671     if (tag == RPMTAG_PRETRANS) {
672 	rc = (te->transscripts & RPMTE_HAVE_PRETRANS);
673     } else if (tag == RPMTAG_POSTTRANS) {
674 	rc = (te->transscripts & RPMTE_HAVE_POSTTRANS);
675     }
676     return rc;
677 }
678 
rpmteProblems(rpmte te)679 rpmps rpmteProblems(rpmte te)
680 {
681     return (te != NULL) ? rpmpsLink(te->probs) : NULL;
682 }
683 
rpmteCleanProblems(rpmte te)684 void rpmteCleanProblems(rpmte te)
685 {
686     if (te != NULL && te->probs != NULL) {
687 	te->probs = rpmpsFree(te->probs);
688     }
689 }
690 
appendProblem(rpmte te,rpmProblemType type,fnpyKey key,const char * altNEVR,const char * str,uint64_t number)691 static void appendProblem(rpmte te, rpmProblemType type,
692 		fnpyKey key, const char * altNEVR,
693 		const char * str, uint64_t number)
694 {
695     rpmProblem o;
696     rpmProblem p = rpmProblemCreate(type, te->NEVRA, key, altNEVR, str, number);
697     rpmpsi psi = rpmpsInitIterator(te->probs);
698 
699     /* Only add new, unique problems to the set */
700     while ((o = rpmpsiNext(psi))) {
701 	if (rpmProblemCompare(p, o) == 0)
702 	    break;
703     }
704     rpmpsFreeIterator(psi);
705 
706     if (o == NULL) {
707 	if (te->probs == NULL)
708 	    te->probs = rpmpsCreate();
709 	rpmpsAppendProblem(te->probs, p);
710 	rpmteMarkFailed(te);
711     }
712     rpmProblemFree(p);
713 }
714 
rpmteAddProblem(rpmte te,rpmProblemType type,const char * altNEVR,const char * str,uint64_t number)715 void rpmteAddProblem(rpmte te, rpmProblemType type,
716 		     const char *altNEVR, const char *str, uint64_t number)
717 {
718     if (te != NULL) {
719 	appendProblem(te, type, rpmteKey(te), altNEVR, str, number);
720     }
721 }
722 
rpmteAddDepProblem(rpmte te,const char * altNEVR,rpmds ds,fnpyKey * suggestedKeys)723 void rpmteAddDepProblem(rpmte te, const char * altNEVR, rpmds ds,
724 		        fnpyKey * suggestedKeys)
725 {
726     if (te != NULL) {
727 	const char * DNEVR = rpmdsDNEVR(ds);
728 	rpmProblemType type;
729 	fnpyKey key = (suggestedKeys ? suggestedKeys[0] : NULL);
730 
731 	switch ((unsigned)DNEVR[0]) {
732 	case 'O':	type = RPMPROB_OBSOLETES;	break;
733 	case 'C':	type = RPMPROB_CONFLICT;	break;
734 	default:
735 	case 'R':	type = RPMPROB_REQUIRES;	break;
736 	}
737 
738 	appendProblem(te, type, key, altNEVR, DNEVR+2, rpmdsInstance(ds));
739     }
740 }
741 
rpmteAddRelocProblems(rpmte te)742 void rpmteAddRelocProblems(rpmte te)
743 {
744     if (te && te->badrelocs) {
745 	for (int i = 0; i < te->nrelocs; i++) {
746 	    if (te->badrelocs[i]) {
747 		rpmteAddProblem(te, RPMPROB_BADRELOCATE, NULL,
748 				te->relocs[i].oldPath, 0);
749 	    }
750 	}
751     }
752 }
753 
rpmteTypeString(rpmte te)754 const char * rpmteTypeString(rpmte te)
755 {
756     switch (rpmteType(te)) {
757     case TR_ADDED:	return _("install");
758     case TR_REMOVED:	return _("erase");
759     case TR_RPMDB:	return _("rpmdb");
760     default:		return "???";
761     }
762 }
763 
rpmteGetFileStates(rpmte te)764 rpmfs rpmteGetFileStates(rpmte te)
765 {
766     return te->fs;
767 }
768 
rpmteSetVerified(rpmte te,int verified)769 void rpmteSetVerified(rpmte te, int verified)
770 {
771     te->verified = verified;
772 }
773 
rpmteVerified(rpmte te)774 int rpmteVerified(rpmte te)
775 {
776     return (te != NULL) ? te->verified : 0;
777 }
778 
rpmteAddOp(rpmte te)779 int rpmteAddOp(rpmte te)
780 {
781     return te->addop;
782 }
783 
rpmteProcess(rpmte te,pkgGoal goal,int num)784 int rpmteProcess(rpmte te, pkgGoal goal, int num)
785 {
786     /* Only install/erase resets pkg file info */
787     int scriptstage = (goal != PKG_INSTALL && goal != PKG_ERASE);
788     int test = (rpmtsFlags(te->ts) & RPMTRANS_FLAG_TEST);
789     int reset_fi = (scriptstage == 0 && test == 0);
790     int failed = 1;
791 
792     /* Dont bother opening for elements without pre/posttrans scripts */
793     if (goal == PKG_PRETRANS || goal == PKG_POSTTRANS) {
794 	if (!rpmteHaveTransScript(te, goal)) {
795 	    return 0;
796 	}
797     }
798 
799     if (rpmteOpen(te, reset_fi)) {
800 	if (!scriptstage) {
801 	    rpmtsNotify(te->ts, te, RPMCALLBACK_ELEM_PROGRESS, num,
802 			rpmtsMembers(te->ts)->orderCount);
803 	}
804 
805 	failed = rpmpsmRun(te->ts, te, goal);
806 	rpmteClose(te, reset_fi);
807     }
808 
809     if (failed) {
810 	failed = rpmteMarkFailed(te);
811     }
812 
813     return failed;
814 }
815