b6c808e0992120b42b8fc63aada38f56cf9bc6c2
[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     /*
335      * Add system-wide Tizen build information
336      */
337     char *buildinfo = rpmExpand("%{?_buildinfo}", NULL);
338     if (buildinfo && *buildinfo) {
339       int err;
340       int count = 0;
341       char **strings = NULL;
342
343       if ((err = poptParseArgvString(buildinfo, &count, &strings))) {
344         rpmlog(RPMLOG_ERR, _("Can't parse BUILDINFO tag: %s\n"), poptStrerror(xx));
345         goto exit;
346       }
347
348       if (count)
349         headerPutStringArray(h, RPMTAG_BUILDINFO, strings, count);
350
351       strings = _free(strings);
352     }
353     free(buildinfo);
354
355     /* Reallocate the header into one contiguous region. */
356     h = headerReload(h, RPMTAG_HEADERIMMUTABLE);
357     if (h == NULL) {    /* XXX can't happen */
358         rc = RPMRC_FAIL;
359         rpmlog(RPMLOG_ERR, _("Unable to create immutable header region.\n"));
360         goto exit;
361     }
362     /* Re-reference reallocated header. */
363     *hdrp = headerLink(h);
364
365     /*
366      * Write the header+archive into a temp file so that the size of
367      * archive (after compression) can be added to the header.
368      */
369     fd = rpmMkTempFile(NULL, &sigtarget);
370     if (fd == NULL || Ferror(fd)) {
371         rc = RPMRC_FAIL;
372         rpmlog(RPMLOG_ERR, _("Unable to open temp file.\n"));
373         goto exit;
374     }
375
376     fdInitDigest(fd, PGPHASHALGO_SHA1, 0);
377     if (headerWrite(fd, h, HEADER_MAGIC_YES)) {
378         rc = RPMRC_FAIL;
379         rpmlog(RPMLOG_ERR, _("Unable to write temp header\n"));
380     } else { /* Write the archive and get the size */
381         (void) Fflush(fd);
382         fdFiniDigest(fd, PGPHASHALGO_SHA1, (void **)&SHA1, NULL, 1);
383         if (csa->cpioList != NULL) {
384             rc = cpio_doio(fd, h, csa, rpmio_flags);
385         } else {
386             rc = RPMRC_FAIL;
387             rpmlog(RPMLOG_ERR, _("Bad CSA data\n"));
388         }
389     }
390
391     if (rc != RPMRC_OK)
392         goto exit;
393
394     (void) Fclose(fd);
395     fd = NULL;
396     (void) unlink(fileName);
397
398     /* Generate the signature */
399     (void) fflush(stdout);
400     sig = rpmNewSignature();
401
402     /*
403      * There should be rpmlib() dependency on this, but that doesn't
404      * really do much good as these are signature tags that get read
405      * way before dependency checking has a chance to figure out anything.
406      * On the positive side, not inserting the 32bit tag at all means
407      * older rpm will just bail out with error message on attempt to read
408      * such a package.
409      */
410     if (csa->cpioArchiveSize < UINT32_MAX) {
411         sizetag = RPMSIGTAG_SIZE;
412         payloadtag = RPMSIGTAG_PAYLOADSIZE;
413     } else {
414         sizetag = RPMSIGTAG_LONGSIZE;
415         payloadtag = RPMSIGTAG_LONGARCHIVESIZE;
416     }
417     (void) rpmGenDigest(sig, sigtarget, sizetag);
418     (void) rpmGenDigest(sig, sigtarget, RPMSIGTAG_MD5);
419
420     if (SHA1) {
421         /* XXX can't use rpmtdFromFoo() on RPMSIGTAG_* items */
422         rpmtdReset(&td);
423         td.tag = RPMSIGTAG_SHA1;
424         td.type = RPM_STRING_TYPE;
425         td.data = SHA1;
426         td.count = 1;
427         headerPut(sig, &td, HEADERPUT_DEFAULT);
428         SHA1 = _free(SHA1);
429     }
430
431     {   
432         /* XXX can't use headerPutType() on legacy RPMSIGTAG_* items */
433         rpmtdReset(&td);
434         td.tag = payloadtag;
435         td.count = 1;
436         if (payloadtag == RPMSIGTAG_PAYLOADSIZE) {
437             rpm_off_t asize = csa->cpioArchiveSize;
438             td.type = RPM_INT32_TYPE;
439             td.data = &asize;
440             headerPut(sig, &td, HEADERPUT_DEFAULT);
441         } else {
442             rpm_loff_t asize = csa->cpioArchiveSize;
443             td.type = RPM_INT64_TYPE;
444             td.data = &asize;
445             headerPut(sig, &td, HEADERPUT_DEFAULT);
446         }
447     }
448
449     /* Reallocate the signature into one contiguous region. */
450     sig = headerReload(sig, RPMTAG_HEADERSIGNATURES);
451     if (sig == NULL) {  /* XXX can't happen */
452         rc = RPMRC_FAIL;
453         rpmlog(RPMLOG_ERR, _("Unable to reload signature header.\n"));
454         goto exit;
455     }
456
457     /* Open the output file */
458     fd = Fopen(fileName, "w.ufdio");
459     if (fd == NULL || Ferror(fd)) {
460         rc = RPMRC_FAIL;
461         rpmlog(RPMLOG_ERR, _("Could not open %s: %s\n"),
462                 fileName, Fstrerror(fd));
463         goto exit;
464     }
465
466     /* Write the lead section into the package. */
467     {   
468         rpmlead lead = rpmLeadFromHeader(h);
469         rc = rpmLeadWrite(fd, lead);
470         rpmLeadFree(lead);
471         if (rc != RPMRC_OK) {
472             rc = RPMRC_FAIL;
473             rpmlog(RPMLOG_ERR, _("Unable to write package: %s\n"),
474                  Fstrerror(fd));
475             goto exit;
476         }
477     }
478
479     /* Write the signature section into the package. */
480     if (rpmWriteSignature(fd, sig)) {
481         rc = RPMRC_FAIL;
482         goto exit;
483     }
484
485     /* Append the header and archive */
486     ifd = Fopen(sigtarget, "r.ufdio");
487     if (ifd == NULL || Ferror(ifd)) {
488         rc = RPMRC_FAIL;
489         rpmlog(RPMLOG_ERR, _("Unable to open sigtarget %s: %s\n"),
490                 sigtarget, Fstrerror(ifd));
491         goto exit;
492     }
493
494     /* Add signatures to header, and write header into the package. */
495     /* XXX header+payload digests/signatures might be checked again here. */
496     {   Header nh = headerRead(ifd, HEADER_MAGIC_YES);
497
498         if (nh == NULL) {
499             rc = RPMRC_FAIL;
500             rpmlog(RPMLOG_ERR, _("Unable to read header from %s: %s\n"),
501                         sigtarget, Fstrerror(ifd));
502             goto exit;
503         }
504
505         xx = headerWrite(fd, nh, HEADER_MAGIC_YES);
506         headerFree(nh);
507
508         if (xx) {
509             rc = RPMRC_FAIL;
510             rpmlog(RPMLOG_ERR, _("Unable to write header to %s: %s\n"),
511                         fileName, Fstrerror(fd));
512             goto exit;
513         }
514     }
515         
516     /* Write the payload into the package. */
517     rc = copyPayload(ifd, fileName, fd, sigtarget);
518
519 exit:
520     free(rpmio_flags);
521     free(SHA1);
522     headerFree(h);
523
524     /* XXX Fish the pkgid out of the signature header. */
525     if (sig != NULL && pkgidp != NULL) {
526         struct rpmtd_s md5tag;
527         headerGet(sig, RPMSIGTAG_MD5, &md5tag, HEADERGET_DEFAULT);
528         if (rpmtdType(&md5tag) == RPM_BIN_TYPE &&
529                                 md5tag.count == 16 && md5tag.data != NULL) {
530             *pkgidp = md5tag.data;
531         }
532     }
533
534     rpmFreeSignature(sig);
535     Fclose(ifd);
536     Fclose(fd);
537
538     if (sigtarget) {
539         (void) unlink(sigtarget);
540         free(sigtarget);
541     }
542
543     if (rc == RPMRC_OK)
544         rpmlog(RPMLOG_NOTICE, _("Wrote: %s\n"), fileName);
545     else
546         (void) unlink(fileName);
547
548     return rc;
549 }
550
551 static const rpmTagVal copyTags[] = {
552     RPMTAG_CHANGELOGTIME,
553     RPMTAG_CHANGELOGNAME,
554     RPMTAG_CHANGELOGTEXT,
555     0
556 };
557
558 static rpmRC checkPackages(char *pkgcheck)
559 {
560     int fail = rpmExpandNumeric("%{?_nonzero_exit_pkgcheck_terminate_build}");
561     int xx;
562     
563     rpmlog(RPMLOG_NOTICE, _("Executing \"%s\":\n"), pkgcheck);
564     xx = system(pkgcheck);
565     if (WEXITSTATUS(xx) == -1 || WEXITSTATUS(xx) == 127) {
566         rpmlog(RPMLOG_ERR, _("Execution of \"%s\" failed.\n"), pkgcheck);
567         if (fail) return RPMRC_NOTFOUND;
568     }
569     if (WEXITSTATUS(xx) != 0) {
570         rpmlog(RPMLOG_ERR, _("Package check \"%s\" failed.\n"), pkgcheck);
571         if (fail) return RPMRC_FAIL;
572     }
573     
574     return RPMRC_OK;
575 }
576
577 static void trimChangelog(Header h)
578 {
579     static int oneshot;
580     static int cuttime, minnum, maxnum;
581     int * times;
582     char ** names = 0, ** texts = 0;
583     int i, keep, count = 0;
584
585     if (!oneshot) {
586         char *binarychangelogtrim = rpmExpand("%{?_binarychangelogtrim}", NULL);
587         oneshot = 1;
588         if (binarychangelogtrim && *binarychangelogtrim) {
589             maxnum = atoi(binarychangelogtrim);
590             binarychangelogtrim = strchr(binarychangelogtrim, ',');
591             if (binarychangelogtrim)
592               binarychangelogtrim++;
593         }
594         if (binarychangelogtrim && *binarychangelogtrim) {
595             cuttime = atoi(binarychangelogtrim);
596             binarychangelogtrim = strchr(binarychangelogtrim, ',');
597             if (binarychangelogtrim)
598               binarychangelogtrim++;
599         }
600         if (binarychangelogtrim && *binarychangelogtrim) {
601             minnum = atoi(binarychangelogtrim);
602             binarychangelogtrim = strchr(binarychangelogtrim, ',');
603         }
604     }
605     if (!cuttime && !minnum && !maxnum) {
606         return;
607     }
608     if (!headerGetEntry(h, RPMTAG_CHANGELOGTIME, NULL, (void **) &times, &count))
609         return;
610     if ((!cuttime || count <= minnum) && (!maxnum || count <= maxnum)) {
611         return;
612     }
613     keep = count;
614     if (maxnum && keep > maxnum)
615         keep = maxnum;
616     if (cuttime) {
617         for (i = 0; i < keep; i++) {
618             if (i >= minnum && times[i] < cuttime)
619                 break;
620         }
621         keep = i;
622     }
623     if (keep >= count)
624         return;
625     headerGetEntry(h, RPMTAG_CHANGELOGNAME, NULL, (void **) &names, &count);
626     headerGetEntry(h, RPMTAG_CHANGELOGTEXT, NULL, (void **) &texts, &count);
627     headerModifyEntry(h, RPMTAG_CHANGELOGTIME, RPM_INT32_TYPE, times, keep);
628     headerModifyEntry(h, RPMTAG_CHANGELOGNAME, RPM_STRING_ARRAY_TYPE, names, keep);
629     headerModifyEntry(h, RPMTAG_CHANGELOGTEXT, RPM_STRING_ARRAY_TYPE, texts, keep);
630     free(names);
631     free(texts);
632 }
633
634 rpmRC packageBinaries(rpmSpec spec, const char *cookie, int cheating)
635 {
636     struct cpioSourceArchive_s csabuf;
637     CSA_t csa = &csabuf;
638     rpmRC rc;
639     const char *errorString;
640     Package pkg;
641     char *pkglist = NULL;
642
643     trimChangelog(spec->packages->header);
644     for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
645         char *fn;
646
647         if (pkg->fileList == NULL)
648             continue;
649
650         if ((rc = processScriptFiles(spec, pkg)))
651             return rc;
652         
653         if (cookie) {
654             headerPutString(pkg->header, RPMTAG_COOKIE, cookie);
655         }
656
657         /* Copy changelog from src rpm */
658         headerCopyTags(spec->packages->header, pkg->header, copyTags);
659         
660         headerPutString(pkg->header, RPMTAG_RPMVERSION, VERSION);
661         headerPutString(pkg->header, RPMTAG_BUILDHOST, buildHost());
662         headerPutUint32(pkg->header, RPMTAG_BUILDTIME, getBuildTime(), 1);
663
664         if (spec->sourcePkgId != NULL) {
665             headerPutBin(pkg->header, RPMTAG_SOURCEPKGID, spec->sourcePkgId,16);
666         }
667
668         if (cheating) {
669             (void) rpmlibNeedsFeature(pkg->header, "ShortCircuited", "4.9.0-1");
670         }
671         
672         {   char *binFormat = rpmGetPath("%{_rpmfilename}", NULL);
673             char *binRpm, *binDir;
674             binRpm = headerFormat(pkg->header, binFormat, &errorString);
675             free(binFormat);
676             if (binRpm == NULL) {
677                 rpmlog(RPMLOG_ERR, _("Could not generate output "
678                      "filename for package %s: %s\n"), 
679                      headerGetString(pkg->header, RPMTAG_NAME), errorString);
680                 return RPMRC_FAIL;
681             }
682             fn = rpmGetPath("%{_rpmdir}/", binRpm, NULL);
683             if ((binDir = strchr(binRpm, '/')) != NULL) {
684                 struct stat st;
685                 char *dn;
686                 *binDir = '\0';
687                 dn = rpmGetPath("%{_rpmdir}/", binRpm, NULL);
688                 if (stat(dn, &st) < 0) {
689                     switch(errno) {
690                     case  ENOENT:
691                         if (mkdir(dn, 0755) == 0)
692                             break;
693                     default:
694                         rpmlog(RPMLOG_ERR,_("cannot create %s: %s\n"),
695                             dn, strerror(errno));
696                         break;
697                     }
698                 }
699                 free(dn);
700             }
701             free(binRpm);
702         }
703
704         memset(csa, 0, sizeof(*csa));
705         csa->cpioArchiveSize = 0;
706         csa->cpioList = rpmfiLink(pkg->cpioList);
707
708         rc = writeRPM(&pkg->header, NULL, fn, csa, NULL);
709         csa->cpioList = rpmfiFree(csa->cpioList);
710         if (rc == RPMRC_OK) {
711             /* Do check each written package if enabled */
712             char *pkgcheck = rpmExpand("%{?_build_pkgcheck} ", fn, NULL);
713             if (pkgcheck[0] != ' ') {
714                 rc = checkPackages(pkgcheck);
715             }
716             free(pkgcheck);
717             rstrcat(&pkglist, fn);
718             rstrcat(&pkglist, " ");
719         }
720         free(fn);
721         if (rc != RPMRC_OK) {
722             pkglist = _free(pkglist);
723             return rc;
724         }
725     }
726
727     /* Now check the package set if enabled */
728     if (pkglist != NULL) {
729         char *pkgcheck_set = rpmExpand("%{?_build_pkgcheck_set} ", pkglist,  NULL);
730         if (pkgcheck_set[0] != ' ') {   /* run only if _build_pkgcheck_set is defined */
731             checkPackages(pkgcheck_set);
732         }
733         free(pkgcheck_set);
734         pkglist = _free(pkglist);
735     }
736     
737     return RPMRC_OK;
738 }
739
740 rpmRC packageSources(rpmSpec spec, char **cookie)
741 {
742     struct cpioSourceArchive_s csabuf;
743     CSA_t csa = &csabuf;
744     rpmRC rc;
745
746     /* Add some cruft */
747     headerPutString(spec->sourceHeader, RPMTAG_RPMVERSION, VERSION);
748     headerPutString(spec->sourceHeader, RPMTAG_BUILDHOST, buildHost());
749     headerPutUint32(spec->sourceHeader, RPMTAG_BUILDTIME, getBuildTime(), 1);
750
751     /* XXX this should be %_srpmdir */
752     {   char *fn = rpmGetPath("%{_srcrpmdir}/", spec->sourceRpmName,NULL);
753         char *pkgcheck = rpmExpand("%{?_build_pkgcheck_srpm} ", fn, NULL);
754
755         memset(csa, 0, sizeof(*csa));
756         csa->cpioArchiveSize = 0;
757         csa->cpioList = rpmfiLink(spec->sourceCpioList); 
758
759         spec->sourcePkgId = NULL;
760         rc = writeRPM(&spec->sourceHeader, &spec->sourcePkgId, fn, csa, cookie);
761
762         /* Do check SRPM package if enabled */
763         if (rc == RPMRC_OK && pkgcheck[0] != ' ') {
764             rc = checkPackages(pkgcheck);
765         }
766
767         rpmfiFree(csa->cpioList);
768         free(pkgcheck);
769         free(fn);
770     }
771     return rc;
772 }