[4.0] Use strip (instead of eu-strip) to support --strip-debug of *.so at build time
[platform/upstream/rpm.git] / lib / rpmte.c
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/rpmplugins.h"
17 #include "lib/rpmte_internal.h"
18 /* strpool-related interfaces */
19 #include "lib/rpmfi_internal.h"
20 #include "lib/rpmds_internal.h"
21 #include "lib/rpmts_internal.h"
22
23 #include "debug.h"
24
25 /** \ingroup rpmte
26  * A single package instance to be installed/removed atomically.
27  */
28 struct rpmte_s {
29     rpmElementType type;        /*!< Package disposition (installed/removed). */
30
31     Header h;                   /*!< Package header. */
32     char * NEVR;                /*!< Package name-version-release. */
33     char * NEVRA;               /*!< Package name-version-release.arch. */
34     char * name;                /*!< Name: */
35     char * epoch;
36     char * version;             /*!< Version: */
37     char * release;             /*!< Release: */
38     char * arch;                /*!< Architecture hint. */
39     char * os;                  /*!< Operating system hint. */
40     int isSource;               /*!< (TR_ADDED) source rpm? */
41
42     rpmte depends;              /*!< Package updated by this package (ERASE te) */
43     rpmte parent;               /*!< Parent transaction element. */
44     unsigned int db_instance;   /*!< Database instance (of removed pkgs) */
45     tsortInfo tsi;              /*!< Dependency ordering chains. */
46
47     rpmds thisds;               /*!< This package's provided NEVR. */
48     rpmds provides;             /*!< Provides: dependencies. */
49     rpmds requires;             /*!< Requires: dependencies. */
50     rpmds conflicts;            /*!< Conflicts: dependencies. */
51     rpmds obsoletes;            /*!< Obsoletes: dependencies. */
52     rpmds order;                /*!< Order: dependencies. */
53     rpmfi fi;                   /*!< File information. */
54     rpmps probs;                /*!< Problems (relocations) */
55     rpmts ts;                   /*!< Parent transaction */
56
57     rpm_color_t color;          /*!< Color bit(s) from package dependencies. */
58     rpm_loff_t pkgFileSize;     /*!< No. of bytes in package file (approx). */
59     unsigned int headerSize;    /*!< No. of bytes in package header */
60
61     fnpyKey key;                /*!< (TR_ADDED) Retrieval key. */
62     rpmRelocation * relocs;     /*!< (TR_ADDED) Payload file relocations. */
63     int nrelocs;                /*!< (TR_ADDED) No. of relocations. */
64     uint8_t *badrelocs;         /*!< (TR_ADDED) Bad relocations (or NULL) */
65     FD_t fd;                    /*!< (TR_ADDED) Payload file descriptor. */
66
67 #define RPMTE_HAVE_PRETRANS     (1 << 0)
68 #define RPMTE_HAVE_POSTTRANS    (1 << 1)
69     int transscripts;           /*!< pre/posttrans script existence */
70     int failed;                 /*!< (parent) install/erase failed */
71
72     rpmfs fs;
73
74     ARGV_t lastInCollectionsAny;        /*!< list of collections this te is the last to be installed or removed */
75     ARGV_t lastInCollectionsAdd;        /*!< list of collections this te is the last to be only installed */
76     ARGV_t firstInCollectionsRemove;    /*!< list of collections this te is the first to be only removed */
77     ARGV_t collections;                 /*!< list of collections */
78 };
79
80 /* forward declarations */
81 static void rpmteColorDS(rpmte te, rpmTag tag);
82 static int rpmteClose(rpmte te, int reset_fi);
83
84 void rpmteCleanDS(rpmte te)
85 {
86     te->thisds = rpmdsFree(te->thisds);
87     te->provides = rpmdsFree(te->provides);
88     te->requires = rpmdsFree(te->requires);
89     te->conflicts = rpmdsFree(te->conflicts);
90     te->obsoletes = rpmdsFree(te->obsoletes);
91     te->order = rpmdsFree(te->order);
92 }
93
94 static rpmfi getFI(rpmte p, Header h)
95 {
96     rpmfiFlags fiflags;
97     fiflags = (p->type == TR_ADDED) ? (RPMFI_NOHEADER | RPMFI_FLAGS_INSTALL) :
98                                       (RPMFI_NOHEADER | RPMFI_FLAGS_ERASE);
99
100     /* relocate stuff in header if necessary */
101     if (rpmteType(p) == TR_ADDED && rpmfsFC(p->fs) > 0 && p->nrelocs) {
102         if (!headerIsSource(h) && !headerIsEntry(h, RPMTAG_ORIGBASENAMES)) {
103             rpmRelocateFileList(p->relocs, p->nrelocs, p->fs, h);
104         }
105     }
106     return rpmfiNewPool(rpmtsPool(p->ts), h, RPMTAG_BASENAMES, fiflags);
107 }
108
109 /* stupid bubble sort, but it's probably faster here */
110 static void sortRelocs(rpmRelocation *relocations, int numRelocations)
111 {
112     for (int i = 0; i < numRelocations; i++) {
113         int madeSwap = 0;
114         for (int j = 1; j < numRelocations; j++) {
115             rpmRelocation tmpReloc;
116             if (relocations[j - 1].oldPath == NULL || /* XXX can't happen */
117                 relocations[j    ].oldPath == NULL || /* XXX can't happen */
118                 strcmp(relocations[j - 1].oldPath, relocations[j].oldPath) <= 0)
119                 continue;
120             tmpReloc = relocations[j - 1];
121             relocations[j - 1] = relocations[j];
122             relocations[j] = tmpReloc;
123             madeSwap = 1;
124         }
125         if (!madeSwap) break;
126     }
127 }
128
129 static char * stripTrailingChar(char * s, char c)
130 {
131     char * t;
132     for (t = s + strlen(s) - 1; *t == c && t >= s; t--)
133         *t = '\0';
134     return s;
135 }
136
137 static void buildRelocs(rpmte p, Header h, rpmRelocation *relocs)
138 {
139     int i;
140     struct rpmtd_s validRelocs;
141
142     for (rpmRelocation *r = relocs; r->oldPath || r->newPath; r++)
143         p->nrelocs++;
144
145     headerGet(h, RPMTAG_PREFIXES, &validRelocs, HEADERGET_MINMEM);
146     p->relocs = xmalloc(sizeof(*p->relocs) * (p->nrelocs+1));
147
148     /* Build sorted relocation list from raw relocations. */
149     for (i = 0; i < p->nrelocs; i++) {
150         char * t;
151
152         /*
153          * Default relocations (oldPath == NULL) are handled in the UI,
154          * not rpmlib.
155          */
156         if (relocs[i].oldPath == NULL) continue; /* XXX can't happen */
157
158         /* FIXME: Trailing /'s will confuse us greatly. Internal ones will 
159            too, but those are more trouble to fix up. :-( */
160         t = xstrdup(relocs[i].oldPath);
161         p->relocs[i].oldPath = (t[0] == '/' && t[1] == '\0')
162             ? t
163             : stripTrailingChar(t, '/');
164
165         /* An old path w/o a new path is valid, and indicates exclusion */
166         if (relocs[i].newPath) {
167             int valid = 0;
168             const char *validprefix;
169
170             t = xstrdup(relocs[i].newPath);
171             p->relocs[i].newPath = (t[0] == '/' && t[1] == '\0')
172                 ? t
173                 : stripTrailingChar(t, '/');
174
175                 /* FIX:  relocations[i].oldPath == NULL */
176             /* Verify that the relocation's old path is in the header. */
177             rpmtdInit(&validRelocs);
178             while ((validprefix = rpmtdNextString(&validRelocs))) {
179                 if (rstreq(validprefix, p->relocs[i].oldPath)) {
180                     valid = 1;
181                     break;
182                 }
183             }
184
185             if (!valid) {
186                 if (p->badrelocs == NULL)
187                     p->badrelocs = xcalloc(p->nrelocs, sizeof(*p->badrelocs));
188                 p->badrelocs[i] = 1;
189             }
190         } else {
191             p->relocs[i].newPath = NULL;
192         }
193     }
194     p->relocs[i].oldPath = NULL;
195     p->relocs[i].newPath = NULL;
196     sortRelocs(p->relocs, p->nrelocs);
197     
198     rpmtdFreeData(&validRelocs);
199 }
200
201 /**
202  * Initialize transaction element data from header.
203  * @param p             transaction element
204  * @param h             header
205  * @param key           (TR_ADDED) package retrieval key (e.g. file name)
206  * @param relocs        (TR_ADDED) package file relocations
207  */
208 static int addTE(rpmte p, Header h, fnpyKey key, rpmRelocation * relocs)
209 {
210     rpmstrPool tspool = rpmtsPool(p->ts);
211     struct rpmtd_s colls, bnames;
212     int rc = 1; /* assume failure */
213
214     p->name = headerGetAsString(h, RPMTAG_NAME);
215     p->version = headerGetAsString(h, RPMTAG_VERSION);
216     p->release = headerGetAsString(h, RPMTAG_RELEASE);
217
218     /* name, version and release are required in all packages */
219     if (p->name == NULL || p->version == NULL || p->release == NULL)
220         goto exit;
221
222     p->epoch = headerGetAsString(h, RPMTAG_EPOCH);
223
224     p->arch = headerGetAsString(h, RPMTAG_ARCH);
225     p->os = headerGetAsString(h, RPMTAG_OS);
226
227     /* gpg-pubkey's dont have os or arch (sigh), for others they are required */
228     if (!rstreq(p->name, "gpg-pubkey") && (p->arch == NULL || p->os == NULL))
229         goto exit;
230
231     p->isSource = headerIsSource(h);
232     
233     p->NEVR = headerGetAsString(h, RPMTAG_NEVR);
234     p->NEVRA = headerGetAsString(h, RPMTAG_NEVRA);
235
236     p->nrelocs = 0;
237     p->relocs = NULL;
238     p->badrelocs = NULL;
239     if (relocs != NULL)
240         buildRelocs(p, h, relocs);
241
242     p->db_instance = headerGetInstance(h);
243     p->key = key;
244     p->fd = NULL;
245
246     p->pkgFileSize = 0;
247     p->headerSize = headerSizeof(h, HEADER_MAGIC_NO);
248
249     p->thisds = rpmdsThisPool(tspool, h, RPMTAG_PROVIDENAME, RPMSENSE_EQUAL);
250     p->provides = rpmdsNewPool(tspool, h, RPMTAG_PROVIDENAME, 0);
251     p->requires = rpmdsNewPool(tspool, h, RPMTAG_REQUIRENAME, 0);
252     p->conflicts = rpmdsNewPool(tspool, h, RPMTAG_CONFLICTNAME, 0);
253     p->obsoletes = rpmdsNewPool(tspool, h, RPMTAG_OBSOLETENAME, 0);
254     p->order = rpmdsNewPool(tspool, h, RPMTAG_ORDERNAME, 0);
255
256     /* Relocation needs to know file count before rpmfiNew() */
257     headerGet(h, RPMTAG_BASENAMES, &bnames, HEADERGET_MINMEM);
258     p->fs = rpmfsNew(rpmtdCount(&bnames), (p->type == TR_ADDED));
259     rpmtdFreeData(&bnames);
260
261     p->fi = getFI(p, h);
262
263     /* Packages with no files return an empty file info set, NULL is an error */
264     if (p->fi == NULL)
265         goto exit;
266
267     /* See if we have pre/posttrans scripts. */
268     p->transscripts |= (headerIsEntry(h, RPMTAG_PRETRANS) ||
269                          headerIsEntry(h, RPMTAG_PRETRANSPROG)) ?
270                         RPMTE_HAVE_PRETRANS : 0;
271     p->transscripts |= (headerIsEntry(h, RPMTAG_POSTTRANS) ||
272                          headerIsEntry(h, RPMTAG_POSTTRANSPROG)) ?
273                         RPMTE_HAVE_POSTTRANS : 0;
274
275     p->lastInCollectionsAny = NULL;
276     p->lastInCollectionsAdd = NULL;
277     p->firstInCollectionsRemove = NULL;
278     p->collections = NULL;
279     if (headerGet(h, RPMTAG_COLLECTIONS, &colls, HEADERGET_MINMEM)) {
280         const char *collname;
281         while ((collname = rpmtdNextString(&colls))) {
282             argvAdd(&p->collections, collname);
283         }
284         argvSort(p->collections, NULL);
285         rpmtdFreeData(&colls);
286     }
287
288     rpmteColorDS(p, RPMTAG_PROVIDENAME);
289     rpmteColorDS(p, RPMTAG_REQUIRENAME);
290
291     if (p->type == TR_ADDED)
292         p->pkgFileSize = headerGetNumber(h, RPMTAG_LONGSIGSIZE) + 96 + 256;
293
294     rc = 0;
295
296 exit:
297     return rc;
298 }
299
300 rpmte rpmteFree(rpmte te)
301 {
302     if (te != NULL) {
303         if (te->relocs) {
304             for (int i = 0; i < te->nrelocs; i++) {
305                 free(te->relocs[i].oldPath);
306                 free(te->relocs[i].newPath);
307             }
308             free(te->relocs);
309             free(te->badrelocs);
310         }
311
312         free(te->os);
313         free(te->arch);
314         free(te->epoch);
315         free(te->name);
316         free(te->version);
317         free(te->release);
318         free(te->NEVR);
319         free(te->NEVRA);
320
321         fdFree(te->fd);
322         rpmfiFree(te->fi);
323         headerFree(te->h);
324         rpmfsFree(te->fs);
325         rpmpsFree(te->probs);
326         rpmteCleanDS(te);
327
328         argvFree(te->collections);
329         argvFree(te->lastInCollectionsAny);
330         argvFree(te->lastInCollectionsAdd);
331         argvFree(te->firstInCollectionsRemove);
332
333         memset(te, 0, sizeof(*te));     /* XXX trash and burn */
334         free(te);
335     }
336     return NULL;
337 }
338
339 rpmte rpmteNew(rpmts ts, Header h, rpmElementType type, fnpyKey key,
340                rpmRelocation * relocs)
341 {
342     rpmte p = xcalloc(1, sizeof(*p));
343     p->ts = ts;
344     p->type = type;
345
346     if (addTE(p, h, key, relocs)) {
347         rpmteFree(p);
348         return NULL;
349     }
350
351     return p;
352 }
353
354 unsigned int rpmteDBInstance(rpmte te) 
355 {
356     return (te != NULL ? te->db_instance : 0);
357 }
358
359 void rpmteSetDBInstance(rpmte te, unsigned int instance) 
360 {
361     if (te != NULL) 
362         te->db_instance = instance;
363 }
364
365 Header rpmteHeader(rpmte te)
366 {
367     return (te != NULL && te->h != NULL ? headerLink(te->h) : NULL);
368 }
369
370 Header rpmteSetHeader(rpmte te, Header h)
371 {
372     if (te != NULL)  {
373         te->h = headerFree(te->h);
374         if (h != NULL)
375             te->h = headerLink(h);
376     }
377     return NULL;
378 }
379
380 rpmElementType rpmteType(rpmte te)
381 {
382     /* XXX returning negative for unsigned type */
383     return (te != NULL ? te->type : -1);
384 }
385
386 const char * rpmteN(rpmte te)
387 {
388     return (te != NULL ? te->name : NULL);
389 }
390
391 const char * rpmteE(rpmte te)
392 {
393     return (te != NULL ? te->epoch : NULL);
394 }
395
396 const char * rpmteV(rpmte te)
397 {
398     return (te != NULL ? te->version : NULL);
399 }
400
401 const char * rpmteR(rpmte te)
402 {
403     return (te != NULL ? te->release : NULL);
404 }
405
406 const char * rpmteA(rpmte te)
407 {
408     return (te != NULL ? te->arch : NULL);
409 }
410
411 const char * rpmteO(rpmte te)
412 {
413     return (te != NULL ? te->os : NULL);
414 }
415
416 int rpmteIsSource(rpmte te)
417 {
418     return (te != NULL ? te->isSource : 0);
419 }
420
421 rpm_color_t rpmteColor(rpmte te)
422 {
423     return (te != NULL ? te->color : 0);
424 }
425
426 rpm_color_t rpmteSetColor(rpmte te, rpm_color_t color)
427 {
428     rpm_color_t ocolor = 0;
429     if (te != NULL) {
430         ocolor = te->color;
431         te->color = color;
432     }
433     return ocolor;
434 }
435
436 ARGV_const_t rpmteCollections(rpmte te)
437 {
438     return (te != NULL) ? te->collections : NULL;
439 }
440
441 int rpmteHasCollection(rpmte te, const char *collname)
442 {
443     return (argvSearch(rpmteCollections(te), collname, NULL) != NULL);
444 }
445
446 int rpmteAddToLastInCollectionAdd(rpmte te, const char *collname)
447 {
448     if (te != NULL) {
449         argvAdd(&te->lastInCollectionsAdd, collname);
450         argvSort(te->lastInCollectionsAdd, NULL);
451         return 0;
452     }
453     return -1;
454 }
455
456 int rpmteAddToLastInCollectionAny(rpmte te, const char *collname)
457 {
458     if (te != NULL) {
459         argvAdd(&te->lastInCollectionsAny, collname);
460         argvSort(te->lastInCollectionsAny, NULL);
461         return 0;
462     }
463     return -1;
464 }
465
466 int rpmteAddToFirstInCollectionRemove(rpmte te, const char *collname)
467 {
468     if (te != NULL) {
469         argvAdd(&te->firstInCollectionsRemove, collname);
470         argvSort(te->firstInCollectionsRemove, NULL);
471         return 0;
472     }
473     return -1;
474 }
475
476 rpm_loff_t rpmtePkgFileSize(rpmte te)
477 {
478     return (te != NULL ? te->pkgFileSize : 0);
479 }
480
481 unsigned int rpmteHeaderSize(rpmte te)
482 {
483     return (te != NULL ? te->headerSize : 0);
484 }
485
486 rpmte rpmteParent(rpmte te)
487 {
488     return (te != NULL ? te->parent : NULL);
489 }
490
491 rpmte rpmteSetParent(rpmte te, rpmte pte)
492 {
493     rpmte opte = NULL;
494     if (te != NULL) {
495         opte = te->parent;
496         te->parent = pte;
497     }
498     return opte;
499 }
500
501 tsortInfo rpmteTSI(rpmte te)
502 {
503     return te->tsi;
504 }
505
506 void rpmteSetTSI(rpmte te, tsortInfo tsi)
507 {
508     te->tsi = tsi;
509 }
510
511 void rpmteSetDependsOn(rpmte te, rpmte depends)
512 {
513     te->depends = depends;
514 }
515
516 rpmte rpmteDependsOn(rpmte te)
517 {
518     return te->depends;
519 }
520
521 int rpmteDBOffset(rpmte te)
522 {
523     return rpmteDBInstance(te);
524 }
525
526 const char * rpmteEVR(rpmte te)
527 {
528     return (te != NULL ? te->NEVR + strlen(te->name) + 1 : NULL);
529 }
530
531 const char * rpmteNEVR(rpmte te)
532 {
533     return (te != NULL ? te->NEVR : NULL);
534 }
535
536 const char * rpmteNEVRA(rpmte te)
537 {
538     return (te != NULL ? te->NEVRA : NULL);
539 }
540
541 FD_t rpmteSetFd(rpmte te, FD_t fd)
542 {
543     if (te != NULL)  {
544         if (te->fd != NULL)
545             te->fd = fdFree(te->fd);
546         if (fd != NULL)
547             te->fd = fdLink(fd);
548     }
549     return NULL;
550 }
551
552 fnpyKey rpmteKey(rpmte te)
553 {
554     return (te != NULL ? te->key : NULL);
555 }
556
557 rpmds rpmteDS(rpmte te, rpmTagVal tag)
558 {
559     if (te == NULL)
560         return NULL;
561
562     switch (tag) {
563     case RPMTAG_NAME:           return te->thisds;
564     case RPMTAG_PROVIDENAME:    return te->provides;
565     case RPMTAG_REQUIRENAME:    return te->requires;
566     case RPMTAG_CONFLICTNAME:   return te->conflicts;
567     case RPMTAG_OBSOLETENAME:   return te->obsoletes;
568     case RPMTAG_ORDERNAME:      return te->order;
569     default:                    break;
570     }
571     return NULL;
572 }
573
574 rpmfi rpmteSetFI(rpmte te, rpmfi fi)
575 {
576     if (te != NULL)  {
577         te->fi = rpmfiFree(te->fi);
578         if (fi != NULL)
579             te->fi = rpmfiLink(fi);
580     }
581     return NULL;
582 }
583
584 rpmfi rpmteFI(rpmte te)
585 {
586     if (te == NULL)
587         return NULL;
588
589     return te->fi; /* XXX take fi reference here? */
590 }
591
592 static void rpmteColorDS(rpmte te, rpmTag tag)
593 {
594     rpmfi fi = rpmteFI(te);
595     rpmds ds = rpmteDS(te, tag);
596     char deptype = 'R';
597     char mydt;
598     const uint32_t * ddict;
599     rpm_color_t * colors;
600     rpm_color_t val;
601     int Count;
602     unsigned ix;
603     int ndx, i;
604
605     if (!(te && (Count = rpmdsCount(ds)) > 0 && rpmfiFC(fi) > 0))
606         return;
607
608     switch (tag) {
609     default:
610         return;
611         break;
612     case RPMTAG_PROVIDENAME:
613         deptype = 'P';
614         break;
615     case RPMTAG_REQUIRENAME:
616         deptype = 'R';
617         break;
618     }
619
620     colors = xcalloc(Count, sizeof(*colors));
621
622     /* Calculate dependency color. */
623     fi = rpmfiInit(fi, 0);
624     if (fi != NULL)
625     while (rpmfiNext(fi) >= 0) {
626         val = rpmfiFColor(fi);
627         ddict = NULL;
628         ndx = rpmfiFDepends(fi, &ddict);
629         if (ddict != NULL)
630         while (ndx-- > 0) {
631             ix = *ddict++;
632             mydt = ((ix >> 24) & 0xff);
633             if (mydt != deptype)
634                 continue;
635             ix &= 0x00ffffff;
636 assert (ix < Count);
637             colors[ix] |= val;
638         }
639     }
640
641     /* Set color values in dependency set. */
642     ds = rpmdsInit(ds);
643     while ((i = rpmdsNext(ds)) >= 0) {
644         val = colors[i];
645         te->color |= val;
646         (void) rpmdsSetColor(ds, val);
647     }
648     free(colors);
649 }
650
651 static Header rpmteDBHeader(rpmte te)
652 {
653     Header h = NULL;
654     rpmdbMatchIterator mi;
655
656     mi = rpmtsInitIterator(te->ts, RPMDBI_PACKAGES,
657                            &te->db_instance, sizeof(te->db_instance));
658     /* iterator returns weak refs, grab hold of header */
659     if ((h = rpmdbNextIterator(mi)))
660         h = headerLink(h);
661     rpmdbFreeIterator(mi);
662     return h;
663 }
664
665 static Header rpmteFDHeader(rpmte te)
666 {
667     Header h = NULL;
668     te->fd = rpmtsNotify(te->ts, te, RPMCALLBACK_INST_OPEN_FILE, 0, 0);
669     if (te->fd != NULL) {
670         rpmVSFlags ovsflags;
671         rpmRC pkgrc;
672
673         ovsflags = rpmtsSetVSFlags(te->ts,
674                                    rpmtsVSFlags(te->ts) | RPMVSF_NEEDPAYLOAD);
675         pkgrc = rpmReadPackageFile(te->ts, te->fd, rpmteNEVRA(te), &h);
676         rpmtsSetVSFlags(te->ts, ovsflags);
677         switch (pkgrc) {
678         default:
679             rpmteClose(te, 1);
680             break;
681         case RPMRC_NOTTRUSTED:
682         case RPMRC_NOKEY:
683         case RPMRC_OK:
684             break;
685         }
686     }
687     return h;
688 }
689
690 static int rpmteOpen(rpmte te, int reload_fi)
691 {
692     int rc = 0; /* assume failure */
693     Header h = NULL;
694     if (te == NULL || te->ts == NULL || rpmteFailed(te))
695         goto exit;
696
697     rpmteSetHeader(te, NULL);
698
699     switch (rpmteType(te)) {
700     case TR_ADDED:
701         h = rpmteDBInstance(te) ? rpmteDBHeader(te) : rpmteFDHeader(te);
702         break;
703     case TR_REMOVED:
704         h = rpmteDBHeader(te);
705         break;
706     }
707     if (h != NULL) {
708         if (reload_fi) {
709             /* This can fail if we get a different, bad header from callback */
710             te->fi = getFI(te, h);
711             rc = (te->fi != NULL);
712         } else {
713             rc = 1;
714         }
715         
716         rpmteSetHeader(te, h);
717         headerFree(h);
718     }
719
720 exit:
721     return rc;
722 }
723
724 static int rpmteClose(rpmte te, int reset_fi)
725 {
726     if (te == NULL || te->ts == NULL)
727         return 0;
728
729     switch (te->type) {
730     case TR_ADDED:
731         if (te->fd) {
732             rpmtsNotify(te->ts, te, RPMCALLBACK_INST_CLOSE_FILE, 0, 0);
733             te->fd = NULL;
734         }
735         break;
736     case TR_REMOVED:
737         /* eventually we'll want notifications for erase open too */
738         break;
739     }
740     rpmteSetHeader(te, NULL);
741     if (reset_fi) {
742         rpmteSetFI(te, NULL);
743     }
744     return 1;
745 }
746
747 FD_t rpmtePayload(rpmte te)
748 {
749     FD_t payload = NULL;
750     if (te->fd && te->h) {
751         const char *compr = headerGetString(te->h, RPMTAG_PAYLOADCOMPRESSOR);
752         char *ioflags = rstrscat(NULL, "r.", compr ? compr : "gzip", NULL);
753         payload = Fdopen(fdDup(Fileno(te->fd)), ioflags);
754         free(ioflags);
755     }
756     return payload;
757 }
758
759 static int rpmteMarkFailed(rpmte te)
760 {
761     rpmtsi pi = rpmtsiInit(te->ts);
762     rpmte p;
763
764     te->failed++;
765     /* XXX we can do a much better here than this... */
766     while ((p = rpmtsiNext(pi, TR_REMOVED))) {
767         if (rpmteDependsOn(p) == te) {
768             p->failed++;
769         }
770     }
771     rpmtsiFree(pi);
772     return te->failed;
773 }
774
775 int rpmteFailed(rpmte te)
776 {
777     return (te != NULL) ? te->failed : -1;
778 }
779
780 int rpmteHaveTransScript(rpmte te, rpmTagVal tag)
781 {
782     int rc = 0;
783     if (tag == RPMTAG_PRETRANS) {
784         rc = (te->transscripts & RPMTE_HAVE_PRETRANS);
785     } else if (tag == RPMTAG_POSTTRANS) {
786         rc = (te->transscripts & RPMTE_HAVE_POSTTRANS);
787     }
788     return rc;
789 }
790
791 rpmps rpmteProblems(rpmte te)
792 {
793     return (te != NULL) ? rpmpsLink(te->probs) : NULL;
794 }
795
796 void rpmteCleanProblems(rpmte te)
797 {
798     if (te != NULL && te->probs != NULL) {
799         te->probs = rpmpsFree(te->probs);
800     }
801 }
802
803 static void appendProblem(rpmte te, rpmProblemType type,
804                 fnpyKey key, const char * altNEVR,
805                 const char * str, uint64_t number)
806 {
807     rpmProblem o;
808     rpmProblem p = rpmProblemCreate(type, te->NEVRA, key, altNEVR, str, number);
809     rpmpsi psi = rpmpsInitIterator(te->probs);
810
811     /* Only add new, unique problems to the set */
812     while ((o = rpmpsiNext(psi))) {
813         if (rpmProblemCompare(p, o) == 0)
814             break;
815     }
816     rpmpsFreeIterator(psi);
817
818     if (o == NULL) {
819         if (te->probs == NULL)
820             te->probs = rpmpsCreate();
821         rpmpsAppendProblem(te->probs, p);
822     }
823     rpmProblemFree(p);
824 }
825
826 void rpmteAddProblem(rpmte te, rpmProblemType type,
827                      const char *altNEVR, const char *str, uint64_t number)
828 {
829     if (te != NULL) {
830         appendProblem(te, type, rpmteKey(te), altNEVR, str, number);
831     }
832 }
833
834 void rpmteAddDepProblem(rpmte te, const char * altNEVR, rpmds ds,
835                         fnpyKey * suggestedKeys)
836 {
837     if (te != NULL) {
838         const char * DNEVR = rpmdsDNEVR(ds);
839         rpmProblemType type;
840         fnpyKey key = (suggestedKeys ? suggestedKeys[0] : NULL);
841
842         switch ((unsigned)DNEVR[0]) {
843         case 'O':       type = RPMPROB_OBSOLETES;       break;
844         case 'C':       type = RPMPROB_CONFLICT;        break;
845         default:
846         case 'R':       type = RPMPROB_REQUIRES;        break;
847         }
848
849         appendProblem(te, type, key, altNEVR, DNEVR+2, rpmdsInstance(ds));
850     }
851 }
852
853 void rpmteAddRelocProblems(rpmte te)
854 {
855     if (te && te->badrelocs) {
856         for (int i = 0; i < te->nrelocs; i++) {
857             if (te->badrelocs[i]) {
858                 rpmteAddProblem(te, RPMPROB_BADRELOCATE, NULL,
859                                 te->relocs[i].oldPath, 0);
860             }
861         }
862     }
863 }
864
865 const char * rpmteTypeString(rpmte te)
866 {
867     switch(rpmteType(te)) {
868     case TR_ADDED:      return _("install");
869     case TR_REMOVED:    return _("erase");
870     default:            return "???";
871     }
872 }
873
874 rpmfs rpmteGetFileStates(rpmte te)
875 {
876     return te->fs;
877 }
878
879 rpmRC rpmteSetupCollectionPlugins(rpmte te)
880 {
881     ARGV_const_t colls = rpmteCollections(te);
882     rpmPlugins plugins = rpmtsPlugins(te->ts);
883     rpmRC rc = RPMRC_OK;
884
885     if (!colls) {
886         return rc;
887     }
888
889     rpmteOpen(te, 0);
890     for (; colls && *colls; colls++) {
891         if (!rpmpluginsPluginAdded(plugins, *colls)) {
892             rc = rpmpluginsAddPlugin(plugins, "collection", *colls);
893             if (rc != RPMRC_OK) {
894                 break;
895             }
896         }
897         rc = rpmpluginsCallOpenTE(plugins, *colls, te);
898         if (rc != RPMRC_OK) {
899             break;
900         }
901     }
902     rpmteClose(te, 0);
903
904     return rc;
905 }
906
907 static rpmRC rpmteRunAllCollections(rpmte te, rpmPluginHook hook)
908 {
909     ARGV_const_t colls;
910     rpmRC(*collHook) (rpmPlugins, const char *);
911     rpmRC rc = RPMRC_OK;
912
913     if (rpmtsFlags(te->ts) & RPMTRANS_FLAG_NOCOLLECTIONS) {
914         goto exit;
915     }
916
917     switch (hook) {
918     case PLUGINHOOK_COLL_POST_ADD:
919         colls = te->lastInCollectionsAdd;
920         collHook = rpmpluginsCallCollectionPostAdd;
921         break;
922     case PLUGINHOOK_COLL_POST_ANY:
923         colls = te->lastInCollectionsAny;
924         collHook = rpmpluginsCallCollectionPostAny;
925         break;
926     case PLUGINHOOK_COLL_PRE_REMOVE:
927         colls = te->firstInCollectionsRemove;
928         collHook = rpmpluginsCallCollectionPreRemove;
929         break;
930     default:
931         goto exit;
932     }
933
934     for (; colls && *colls; colls++) {
935         rc = collHook(rpmtsPlugins(te->ts), *colls);
936     }
937
938   exit:
939     return rc;
940 }
941
942 int rpmteProcess(rpmte te, pkgGoal goal)
943 {
944     /* Only install/erase resets pkg file info */
945     int scriptstage = (goal != PKG_INSTALL && goal != PKG_ERASE);
946     int test = (rpmtsFlags(te->ts) & RPMTRANS_FLAG_TEST);
947     int reset_fi = (scriptstage == 0 && test == 0);
948     int failed = 1;
949
950     /* Dont bother opening for elements without pre/posttrans scripts */
951     if (goal == PKG_PRETRANS || goal == PKG_POSTTRANS) {
952         if (!rpmteHaveTransScript(te, goal)) {
953             return 0;
954         }
955     }
956
957     if (!scriptstage) {
958         rpmteRunAllCollections(te, PLUGINHOOK_COLL_PRE_REMOVE);
959     }
960
961     if (rpmteOpen(te, reset_fi)) {
962         failed = rpmpsmRun(te->ts, te, goal);
963         rpmteClose(te, reset_fi);
964     }
965     
966     if (!scriptstage) {
967         rpmteRunAllCollections(te, PLUGINHOOK_COLL_POST_ADD);
968         rpmteRunAllCollections(te, PLUGINHOOK_COLL_POST_ANY);
969     }
970
971     if (failed) {
972         failed = rpmteMarkFailed(te);
973     }
974
975     return failed;
976 }