Realize the remaining bits of direct rpmdb interface are dead too
[platform/upstream/rpm.git] / build / pack.c
1 /** \ingroup rpmbuild
2  * \file build/pack.c
3  *  Assemble components of an RPM package.
4  */
5
6 #include "system.h"
7
8 #include <rpm/rpmlib.h>                 /* RPMSIGTAG*, rpmReadPackageFile */
9 #include <rpm/rpmts.h>
10 #include <rpm/rpmbuild.h>
11 #include <rpm/rpmfileutil.h>
12 #include <rpm/rpmlog.h>
13
14 #include "rpmio/rpmio_internal.h"       /* fdInitDigest, fdFiniDigest */
15 #include "lib/cpio.h"
16 #include "lib/fsm.h"
17 #include "lib/rpmfi_internal.h"         /* rpmfiFSM() */
18 #include "lib/rpmte_internal.h"         /* rpmfs */
19 #include "lib/signature.h"
20 #include "lib/rpmlead.h"
21 #include "build/buildio.h"
22
23 #include "debug.h"
24
25 /**
26  * @todo Create transaction set *much* earlier.
27  */
28 static rpmRC cpio_doio(FD_t fdo, Header h, CSA_t csa,
29                 const char * fmodeMacro)
30 {
31     rpmts ts = rpmtsCreate();
32     rpmfi fi = csa->cpioList;
33     rpmte te = NULL;
34     rpmfs fs = NULL;
35     char *failedFile = NULL;
36     FD_t cfd;
37     rpmRC rc = RPMRC_OK;
38     int xx, i;
39
40     {   char *fmode = rpmExpand(fmodeMacro, NULL);
41         if (!(fmode && fmode[0] == 'w'))
42             fmode = xstrdup("w9.gzdio");
43         (void) Fflush(fdo);
44         cfd = Fdopen(fdDup(Fileno(fdo)), fmode);
45         fmode = _free(fmode);
46     }
47     if (cfd == NULL)
48         return RPMRC_FAIL;
49
50     /* make up a transaction element for passing to fsm */
51     rpmtsAddInstallElement(ts, h, NULL, 0, NULL);
52     te = rpmtsElement(ts, 0);
53     fs = rpmteGetFileStates(te);
54
55     fi = rpmfiInit(fi, 0);
56     while ((i = rpmfiNext(fi)) >= 0) {
57         if (rpmfiFFlags(fi) & RPMFILE_GHOST)
58             rpmfsSetAction(fs, i, FA_SKIP);
59         else
60             rpmfsSetAction(fs, i, FA_COPYOUT);
61     }
62
63     xx = fsmSetup(rpmfiFSM(fi), FSM_PKGBUILD, ts, te, fi, cfd,
64                 &csa->cpioArchiveSize, &failedFile);
65     if (xx)
66         rc = RPMRC_FAIL;
67     (void) Fclose(cfd);
68     xx = fsmTeardown(rpmfiFSM(fi));
69     if (rc == RPMRC_OK && xx) rc = RPMRC_FAIL;
70
71     if (rc) {
72         if (failedFile)
73             rpmlog(RPMLOG_ERR, _("create archive failed on file %s: %s\n"),
74                 failedFile, cpioStrerror(rc));
75         else
76             rpmlog(RPMLOG_ERR, _("create archive failed: %s\n"),
77                 cpioStrerror(rc));
78       rc = RPMRC_FAIL;
79     }
80     rpmtsEmpty(ts);
81
82     failedFile = _free(failedFile);
83     ts = rpmtsFree(ts);
84
85     return rc;
86 }
87
88 /**
89  */
90 static rpmRC cpio_copy(FD_t fdo, CSA_t csa)
91 {
92     char buf[BUFSIZ];
93     size_t nb;
94
95     while((nb = Fread(buf, sizeof(buf[0]), sizeof(buf), csa->cpioFdIn)) > 0) {
96         if (Fwrite(buf, sizeof(buf[0]), nb, fdo) != nb) {
97             rpmlog(RPMLOG_ERR, _("cpio_copy write failed: %s\n"),
98                         Fstrerror(fdo));
99             return RPMRC_FAIL;
100         }
101         csa->cpioArchiveSize += nb;
102     }
103     if (Ferror(csa->cpioFdIn)) {
104         rpmlog(RPMLOG_ERR, _("cpio_copy read failed: %s\n"),
105                 Fstrerror(csa->cpioFdIn));
106         return RPMRC_FAIL;
107     }
108     return RPMRC_OK;
109 }
110
111 /**
112  */
113 static StringBuf addFileToTagAux(rpmSpec spec,
114                 const char * file, StringBuf sb)
115 {
116     char buf[BUFSIZ];
117     char * fn;
118     FILE * f;
119
120     fn = rpmGetPath("%{_builddir}/%{?buildsubdir:%{buildsubdir}/}", file, NULL);
121
122     f = fopen(fn, "r");
123     if (f == NULL || ferror(f)) {
124         sb = freeStringBuf(sb);
125         goto exit;
126     }
127     while (fgets(buf, sizeof(buf), f)) {
128         if (expandMacros(spec, spec->macros, buf, sizeof(buf))) {
129             rpmlog(RPMLOG_ERR, _("%s: line: %s\n"), fn, buf);
130             sb = freeStringBuf(sb);
131             break;
132         }
133         appendStringBuf(sb, buf);
134     }
135     (void) fclose(f);
136
137 exit:
138     free(fn);
139
140     return sb;
141 }
142
143 /**
144  */
145 static int addFileToTag(rpmSpec spec, const char * file, Header h, rpmTag tag)
146 {
147     StringBuf sb = newStringBuf();
148     const char *s = headerGetString(h, tag);
149
150     if (s) {
151         appendLineStringBuf(sb, s);
152         (void) headerDel(h, tag);
153     }
154
155     if ((sb = addFileToTagAux(spec, file, sb)) == NULL)
156         return 1;
157     
158     headerPutString(h, tag, getStringBuf(sb));
159
160     sb = freeStringBuf(sb);
161     return 0;
162 }
163
164 /**
165  */
166 static int addFileToArrayTag(rpmSpec spec, const char *file, Header h, rpmTag tag)
167 {
168     StringBuf sb = newStringBuf();
169     const char *s;
170
171     if ((sb = addFileToTagAux(spec, file, sb)) == NULL)
172         return 1;
173
174     s = getStringBuf(sb);
175     headerPutString(h, tag, s);
176
177     sb = freeStringBuf(sb);
178     return 0;
179 }
180
181 /**
182  */
183 static rpmRC processScriptFiles(rpmSpec spec, Package pkg)
184 {
185     struct TriggerFileEntry *p;
186     
187     if (pkg->preInFile) {
188         if (addFileToTag(spec, pkg->preInFile, pkg->header, RPMTAG_PREIN)) {
189             rpmlog(RPMLOG_ERR,
190                      _("Could not open PreIn file: %s\n"), pkg->preInFile);
191             return RPMRC_FAIL;
192         }
193     }
194     if (pkg->preUnFile) {
195         if (addFileToTag(spec, pkg->preUnFile, pkg->header, RPMTAG_PREUN)) {
196             rpmlog(RPMLOG_ERR,
197                      _("Could not open PreUn file: %s\n"), pkg->preUnFile);
198             return RPMRC_FAIL;
199         }
200     }
201     if (pkg->preTransFile) {
202         if (addFileToTag(spec, pkg->preTransFile, pkg->header, RPMTAG_PRETRANS)) {
203             rpmlog(RPMLOG_ERR,
204                      _("Could not open PreTrans file: %s\n"), pkg->preTransFile);
205             return RPMRC_FAIL;
206         }
207     }
208     if (pkg->postInFile) {
209         if (addFileToTag(spec, pkg->postInFile, pkg->header, RPMTAG_POSTIN)) {
210             rpmlog(RPMLOG_ERR,
211                      _("Could not open PostIn file: %s\n"), pkg->postInFile);
212             return RPMRC_FAIL;
213         }
214     }
215     if (pkg->postUnFile) {
216         if (addFileToTag(spec, pkg->postUnFile, pkg->header, RPMTAG_POSTUN)) {
217             rpmlog(RPMLOG_ERR,
218                      _("Could not open PostUn file: %s\n"), pkg->postUnFile);
219             return RPMRC_FAIL;
220         }
221     }
222     if (pkg->postTransFile) {
223         if (addFileToTag(spec, pkg->postTransFile, pkg->header, RPMTAG_POSTTRANS)) {
224             rpmlog(RPMLOG_ERR,
225                      _("Could not open PostTrans file: %s\n"), pkg->postTransFile);
226             return RPMRC_FAIL;
227         }
228     }
229     if (pkg->verifyFile) {
230         if (addFileToTag(spec, pkg->verifyFile, pkg->header,
231                          RPMTAG_VERIFYSCRIPT)) {
232             rpmlog(RPMLOG_ERR,
233                      _("Could not open VerifyScript file: %s\n"), pkg->verifyFile);
234             return RPMRC_FAIL;
235         }
236     }
237
238     for (p = pkg->triggerFiles; p != NULL; p = p->next) {
239         headerPutString(pkg->header, RPMTAG_TRIGGERSCRIPTPROG, p->prog);
240
241         if (p->script) {
242             headerPutString(pkg->header, RPMTAG_TRIGGERSCRIPTS, p->script);
243         } else if (p->fileName) {
244             if (addFileToArrayTag(spec, p->fileName, pkg->header,
245                                   RPMTAG_TRIGGERSCRIPTS)) {
246                 rpmlog(RPMLOG_ERR,
247                          _("Could not open Trigger script file: %s\n"),
248                          p->fileName);
249                 return RPMRC_FAIL;
250             }
251         } else {
252             /* This is dumb.  When the header supports NULL string */
253             /* this will go away.                                  */
254             headerPutString(pkg->header, RPMTAG_TRIGGERSCRIPTS, "");
255         }
256     }
257
258     return RPMRC_OK;
259 }
260
261 rpmRC readRPM(const char *fileName, rpmSpec *specp, 
262                 Header *sigs, CSA_t csa)
263 {
264     FD_t fdi;
265     rpmSpec spec;
266     rpmRC rc;
267
268     fdi = (fileName != NULL)
269         ? Fopen(fileName, "r.ufdio")
270         : fdDup(STDIN_FILENO);
271
272     if (fdi == NULL || Ferror(fdi)) {
273         rpmlog(RPMLOG_ERR, _("readRPM: open %s: %s\n"),
274                 (fileName ? fileName : "<stdin>"),
275                 Fstrerror(fdi));
276         if (fdi) (void) Fclose(fdi);
277         return RPMRC_FAIL;
278     }
279
280     /* XXX FIXME: EPIPE on <stdin> */
281     if (Fseek(fdi, 0, SEEK_SET) == -1) {
282         rpmlog(RPMLOG_ERR, _("%s: Fseek failed: %s\n"),
283                         (fileName ? fileName : "<stdin>"), Fstrerror(fdi));
284         return RPMRC_FAIL;
285     }
286
287     /* Reallocate build data structures */
288     spec = newSpec();
289     spec->packages = newPackage(spec);
290
291     /* XXX the header just allocated will be allocated again */
292     spec->packages->header = headerFree(spec->packages->header);
293
294     /* Read the rpm lead, signatures, and header */
295     {   rpmts ts = rpmtsCreate();
296
297         /* XXX W2DO? pass fileName? */
298         rc = rpmReadPackageFile(ts, fdi, "readRPM",
299                          &spec->packages->header);
300
301         ts = rpmtsFree(ts);
302
303         if (sigs) *sigs = NULL;                 /* XXX HACK */
304     }
305
306     switch (rc) {
307     case RPMRC_OK:
308     case RPMRC_NOKEY:
309     case RPMRC_NOTTRUSTED:
310         break;
311     case RPMRC_NOTFOUND:
312         rpmlog(RPMLOG_ERR, _("readRPM: %s is not an RPM package\n"),
313                 (fileName ? fileName : "<stdin>"));
314         return RPMRC_FAIL;
315     case RPMRC_FAIL:
316     default:
317         rpmlog(RPMLOG_ERR, _("readRPM: reading header from %s\n"),
318                 (fileName ? fileName : "<stdin>"));
319         return RPMRC_FAIL;
320         break;
321     }
322
323     if (specp)
324         *specp = spec;
325     else
326         spec = freeSpec(spec);
327
328     if (csa != NULL)
329         csa->cpioFdIn = fdi;
330     else
331         (void) Fclose(fdi);
332
333     return RPMRC_OK;
334 }
335
336 rpmRC writeRPM(Header *hdrp, unsigned char ** pkgidp, const char *fileName,
337              CSA_t csa, char *passPhrase, char **cookie)
338 {
339     FD_t fd = NULL;
340     FD_t ifd = NULL;
341     ssize_t count;
342     rpmSigTag sigtag;
343     char * sigtarget = NULL;;
344     char * rpmio_flags = NULL;
345     char * SHA1 = NULL;
346     char *s;
347     char *buf = NULL;
348     Header h;
349     Header sig = NULL;
350     int xx;
351     rpmRC rc = RPMRC_OK;
352     struct rpmtd_s td;
353     rpmSigTag sizetag;
354     rpmTag payloadtag;
355
356     /* Transfer header reference form *hdrp to h. */
357     h = headerLink(*hdrp);
358     *hdrp = headerFree(*hdrp);
359
360     if (pkgidp)
361         *pkgidp = NULL;
362
363     /* Save payload information */
364     if (headerIsSource(h))
365         rpmio_flags = rpmExpand("%{?_source_payload}", NULL);
366     else 
367         rpmio_flags = rpmExpand("%{?_binary_payload}", NULL);
368
369     if (!(rpmio_flags && *rpmio_flags)) {
370         rpmio_flags = _free(rpmio_flags);
371         rpmio_flags = xstrdup("w9.gzdio");
372     }
373     s = strchr(rpmio_flags, '.');
374     if (s) {
375         const char *compr = NULL;
376         headerPutString(h, RPMTAG_PAYLOADFORMAT, "cpio");
377
378         if (rstreq(s+1, "gzdio")) {
379             compr = "gzip";
380 #if HAVE_BZLIB_H
381         } else if (rstreq(s+1, "bzdio")) {
382             compr = "bzip2";
383             /* Add prereq on rpm version that understands bzip2 payloads */
384             (void) rpmlibNeedsFeature(h, "PayloadIsBzip2", "3.0.5-1");
385 #endif
386 #if HAVE_LZMA_H
387         } else if (rstreq(s+1, "xzdio")) {
388             compr = "xz";
389             (void) rpmlibNeedsFeature(h, "PayloadIsXz", "5.2-1");
390         } else if (rstreq(s+1, "lzdio")) {
391             compr = "lzma";
392             (void) rpmlibNeedsFeature(h, "PayloadIsLzma", "4.4.6-1");
393 #endif
394         } else {
395             rpmlog(RPMLOG_ERR, _("Unknown payload compression: %s\n"),
396                    rpmio_flags);
397             rc = RPMRC_FAIL;
398             goto exit;
399         }
400
401         headerPutString(h, RPMTAG_PAYLOADCOMPRESSOR, compr);
402         buf = xstrdup(rpmio_flags);
403         buf[s - rpmio_flags] = '\0';
404         headerPutString(h, RPMTAG_PAYLOADFLAGS, buf+1);
405         free(buf);
406     }
407
408     /* Create and add the cookie */
409     if (cookie) {
410         rasprintf(cookie, "%s %d", buildHost(), (int) (*getBuildTime()));
411         headerPutString(h, RPMTAG_COOKIE, *cookie);
412     }
413     
414     /* Reallocate the header into one contiguous region. */
415     h = headerReload(h, RPMTAG_HEADERIMMUTABLE);
416     if (h == NULL) {    /* XXX can't happen */
417         rc = RPMRC_FAIL;
418         rpmlog(RPMLOG_ERR, _("Unable to create immutable header region.\n"));
419         goto exit;
420     }
421     /* Re-reference reallocated header. */
422     *hdrp = headerLink(h);
423
424     /*
425      * Write the header+archive into a temp file so that the size of
426      * archive (after compression) can be added to the header.
427      */
428     fd = rpmMkTempFile(NULL, &sigtarget);
429     if (fd == NULL || Ferror(fd)) {
430         rc = RPMRC_FAIL;
431         rpmlog(RPMLOG_ERR, _("Unable to open temp file.\n"));
432         goto exit;
433     }
434
435     fdInitDigest(fd, PGPHASHALGO_SHA1, 0);
436     if (headerWrite(fd, h, HEADER_MAGIC_YES)) {
437         rc = RPMRC_FAIL;
438         rpmlog(RPMLOG_ERR, _("Unable to write temp header\n"));
439     } else { /* Write the archive and get the size */
440         (void) Fflush(fd);
441         fdFiniDigest(fd, PGPHASHALGO_SHA1, (void **)&SHA1, NULL, 1);
442         if (csa->cpioList != NULL) {
443             rc = cpio_doio(fd, h, csa, rpmio_flags);
444         } else if (Fileno(csa->cpioFdIn) >= 0) {
445             rc = cpio_copy(fd, csa);
446         } else {
447             rc = RPMRC_FAIL;
448             rpmlog(RPMLOG_ERR, _("Bad CSA data\n"));
449         }
450     }
451     rpmio_flags = _free(rpmio_flags);
452
453     if (rc != RPMRC_OK)
454         goto exit;
455
456     (void) Fclose(fd);
457     fd = NULL;
458     (void) unlink(fileName);
459
460     /* Generate the signature */
461     (void) fflush(stdout);
462     sig = rpmNewSignature();
463
464     /*
465      * There should be rpmlib() dependency on this, but that doesn't
466      * really do much good as these are signature tags that get read
467      * way before dependency checking has a chance to figure out anything.
468      * On the positive side, not inserting the 32bit tag at all means
469      * older rpm will just bail out with error message on attempt to read
470      * such a package.
471      */
472     if (csa->cpioArchiveSize < UINT32_MAX) {
473         sizetag = RPMSIGTAG_SIZE;
474         payloadtag = RPMSIGTAG_PAYLOADSIZE;
475     } else {
476         sizetag = RPMSIGTAG_LONGSIZE;
477         payloadtag = RPMSIGTAG_LONGARCHIVESIZE;
478     }
479     (void) rpmAddSignature(sig, sigtarget, sizetag, passPhrase);
480     (void) rpmAddSignature(sig, sigtarget, RPMSIGTAG_MD5, passPhrase);
481
482     if ((sigtag = rpmLookupSignatureType(RPMLOOKUPSIG_QUERY)) > 0) {
483         rpmlog(RPMLOG_NOTICE, _("Generating signature: %d\n"), sigtag);
484         (void) rpmAddSignature(sig, sigtarget, sigtag, passPhrase);
485     }
486     
487     if (SHA1) {
488         /* XXX can't use rpmtdFromFoo() on RPMSIGTAG_* items */
489         rpmtdReset(&td);
490         td.tag = RPMSIGTAG_SHA1;
491         td.type = RPM_STRING_TYPE;
492         td.data = SHA1;
493         td.count = 1;
494         headerPut(sig, &td, HEADERPUT_DEFAULT);
495         SHA1 = _free(SHA1);
496     }
497
498     {   
499         /* XXX can't use headerPutType() on legacy RPMSIGTAG_* items */
500         rpmtdReset(&td);
501         td.tag = payloadtag;
502         td.count = 1;
503         if (payloadtag == RPMSIGTAG_PAYLOADSIZE) {
504             rpm_off_t asize = csa->cpioArchiveSize;
505             td.type = RPM_INT32_TYPE;
506             td.data = &asize;
507             headerPut(sig, &td, HEADERPUT_DEFAULT);
508         } else {
509             rpm_loff_t asize = csa->cpioArchiveSize;
510             td.type = RPM_INT64_TYPE;
511             td.data = &asize;
512             headerPut(sig, &td, HEADERPUT_DEFAULT);
513         }
514     }
515
516     /* Reallocate the signature into one contiguous region. */
517     sig = headerReload(sig, RPMTAG_HEADERSIGNATURES);
518     if (sig == NULL) {  /* XXX can't happen */
519         rc = RPMRC_FAIL;
520         rpmlog(RPMLOG_ERR, _("Unable to reload signature header.\n"));
521         goto exit;
522     }
523
524     /* Open the output file */
525     fd = Fopen(fileName, "w.ufdio");
526     if (fd == NULL || Ferror(fd)) {
527         rc = RPMRC_FAIL;
528         rpmlog(RPMLOG_ERR, _("Could not open %s: %s\n"),
529                 fileName, Fstrerror(fd));
530         goto exit;
531     }
532
533     /* Write the lead section into the package. */
534     {   
535         rpmlead lead = rpmLeadFromHeader(h);
536         rc = rpmLeadWrite(fd, lead);
537         lead = rpmLeadFree(lead);
538         if (rc != RPMRC_OK) {
539             rc = RPMRC_FAIL;
540             rpmlog(RPMLOG_ERR, _("Unable to write package: %s\n"),
541                  Fstrerror(fd));
542             goto exit;
543         }
544     }
545
546     /* Write the signature section into the package. */
547     if (rpmWriteSignature(fd, sig)) {
548         rc = RPMRC_FAIL;
549         goto exit;
550     }
551
552     /* Append the header and archive */
553     ifd = Fopen(sigtarget, "r.ufdio");
554     if (ifd == NULL || Ferror(ifd)) {
555         rc = RPMRC_FAIL;
556         rpmlog(RPMLOG_ERR, _("Unable to open sigtarget %s: %s\n"),
557                 sigtarget, Fstrerror(ifd));
558         goto exit;
559     }
560
561     /* Add signatures to header, and write header into the package. */
562     /* XXX header+payload digests/signatures might be checked again here. */
563     {   Header nh = headerRead(ifd, HEADER_MAGIC_YES);
564
565         if (nh == NULL) {
566             rc = RPMRC_FAIL;
567             rpmlog(RPMLOG_ERR, _("Unable to read header from %s: %s\n"),
568                         sigtarget, Fstrerror(ifd));
569             goto exit;
570         }
571
572 #ifdef  NOTYET
573         (void) headerMergeLegacySigs(nh, sig);
574 #endif
575
576         xx = headerWrite(fd, nh, HEADER_MAGIC_YES);
577         nh = headerFree(nh);
578
579         if (xx) {
580             rc = RPMRC_FAIL;
581             rpmlog(RPMLOG_ERR, _("Unable to write header to %s: %s\n"),
582                         fileName, Fstrerror(fd));
583             goto exit;
584         }
585     }
586         
587     /* Write the payload into the package. */
588     buf = xmalloc(BUFSIZ);
589     while ((count = Fread(buf, 1, BUFSIZ, ifd)) > 0) {
590         if (count == -1) {
591             free(buf);
592             rc = RPMRC_FAIL;
593             rpmlog(RPMLOG_ERR, _("Unable to read payload from %s: %s\n"),
594                      sigtarget, Fstrerror(ifd));
595             goto exit;
596         }
597         if (Fwrite(buf, sizeof(buf[0]), count, fd) != count) {
598             free(buf);
599             rc = RPMRC_FAIL;
600             rpmlog(RPMLOG_ERR, _("Unable to write payload to %s: %s\n"),
601                      fileName, Fstrerror(fd));
602             goto exit;
603         }
604     }
605     free(buf);
606     rc = RPMRC_OK;
607
608 exit:
609     SHA1 = _free(SHA1);
610     h = headerFree(h);
611
612     /* XXX Fish the pkgid out of the signature header. */
613     if (sig != NULL && pkgidp != NULL) {
614         struct rpmtd_s md5tag;
615         headerGet(sig, RPMSIGTAG_MD5, &md5tag, HEADERGET_DEFAULT);
616         if (rpmtdType(&md5tag) == RPM_BIN_TYPE &&
617                                 md5tag.count == 16 && md5tag.data != NULL) {
618             *pkgidp = md5tag.data;
619         }
620     }
621
622     sig = rpmFreeSignature(sig);
623     if (ifd) {
624         (void) Fclose(ifd);
625         ifd = NULL;
626     }
627     if (fd) {
628         (void) Fclose(fd);
629         fd = NULL;
630     }
631     if (sigtarget) {
632         (void) unlink(sigtarget);
633         sigtarget = _free(sigtarget);
634     }
635
636     if (rc == RPMRC_OK)
637         rpmlog(RPMLOG_NOTICE, _("Wrote: %s\n"), fileName);
638     else
639         (void) unlink(fileName);
640
641     return rc;
642 }
643
644 static const rpmTag copyTags[] = {
645     RPMTAG_CHANGELOGTIME,
646     RPMTAG_CHANGELOGNAME,
647     RPMTAG_CHANGELOGTEXT,
648     0
649 };
650
651 /*
652  * Add extra provides to package.
653  */
654 static void addPackageProvides(Header h)
655 {
656     const char *arch, *name;
657     char *evr, *isaprov;
658     rpmsenseFlags pflags = RPMSENSE_EQUAL;
659
660     /* <name> = <evr> provide */
661     name = headerGetString(h, RPMTAG_NAME);
662     arch = headerGetString(h, RPMTAG_ARCH);
663     evr = headerGetAsString(h, RPMTAG_EVR);
664     headerPutString(h, RPMTAG_PROVIDENAME, name);
665     headerPutString(h, RPMTAG_PROVIDEVERSION, evr);
666     headerPutUint32(h, RPMTAG_PROVIDEFLAGS, &pflags, 1);
667
668     /*
669      * <name>(<isa>) = <evr> provide
670      * FIXME: noarch needs special casing for now as BuildArch: noarch doesn't
671      * cause reading in the noarch macros :-/ 
672      */
673     isaprov = rpmExpand(name, "%{?_isa}", NULL);
674     if (!rstreq(arch, "noarch") && !rstreq(name, isaprov)) {
675         headerPutString(h, RPMTAG_PROVIDENAME, isaprov);
676         headerPutString(h, RPMTAG_PROVIDEVERSION, evr);
677         headerPutUint32(h, RPMTAG_PROVIDEFLAGS, &pflags, 1);
678     }
679     free(isaprov);
680     free(evr);
681 }
682
683 rpmRC checkPackages(char *pkgcheck)
684 {
685     int fail = rpmExpandNumeric("%{?_nonzero_exit_pkgcheck_terminate_build}");
686     int xx;
687     
688     rpmlog(RPMLOG_NOTICE, _("Executing \"%s\":\n"), pkgcheck);
689     xx = system(pkgcheck);
690     if (WEXITSTATUS(xx) == -1 || WEXITSTATUS(xx) == 127) {
691         rpmlog(RPMLOG_ERR, _("Execution of \"%s\" failed.\n"), pkgcheck);
692         if (fail) return 127;
693     }
694     if (WEXITSTATUS(xx) != 0) {
695         rpmlog(RPMLOG_ERR, _("Package check \"%s\" failed.\n"), pkgcheck);
696         if (fail) return RPMRC_FAIL;
697     }
698     
699     return RPMRC_OK;
700 }
701
702 rpmRC packageBinaries(rpmSpec spec)
703 {
704     struct cpioSourceArchive_s csabuf;
705     CSA_t csa = &csabuf;
706     rpmRC rc;
707     const char *errorString;
708     Package pkg;
709     char *pkglist = NULL;
710
711     for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
712         char *fn;
713
714         if (pkg->fileList == NULL)
715             continue;
716
717         if ((rc = processScriptFiles(spec, pkg)))
718             return rc;
719         
720         if (spec->cookie) {
721             headerPutString(pkg->header, RPMTAG_COOKIE, spec->cookie);
722         }
723
724         /* Copy changelog from src rpm */
725         headerCopyTags(spec->packages->header, pkg->header, copyTags);
726         
727         headerPutString(pkg->header, RPMTAG_RPMVERSION, VERSION);
728         headerPutString(pkg->header, RPMTAG_BUILDHOST, buildHost());
729         headerPutUint32(pkg->header, RPMTAG_BUILDTIME, getBuildTime(), 1);
730
731         addPackageProvides(pkg->header);
732
733     {   char * optflags = rpmExpand("%{optflags}", NULL);
734         headerPutString(pkg->header, RPMTAG_OPTFLAGS, optflags);
735         optflags = _free(optflags);
736     }
737
738         if (spec->sourcePkgId != NULL) {
739             headerPutBin(pkg->header, RPMTAG_SOURCEPKGID, spec->sourcePkgId,16);
740         }
741         
742         {   char *binFormat = rpmGetPath("%{_rpmfilename}", NULL);
743             char *binRpm, *binDir;
744             binRpm = headerFormat(pkg->header, binFormat, &errorString);
745             binFormat = _free(binFormat);
746             if (binRpm == NULL) {
747                 rpmlog(RPMLOG_ERR, _("Could not generate output "
748                      "filename for package %s: %s\n"), 
749                      headerGetString(pkg->header, RPMTAG_NAME), errorString);
750                 return RPMRC_FAIL;
751             }
752             fn = rpmGetPath("%{_rpmdir}/", binRpm, NULL);
753             if ((binDir = strchr(binRpm, '/')) != NULL) {
754                 struct stat st;
755                 char *dn;
756                 *binDir = '\0';
757                 dn = rpmGetPath("%{_rpmdir}/", binRpm, NULL);
758                 if (stat(dn, &st) < 0) {
759                     switch(errno) {
760                     case  ENOENT:
761                         if (mkdir(dn, 0755) == 0)
762                             break;
763                     default:
764                         rpmlog(RPMLOG_ERR,_("cannot create %s: %s\n"),
765                             dn, strerror(errno));
766                         break;
767                     }
768                 }
769                 dn = _free(dn);
770             }
771             binRpm = _free(binRpm);
772         }
773
774         memset(csa, 0, sizeof(*csa));
775         csa->cpioArchiveSize = 0;
776         csa->cpioFdIn = fdNew(RPMDBG_M("init (packageBinaries)"));
777         csa->cpioList = rpmfiLink(pkg->cpioList, RPMDBG_M("packageBinaries"));
778
779         rc = writeRPM(&pkg->header, NULL, fn, csa, spec->passPhrase, NULL);
780         csa->cpioList = rpmfiFree(csa->cpioList);
781         csa->cpioFdIn = fdFree(csa->cpioFdIn, 
782                                RPMDBG_M("init (packageBinaries)"));
783         if (rc == RPMRC_OK) {
784             /* Do check each written package if enabled */
785             char *pkgcheck = rpmExpand("%{?_build_pkgcheck} ", fn, NULL);
786             if (pkgcheck[0] != ' ') {
787                 rc = checkPackages(pkgcheck);
788             }
789             pkgcheck = _free(pkgcheck);
790             rstrcat(&pkglist, fn);
791             rstrcat(&pkglist, " ");
792         }
793         fn = _free(fn);
794         if (rc != RPMRC_OK) {
795             pkglist = _free(pkglist);
796             return rc;
797         }
798     }
799
800     /* Now check the package set if enabled */
801     if (pkglist != NULL) {
802         char *pkgcheck_set = rpmExpand("%{?_build_pkgcheck_set} ", pkglist,  NULL);
803         if (pkgcheck_set[0] != ' ') {   /* run only if _build_pkgcheck_set is defined */
804             checkPackages(pkgcheck_set);
805         }
806         pkgcheck_set = _free(pkgcheck_set);
807         pkglist = _free(pkglist);
808     }
809     
810     return RPMRC_OK;
811 }
812
813 rpmRC packageSources(rpmSpec spec)
814 {
815     struct cpioSourceArchive_s csabuf;
816     CSA_t csa = &csabuf;
817     rpmRC rc;
818
819     /* Add some cruft */
820     headerPutString(spec->sourceHeader, RPMTAG_RPMVERSION, VERSION);
821     headerPutString(spec->sourceHeader, RPMTAG_BUILDHOST, buildHost());
822     headerPutUint32(spec->sourceHeader, RPMTAG_BUILDTIME, getBuildTime(), 1);
823
824     spec->cookie = _free(spec->cookie);
825     
826     /* XXX this should be %_srpmdir */
827     {   char *fn = rpmGetPath("%{_srcrpmdir}/", spec->sourceRpmName,NULL);
828         char *pkgcheck = rpmExpand("%{?_build_pkgcheck_srpm} ", fn, NULL);
829
830         memset(csa, 0, sizeof(*csa));
831         csa->cpioArchiveSize = 0;
832         csa->cpioFdIn = fdNew(RPMDBG_M("init (packageSources)"));
833         csa->cpioList = rpmfiLink(spec->sourceCpioList, 
834                                   RPMDBG_M("packageSources"));
835
836         spec->sourcePkgId = NULL;
837         rc = writeRPM(&spec->sourceHeader, &spec->sourcePkgId, fn, 
838                 csa, spec->passPhrase, &(spec->cookie));
839
840         /* Do check SRPM package if enabled */
841         if (rc == RPMRC_OK && pkgcheck[0] != ' ') {
842             rc = checkPackages(pkgcheck);
843         }
844
845         csa->cpioList = rpmfiFree(csa->cpioList);
846         csa->cpioFdIn = fdFree(csa->cpioFdIn, 
847                                RPMDBG_M("init (packageSources)"));
848         pkgcheck = _free(pkgcheck);
849         fn = _free(fn);
850     }
851     return rc;
852 }