Add support for global LDFLAGS
[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 <errno.h>
9 #include <netdb.h>
10 #include <time.h>
11
12 #include <rpm/rpmlib.h>                 /* RPMSIGTAG*, rpmReadPackageFile */
13 #include <rpm/rpmfileutil.h>
14 #include <rpm/rpmlog.h>
15
16 #include "rpmio/rpmio_internal.h"       /* fdInitDigest, fdFiniDigest */
17 #include "lib/fsm.h"
18 #include "lib/cpio.h"
19 #include "lib/signature.h"
20 #include "lib/rpmlead.h"
21 #include "build/rpmbuild_internal.h"
22 #include "build/rpmbuild_misc.h"
23
24 #include "debug.h"
25
26 typedef struct cpioSourceArchive_s {
27     rpm_loff_t  cpioArchiveSize;
28     rpmfi       cpioList;
29 } * CSA_t;
30
31 /**
32  * @todo Create transaction set *much* earlier.
33  */
34 static rpmRC cpio_doio(FD_t fdo, Header h, CSA_t csa, const char * fmodeMacro)
35 {
36     char *failedFile = NULL;
37     FD_t cfd;
38     int fsmrc;
39
40     (void) Fflush(fdo);
41     cfd = Fdopen(fdDup(Fileno(fdo)), fmodeMacro);
42     if (cfd == NULL)
43         return RPMRC_FAIL;
44
45     fsmrc = rpmPackageFilesArchive(csa->cpioList, headerIsSource(h), cfd,
46                       &csa->cpioArchiveSize, &failedFile);
47
48     if (fsmrc) {
49         if (failedFile)
50             rpmlog(RPMLOG_ERR, _("create archive failed on file %s: %s\n"),
51                    failedFile, rpmcpioStrerror(fsmrc));
52         else
53             rpmlog(RPMLOG_ERR, _("create archive failed: %s\n"),
54                    rpmcpioStrerror(fsmrc));
55     }
56
57     free(failedFile);
58     Fclose(cfd);
59
60     return (fsmrc == 0) ? RPMRC_OK : RPMRC_FAIL;
61 }
62
63 static rpmRC addFileToTag(rpmSpec spec, const char * file,
64                           Header h, rpmTagVal tag, int append)
65 {
66     StringBuf sb = NULL;
67     char buf[BUFSIZ];
68     char * fn;
69     FILE * f;
70     rpmRC rc = RPMRC_FAIL; /* assume failure */
71
72     /* no script file is not an error */
73     if (file == NULL)
74         return RPMRC_OK;
75
76     fn = rpmGetPath("%{_builddir}/%{?buildsubdir:%{buildsubdir}/}", file, NULL);
77
78     f = fopen(fn, "r");
79     if (f == NULL) {
80         rpmlog(RPMLOG_ERR,_("Could not open %s file: %s\n"),
81                            rpmTagGetName(tag), file);
82         goto exit;
83     }
84
85     sb = newStringBuf();
86     if (append) {
87         const char *s = headerGetString(h, tag);
88         if (s) {
89             appendLineStringBuf(sb, s);
90             headerDel(h, tag);
91         }
92     }
93
94     while (fgets(buf, sizeof(buf), f)) {
95         if (expandMacros(spec, spec->macros, buf, sizeof(buf))) {
96             rpmlog(RPMLOG_ERR, _("%s: line: %s\n"), fn, buf);
97             goto exit;
98         }
99         appendStringBuf(sb, buf);
100     }
101     headerPutString(h, tag, getStringBuf(sb));
102     rc = RPMRC_OK;
103
104 exit:
105     if (f) fclose(f);
106     free(fn);
107     freeStringBuf(sb);
108
109     return rc;
110 }
111
112 static rpm_time_t * getBuildTime(void)
113 {
114     static rpm_time_t buildTime[1];
115
116     if (buildTime[0] == 0)
117         buildTime[0] = (int32_t) time(NULL);
118     return buildTime;
119 }
120
121 static const char * buildHost(void)
122 {
123     static char hostname[1024];
124     static int oneshot = 0;
125     struct hostent *hbn;
126
127     if (! oneshot) {
128         (void) gethostname(hostname, sizeof(hostname));
129         hbn = gethostbyname(hostname);
130         if (hbn)
131             strcpy(hostname, hbn->h_name);
132         else
133             rpmlog(RPMLOG_WARNING,
134                         _("Could not canonicalize hostname: %s\n"), hostname);
135         oneshot = 1;
136     }
137     return(hostname);
138 }
139
140 static rpmRC processScriptFiles(rpmSpec spec, Package pkg)
141 {
142     struct TriggerFileEntry *p;
143     int addflags = 0;
144     rpmRC rc = RPMRC_FAIL;
145     Header h = pkg->header;
146     
147     if (addFileToTag(spec, pkg->preInFile, h, RPMTAG_PREIN, 1) ||
148         addFileToTag(spec, pkg->preUnFile, h, RPMTAG_PREUN, 1) ||
149         addFileToTag(spec, pkg->preTransFile, h, RPMTAG_PRETRANS, 1) ||
150         addFileToTag(spec, pkg->postInFile, h, RPMTAG_POSTIN, 1) ||
151         addFileToTag(spec, pkg->postUnFile, h, RPMTAG_POSTUN, 1) ||
152         addFileToTag(spec, pkg->postTransFile, h, RPMTAG_POSTTRANS, 1) ||
153         addFileToTag(spec, pkg->verifyFile, h, RPMTAG_VERIFYSCRIPT, 1))
154     {
155         goto exit;
156     }
157
158     /* if any trigger has flags, we need to add flags entry for all of them */
159     for (p = pkg->triggerFiles; p != NULL; p = p->next) {
160         if (p->flags) {
161             addflags = 1;
162             break;
163         }
164     }
165
166     for (p = pkg->triggerFiles; p != NULL; p = p->next) {
167         headerPutString(h, RPMTAG_TRIGGERSCRIPTPROG, p->prog);
168         if (addflags) {
169             headerPutUint32(h, RPMTAG_TRIGGERSCRIPTFLAGS, &p->flags, 1);
170         }
171
172         if (p->script) {
173             headerPutString(h, RPMTAG_TRIGGERSCRIPTS, p->script);
174         } else if (p->fileName) {
175             if (addFileToTag(spec, p->fileName, h, RPMTAG_TRIGGERSCRIPTS, 0)) {
176                 goto exit;
177             }
178         } else {
179             /* This is dumb.  When the header supports NULL string */
180             /* this will go away.                                  */
181             headerPutString(h, RPMTAG_TRIGGERSCRIPTS, "");
182         }
183     }
184     rc = RPMRC_OK;
185
186 exit:
187     return rc;
188 }
189
190 static rpmRC copyPayload(FD_t ifd, const char *ifn, FD_t ofd, const char *ofn)
191 {
192     char buf[BUFSIZ];
193     size_t nb;
194     rpmRC rc = RPMRC_OK;
195
196     while ((nb = Fread(buf, 1, sizeof(buf), ifd)) > 0) {
197         if (Fwrite(buf, sizeof(buf[0]), nb, ofd) != nb) {
198             rpmlog(RPMLOG_ERR, _("Unable to write payload to %s: %s\n"),
199                      ofn, Fstrerror(ofd));
200             rc = RPMRC_FAIL;
201             break;
202         }
203     }
204
205     if (nb < 0) {
206         rpmlog(RPMLOG_ERR, _("Unable to read payload from %s: %s\n"),
207                  ifn, Fstrerror(ifd));
208         rc = RPMRC_FAIL;
209     }
210
211     return rc;
212 }
213
214 static int depContainsTilde(Header h, rpmTagVal tagEVR)
215 {
216     struct rpmtd_s evrs;
217     const char *evr = NULL;
218
219     if (headerGet(h, tagEVR, &evrs, HEADERGET_MINMEM)) {
220         while ((evr = rpmtdNextString(&evrs)) != NULL)
221             if (strchr(evr, '~'))
222                 break;
223         rpmtdFreeData(&evrs);
224     }
225     return evr != NULL;
226 }
227
228 static rpmTagVal depevrtags[] = {
229     RPMTAG_PROVIDEVERSION,
230     RPMTAG_REQUIREVERSION,
231     RPMTAG_OBSOLETEVERSION,
232     RPMTAG_CONFLICTVERSION,
233     RPMTAG_ORDERVERSION,
234     RPMTAG_TRIGGERVERSION,
235     RPMTAG_SUGGESTSVERSION,
236     RPMTAG_ENHANCESVERSION,
237     0
238 };
239
240 static int haveTildeDep(Header h)
241 {
242     int i;
243
244     for (i = 0; depevrtags[i] != 0; i++)
245         if (depContainsTilde(h, depevrtags[i]))
246             return 1;
247     return 0;
248 }
249
250 static rpmRC writeRPM(Header *hdrp, unsigned char ** pkgidp, const char *fileName,
251              CSA_t csa, char **cookie)
252 {
253     FD_t fd = NULL;
254     FD_t ifd = NULL;
255     char * sigtarget = NULL;;
256     char * rpmio_flags = NULL;
257     char * SHA1 = NULL;
258     const char *s;
259     Header h;
260     Header sig = NULL;
261     int xx;
262     rpmRC rc = RPMRC_OK;
263     struct rpmtd_s td;
264     rpmTagVal sizetag;
265     rpmTagVal payloadtag;
266
267     /* Transfer header reference form *hdrp to h. */
268     h = headerLink(*hdrp);
269     *hdrp = headerFree(*hdrp);
270
271     if (pkgidp)
272         *pkgidp = NULL;
273
274     /* Save payload information */
275     if (headerIsSource(h))
276         rpmio_flags = rpmExpand("%{?_source_payload}", NULL);
277     else 
278         rpmio_flags = rpmExpand("%{?_binary_payload}", NULL);
279
280     /* If not configured or bogus, fall back to gz */
281     if (rpmio_flags[0] != 'w') {
282         free(rpmio_flags);
283         rpmio_flags = xstrdup("w9.gzdio");
284     }
285     s = strchr(rpmio_flags, '.');
286     if (s) {
287         char *buf = NULL;
288         const char *compr = NULL;
289         headerPutString(h, RPMTAG_PAYLOADFORMAT, "cpio");
290
291         if (rstreq(s+1, "ufdio")) {
292             compr = NULL;
293         } else if (rstreq(s+1, "gzdio")) {
294             compr = "gzip";
295 #if HAVE_BZLIB_H
296         } else if (rstreq(s+1, "bzdio")) {
297             compr = "bzip2";
298             /* Add prereq on rpm version that understands bzip2 payloads */
299             (void) rpmlibNeedsFeature(h, "PayloadIsBzip2", "3.0.5-1");
300 #endif
301 #if HAVE_LZMA_H
302         } else if (rstreq(s+1, "xzdio")) {
303             compr = "xz";
304             (void) rpmlibNeedsFeature(h, "PayloadIsXz", "5.2-1");
305         } else if (rstreq(s+1, "lzdio")) {
306             compr = "lzma";
307             (void) rpmlibNeedsFeature(h, "PayloadIsLzma", "4.4.6-1");
308 #endif
309         } else {
310             rpmlog(RPMLOG_ERR, _("Unknown payload compression: %s\n"),
311                    rpmio_flags);
312             rc = RPMRC_FAIL;
313             goto exit;
314         }
315
316         if (compr)
317             headerPutString(h, RPMTAG_PAYLOADCOMPRESSOR, compr);
318         buf = xstrdup(rpmio_flags);
319         buf[s - rpmio_flags] = '\0';
320         headerPutString(h, RPMTAG_PAYLOADFLAGS, buf+1);
321         free(buf);
322     }
323
324     /* check if the package has a dependency with a '~' */
325     if (haveTildeDep(h))
326         (void) rpmlibNeedsFeature(h, "TildeInVersions", "4.10.0-1");
327
328     /* Create and add the cookie */
329     if (cookie) {
330         rasprintf(cookie, "%s %d", buildHost(), (int) (*getBuildTime()));
331         headerPutString(h, RPMTAG_COOKIE, *cookie);
332     }
333     
334     /* Reallocate the header into one contiguous region. */
335     h = headerReload(h, RPMTAG_HEADERIMMUTABLE);
336     if (h == NULL) {    /* XXX can't happen */
337         rc = RPMRC_FAIL;
338         rpmlog(RPMLOG_ERR, _("Unable to create immutable header region.\n"));
339         goto exit;
340     }
341     /* Re-reference reallocated header. */
342     *hdrp = headerLink(h);
343
344     /*
345      * Write the header+archive into a temp file so that the size of
346      * archive (after compression) can be added to the header.
347      */
348     fd = rpmMkTempFile(NULL, &sigtarget);
349     if (fd == NULL || Ferror(fd)) {
350         rc = RPMRC_FAIL;
351         rpmlog(RPMLOG_ERR, _("Unable to open temp file.\n"));
352         goto exit;
353     }
354
355     fdInitDigest(fd, PGPHASHALGO_SHA1, 0);
356     if (headerWrite(fd, h, HEADER_MAGIC_YES)) {
357         rc = RPMRC_FAIL;
358         rpmlog(RPMLOG_ERR, _("Unable to write temp header\n"));
359     } else { /* Write the archive and get the size */
360         (void) Fflush(fd);
361         fdFiniDigest(fd, PGPHASHALGO_SHA1, (void **)&SHA1, NULL, 1);
362         if (csa->cpioList != NULL) {
363             rc = cpio_doio(fd, h, csa, rpmio_flags);
364         } else {
365             rc = RPMRC_FAIL;
366             rpmlog(RPMLOG_ERR, _("Bad CSA data\n"));
367         }
368     }
369
370     if (rc != RPMRC_OK)
371         goto exit;
372
373     (void) Fclose(fd);
374     fd = NULL;
375     (void) unlink(fileName);
376
377     /* Generate the signature */
378     (void) fflush(stdout);
379     sig = rpmNewSignature();
380
381     /*
382      * There should be rpmlib() dependency on this, but that doesn't
383      * really do much good as these are signature tags that get read
384      * way before dependency checking has a chance to figure out anything.
385      * On the positive side, not inserting the 32bit tag at all means
386      * older rpm will just bail out with error message on attempt to read
387      * such a package.
388      */
389     if (csa->cpioArchiveSize < UINT32_MAX) {
390         sizetag = RPMSIGTAG_SIZE;
391         payloadtag = RPMSIGTAG_PAYLOADSIZE;
392     } else {
393         sizetag = RPMSIGTAG_LONGSIZE;
394         payloadtag = RPMSIGTAG_LONGARCHIVESIZE;
395     }
396     (void) rpmGenDigest(sig, sigtarget, sizetag);
397     (void) rpmGenDigest(sig, sigtarget, RPMSIGTAG_MD5);
398
399     if (SHA1) {
400         /* XXX can't use rpmtdFromFoo() on RPMSIGTAG_* items */
401         rpmtdReset(&td);
402         td.tag = RPMSIGTAG_SHA1;
403         td.type = RPM_STRING_TYPE;
404         td.data = SHA1;
405         td.count = 1;
406         headerPut(sig, &td, HEADERPUT_DEFAULT);
407         SHA1 = _free(SHA1);
408     }
409
410     {   
411         /* XXX can't use headerPutType() on legacy RPMSIGTAG_* items */
412         rpmtdReset(&td);
413         td.tag = payloadtag;
414         td.count = 1;
415         if (payloadtag == RPMSIGTAG_PAYLOADSIZE) {
416             rpm_off_t asize = csa->cpioArchiveSize;
417             td.type = RPM_INT32_TYPE;
418             td.data = &asize;
419             headerPut(sig, &td, HEADERPUT_DEFAULT);
420         } else {
421             rpm_loff_t asize = csa->cpioArchiveSize;
422             td.type = RPM_INT64_TYPE;
423             td.data = &asize;
424             headerPut(sig, &td, HEADERPUT_DEFAULT);
425         }
426     }
427
428     /* Reallocate the signature into one contiguous region. */
429     sig = headerReload(sig, RPMTAG_HEADERSIGNATURES);
430     if (sig == NULL) {  /* XXX can't happen */
431         rc = RPMRC_FAIL;
432         rpmlog(RPMLOG_ERR, _("Unable to reload signature header.\n"));
433         goto exit;
434     }
435
436     /* Open the output file */
437     fd = Fopen(fileName, "w.ufdio");
438     if (fd == NULL || Ferror(fd)) {
439         rc = RPMRC_FAIL;
440         rpmlog(RPMLOG_ERR, _("Could not open %s: %s\n"),
441                 fileName, Fstrerror(fd));
442         goto exit;
443     }
444
445     /* Write the lead section into the package. */
446     {   
447         rpmlead lead = rpmLeadFromHeader(h);
448         rc = rpmLeadWrite(fd, lead);
449         rpmLeadFree(lead);
450         if (rc != RPMRC_OK) {
451             rc = RPMRC_FAIL;
452             rpmlog(RPMLOG_ERR, _("Unable to write package: %s\n"),
453                  Fstrerror(fd));
454             goto exit;
455         }
456     }
457
458     /* Write the signature section into the package. */
459     if (rpmWriteSignature(fd, sig)) {
460         rc = RPMRC_FAIL;
461         goto exit;
462     }
463
464     /* Append the header and archive */
465     ifd = Fopen(sigtarget, "r.ufdio");
466     if (ifd == NULL || Ferror(ifd)) {
467         rc = RPMRC_FAIL;
468         rpmlog(RPMLOG_ERR, _("Unable to open sigtarget %s: %s\n"),
469                 sigtarget, Fstrerror(ifd));
470         goto exit;
471     }
472
473     /* Add signatures to header, and write header into the package. */
474     /* XXX header+payload digests/signatures might be checked again here. */
475     {   Header nh = headerRead(ifd, HEADER_MAGIC_YES);
476
477         if (nh == NULL) {
478             rc = RPMRC_FAIL;
479             rpmlog(RPMLOG_ERR, _("Unable to read header from %s: %s\n"),
480                         sigtarget, Fstrerror(ifd));
481             goto exit;
482         }
483
484         xx = headerWrite(fd, nh, HEADER_MAGIC_YES);
485         headerFree(nh);
486
487         if (xx) {
488             rc = RPMRC_FAIL;
489             rpmlog(RPMLOG_ERR, _("Unable to write header to %s: %s\n"),
490                         fileName, Fstrerror(fd));
491             goto exit;
492         }
493     }
494         
495     /* Write the payload into the package. */
496     rc = copyPayload(ifd, fileName, fd, sigtarget);
497
498 exit:
499     free(rpmio_flags);
500     free(SHA1);
501     headerFree(h);
502
503     /* XXX Fish the pkgid out of the signature header. */
504     if (sig != NULL && pkgidp != NULL) {
505         struct rpmtd_s md5tag;
506         headerGet(sig, RPMSIGTAG_MD5, &md5tag, HEADERGET_DEFAULT);
507         if (rpmtdType(&md5tag) == RPM_BIN_TYPE &&
508                                 md5tag.count == 16 && md5tag.data != NULL) {
509             *pkgidp = md5tag.data;
510         }
511     }
512
513     rpmFreeSignature(sig);
514     Fclose(ifd);
515     Fclose(fd);
516
517     if (sigtarget) {
518         (void) unlink(sigtarget);
519         free(sigtarget);
520     }
521
522     if (rc == RPMRC_OK)
523         rpmlog(RPMLOG_NOTICE, _("Wrote: %s\n"), fileName);
524     else
525         (void) unlink(fileName);
526
527     return rc;
528 }
529
530 static const rpmTagVal copyTags[] = {
531     RPMTAG_CHANGELOGTIME,
532     RPMTAG_CHANGELOGNAME,
533     RPMTAG_CHANGELOGTEXT,
534     0
535 };
536
537 static rpmRC checkPackages(char *pkgcheck)
538 {
539     int fail = rpmExpandNumeric("%{?_nonzero_exit_pkgcheck_terminate_build}");
540     int xx;
541     
542     rpmlog(RPMLOG_NOTICE, _("Executing \"%s\":\n"), pkgcheck);
543     xx = system(pkgcheck);
544     if (WEXITSTATUS(xx) == -1 || WEXITSTATUS(xx) == 127) {
545         rpmlog(RPMLOG_ERR, _("Execution of \"%s\" failed.\n"), pkgcheck);
546         if (fail) return RPMRC_NOTFOUND;
547     }
548     if (WEXITSTATUS(xx) != 0) {
549         rpmlog(RPMLOG_ERR, _("Package check \"%s\" failed.\n"), pkgcheck);
550         if (fail) return RPMRC_FAIL;
551     }
552     
553     return RPMRC_OK;
554 }
555
556 static void trimChangelog(Header h)
557 {
558     static int oneshot;
559     static int cuttime, minnum, maxnum;
560     int * times;
561     char ** names = 0, ** texts = 0;
562     int i, keep, count = 0;
563
564     if (!oneshot) {
565         char *binarychangelogtrim = rpmExpand("%{?_binarychangelogtrim}", NULL);
566         oneshot = 1;
567         if (binarychangelogtrim && *binarychangelogtrim) {
568             maxnum = atoi(binarychangelogtrim);
569             binarychangelogtrim = strchr(binarychangelogtrim, ',');
570             if (binarychangelogtrim)
571               binarychangelogtrim++;
572         }
573         if (binarychangelogtrim && *binarychangelogtrim) {
574             cuttime = atoi(binarychangelogtrim);
575             binarychangelogtrim = strchr(binarychangelogtrim, ',');
576             if (binarychangelogtrim)
577               binarychangelogtrim++;
578         }
579         if (binarychangelogtrim && *binarychangelogtrim) {
580             minnum = atoi(binarychangelogtrim);
581             binarychangelogtrim = strchr(binarychangelogtrim, ',');
582         }
583     }
584     if (!cuttime && !minnum && !maxnum) {
585         return;
586     }
587     if (!headerGetEntry(h, RPMTAG_CHANGELOGTIME, NULL, (void **) &times, &count))
588         return;
589     if ((!cuttime || count <= minnum) && (!maxnum || count <= maxnum)) {
590         return;
591     }
592     keep = count;
593     if (maxnum && keep > maxnum)
594         keep = maxnum;
595     if (cuttime) {
596         for (i = 0; i < keep; i++) {
597             if (i >= minnum && times[i] < cuttime)
598                 break;
599         }
600         keep = i;
601     }
602     if (keep >= count)
603         return;
604     headerGetEntry(h, RPMTAG_CHANGELOGNAME, NULL, (void **) &names, &count);
605     headerGetEntry(h, RPMTAG_CHANGELOGTEXT, NULL, (void **) &texts, &count);
606     headerModifyEntry(h, RPMTAG_CHANGELOGTIME, RPM_INT32_TYPE, times, keep);
607     headerModifyEntry(h, RPMTAG_CHANGELOGNAME, RPM_STRING_ARRAY_TYPE, names, keep);
608     headerModifyEntry(h, RPMTAG_CHANGELOGTEXT, RPM_STRING_ARRAY_TYPE, texts, keep);
609     free(names);
610     free(texts);
611 }
612
613 rpmRC packageBinaries(rpmSpec spec, const char *cookie, int cheating)
614 {
615     struct cpioSourceArchive_s csabuf;
616     CSA_t csa = &csabuf;
617     rpmRC rc;
618     const char *errorString;
619     Package pkg;
620     char *pkglist = NULL;
621
622     trimChangelog(spec->packages->header);
623     for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
624         char *fn;
625
626         if (pkg->fileList == NULL)
627             continue;
628
629         if ((rc = processScriptFiles(spec, pkg)))
630             return rc;
631         
632         if (cookie) {
633             headerPutString(pkg->header, RPMTAG_COOKIE, cookie);
634         }
635
636         /* Copy changelog from src rpm */
637         headerCopyTags(spec->packages->header, pkg->header, copyTags);
638         
639         headerPutString(pkg->header, RPMTAG_RPMVERSION, VERSION);
640         headerPutString(pkg->header, RPMTAG_BUILDHOST, buildHost());
641         headerPutUint32(pkg->header, RPMTAG_BUILDTIME, getBuildTime(), 1);
642
643         if (spec->sourcePkgId != NULL) {
644             headerPutBin(pkg->header, RPMTAG_SOURCEPKGID, spec->sourcePkgId,16);
645         }
646
647         if (cheating) {
648             (void) rpmlibNeedsFeature(pkg->header, "ShortCircuited", "4.9.0-1");
649         }
650         
651         {   char *binFormat = rpmGetPath("%{_rpmfilename}", NULL);
652             char *binRpm, *binDir;
653             binRpm = headerFormat(pkg->header, binFormat, &errorString);
654             free(binFormat);
655             if (binRpm == NULL) {
656                 rpmlog(RPMLOG_ERR, _("Could not generate output "
657                      "filename for package %s: %s\n"), 
658                      headerGetString(pkg->header, RPMTAG_NAME), errorString);
659                 return RPMRC_FAIL;
660             }
661             fn = rpmGetPath("%{_rpmdir}/", binRpm, NULL);
662             if ((binDir = strchr(binRpm, '/')) != NULL) {
663                 struct stat st;
664                 char *dn;
665                 *binDir = '\0';
666                 dn = rpmGetPath("%{_rpmdir}/", binRpm, NULL);
667                 if (stat(dn, &st) < 0) {
668                     switch(errno) {
669                     case  ENOENT:
670                         if (mkdir(dn, 0755) == 0)
671                             break;
672                     default:
673                         rpmlog(RPMLOG_ERR,_("cannot create %s: %s\n"),
674                             dn, strerror(errno));
675                         break;
676                     }
677                 }
678                 free(dn);
679             }
680             free(binRpm);
681         }
682
683         memset(csa, 0, sizeof(*csa));
684         csa->cpioArchiveSize = 0;
685         csa->cpioList = rpmfiLink(pkg->cpioList);
686
687         rc = writeRPM(&pkg->header, NULL, fn, csa, NULL);
688         csa->cpioList = rpmfiFree(csa->cpioList);
689         if (rc == RPMRC_OK) {
690             /* Do check each written package if enabled */
691             char *pkgcheck = rpmExpand("%{?_build_pkgcheck} ", fn, NULL);
692             if (pkgcheck[0] != ' ') {
693                 rc = checkPackages(pkgcheck);
694             }
695             free(pkgcheck);
696             rstrcat(&pkglist, fn);
697             rstrcat(&pkglist, " ");
698         }
699         free(fn);
700         if (rc != RPMRC_OK) {
701             pkglist = _free(pkglist);
702             return rc;
703         }
704     }
705
706     /* Now check the package set if enabled */
707     if (pkglist != NULL) {
708         char *pkgcheck_set = rpmExpand("%{?_build_pkgcheck_set} ", pkglist,  NULL);
709         if (pkgcheck_set[0] != ' ') {   /* run only if _build_pkgcheck_set is defined */
710             checkPackages(pkgcheck_set);
711         }
712         free(pkgcheck_set);
713         pkglist = _free(pkglist);
714     }
715     
716     return RPMRC_OK;
717 }
718
719 rpmRC packageSources(rpmSpec spec, char **cookie)
720 {
721     struct cpioSourceArchive_s csabuf;
722     CSA_t csa = &csabuf;
723     rpmRC rc;
724
725     /* Add some cruft */
726     headerPutString(spec->sourceHeader, RPMTAG_RPMVERSION, VERSION);
727     headerPutString(spec->sourceHeader, RPMTAG_BUILDHOST, buildHost());
728     headerPutUint32(spec->sourceHeader, RPMTAG_BUILDTIME, getBuildTime(), 1);
729
730     /* XXX this should be %_srpmdir */
731     {   char *fn = rpmGetPath("%{_srcrpmdir}/", spec->sourceRpmName,NULL);
732         char *pkgcheck = rpmExpand("%{?_build_pkgcheck_srpm} ", fn, NULL);
733
734         memset(csa, 0, sizeof(*csa));
735         csa->cpioArchiveSize = 0;
736         csa->cpioList = rpmfiLink(spec->sourceCpioList); 
737
738         spec->sourcePkgId = NULL;
739         rc = writeRPM(&spec->sourceHeader, &spec->sourcePkgId, fn, csa, cookie);
740
741         /* Do check SRPM package if enabled */
742         if (rc == RPMRC_OK && pkgcheck[0] != ' ') {
743             rc = checkPackages(pkgcheck);
744         }
745
746         rpmfiFree(csa->cpioList);
747         free(pkgcheck);
748         free(fn);
749     }
750     return rc;
751 }