3 * Assemble components of an RPM package.
12 #include <rpm/rpmlib.h> /* RPMSIGTAG*, rpmReadPackageFile */
13 #include <rpm/rpmfileutil.h>
14 #include <rpm/rpmlog.h>
16 #include "rpmio/rpmio_internal.h" /* fdInitDigest, fdFiniDigest */
19 #include "lib/signature.h"
20 #include "lib/rpmlead.h"
21 #include "build/rpmbuild_internal.h"
22 #include "build/rpmbuild_misc.h"
26 typedef struct cpioSourceArchive_s {
27 rpm_loff_t cpioArchiveSize;
32 * @todo Create transaction set *much* earlier.
34 static rpmRC cpio_doio(FD_t fdo, Header h, CSA_t csa, const char * fmodeMacro)
36 char *failedFile = NULL;
41 cfd = Fdopen(fdDup(Fileno(fdo)), fmodeMacro);
45 fsmrc = rpmPackageFilesArchive(csa->cpioList, headerIsSource(h), cfd,
46 &csa->cpioArchiveSize, &failedFile);
50 rpmlog(RPMLOG_ERR, _("create archive failed on file %s: %s\n"),
51 failedFile, rpmcpioStrerror(fsmrc));
53 rpmlog(RPMLOG_ERR, _("create archive failed: %s\n"),
54 rpmcpioStrerror(fsmrc));
60 return (fsmrc == 0) ? RPMRC_OK : RPMRC_FAIL;
63 static rpmRC addFileToTag(rpmSpec spec, const char * file,
64 Header h, rpmTagVal tag, int append)
70 rpmRC rc = RPMRC_FAIL; /* assume failure */
72 /* no script file is not an error */
76 fn = rpmGetPath("%{_builddir}/%{?buildsubdir:%{buildsubdir}/}", file, NULL);
80 rpmlog(RPMLOG_ERR,_("Could not open %s file: %s\n"),
81 rpmTagGetName(tag), file);
87 const char *s = headerGetString(h, tag);
89 appendLineStringBuf(sb, s);
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);
99 appendStringBuf(sb, buf);
101 headerPutString(h, tag, getStringBuf(sb));
112 static rpm_time_t * getBuildTime(void)
114 static rpm_time_t buildTime[1];
116 if (buildTime[0] == 0)
117 buildTime[0] = (int32_t) time(NULL);
121 static const char * buildHost(void)
123 static char hostname[1024];
124 static int oneshot = 0;
128 (void) gethostname(hostname, sizeof(hostname));
129 hbn = gethostbyname(hostname);
131 strcpy(hostname, hbn->h_name);
133 rpmlog(RPMLOG_WARNING,
134 _("Could not canonicalize hostname: %s\n"), hostname);
140 static rpmRC processScriptFiles(rpmSpec spec, Package pkg)
142 struct TriggerFileEntry *p;
144 rpmRC rc = RPMRC_FAIL;
145 Header h = pkg->header;
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))
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) {
166 for (p = pkg->triggerFiles; p != NULL; p = p->next) {
167 headerPutString(h, RPMTAG_TRIGGERSCRIPTPROG, p->prog);
169 headerPutUint32(h, RPMTAG_TRIGGERSCRIPTFLAGS, &p->flags, 1);
173 headerPutString(h, RPMTAG_TRIGGERSCRIPTS, p->script);
174 } else if (p->fileName) {
175 if (addFileToTag(spec, p->fileName, h, RPMTAG_TRIGGERSCRIPTS, 0)) {
179 /* This is dumb. When the header supports NULL string */
180 /* this will go away. */
181 headerPutString(h, RPMTAG_TRIGGERSCRIPTS, "");
190 static rpmRC copyPayload(FD_t ifd, const char *ifn, FD_t ofd, const char *ofn)
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));
206 rpmlog(RPMLOG_ERR, _("Unable to read payload from %s: %s\n"),
207 ifn, Fstrerror(ifd));
214 static int depContainsTilde(Header h, rpmTagVal tagEVR)
217 const char *evr = NULL;
219 if (headerGet(h, tagEVR, &evrs, HEADERGET_MINMEM)) {
220 while ((evr = rpmtdNextString(&evrs)) != NULL)
221 if (strchr(evr, '~'))
223 rpmtdFreeData(&evrs);
228 static rpmTagVal depevrtags[] = {
229 RPMTAG_PROVIDEVERSION,
230 RPMTAG_REQUIREVERSION,
231 RPMTAG_OBSOLETEVERSION,
232 RPMTAG_CONFLICTVERSION,
234 RPMTAG_TRIGGERVERSION,
235 RPMTAG_SUGGESTSVERSION,
236 RPMTAG_ENHANCESVERSION,
240 static int haveTildeDep(Header h)
244 for (i = 0; depevrtags[i] != 0; i++)
245 if (depContainsTilde(h, depevrtags[i]))
250 static rpmRC writeRPM(Header *hdrp, unsigned char ** pkgidp, const char *fileName,
251 CSA_t csa, char **cookie)
255 char * sigtarget = NULL;;
256 char * rpmio_flags = NULL;
265 rpmTagVal payloadtag;
267 /* Transfer header reference form *hdrp to h. */
268 h = headerLink(*hdrp);
269 *hdrp = headerFree(*hdrp);
274 /* Save payload information */
275 if (headerIsSource(h))
276 rpmio_flags = rpmExpand("%{?_source_payload}", NULL);
278 rpmio_flags = rpmExpand("%{?_binary_payload}", NULL);
280 /* If not configured or bogus, fall back to gz */
281 if (rpmio_flags[0] != 'w') {
283 rpmio_flags = xstrdup("w9.gzdio");
285 s = strchr(rpmio_flags, '.');
288 const char *compr = NULL;
289 headerPutString(h, RPMTAG_PAYLOADFORMAT, "cpio");
291 if (rstreq(s+1, "ufdio")) {
293 } else if (rstreq(s+1, "gzdio")) {
296 } else if (rstreq(s+1, "bzdio")) {
298 /* Add prereq on rpm version that understands bzip2 payloads */
299 (void) rpmlibNeedsFeature(h, "PayloadIsBzip2", "3.0.5-1");
302 } else if (rstreq(s+1, "xzdio")) {
304 (void) rpmlibNeedsFeature(h, "PayloadIsXz", "5.2-1");
305 } else if (rstreq(s+1, "lzdio")) {
307 (void) rpmlibNeedsFeature(h, "PayloadIsLzma", "4.4.6-1");
310 rpmlog(RPMLOG_ERR, _("Unknown payload compression: %s\n"),
317 headerPutString(h, RPMTAG_PAYLOADCOMPRESSOR, compr);
318 buf = xstrdup(rpmio_flags);
319 buf[s - rpmio_flags] = '\0';
320 headerPutString(h, RPMTAG_PAYLOADFLAGS, buf+1);
324 /* check if the package has a dependency with a '~' */
326 (void) rpmlibNeedsFeature(h, "TildeInVersions", "4.10.0-1");
328 /* Create and add the cookie */
330 rasprintf(cookie, "%s %d", buildHost(), (int) (*getBuildTime()));
331 headerPutString(h, RPMTAG_COOKIE, *cookie);
334 /* Reallocate the header into one contiguous region. */
335 h = headerReload(h, RPMTAG_HEADERIMMUTABLE);
336 if (h == NULL) { /* XXX can't happen */
338 rpmlog(RPMLOG_ERR, _("Unable to create immutable header region.\n"));
341 /* Re-reference reallocated header. */
342 *hdrp = headerLink(h);
345 * Write the header+archive into a temp file so that the size of
346 * archive (after compression) can be added to the header.
348 fd = rpmMkTempFile(NULL, &sigtarget);
349 if (fd == NULL || Ferror(fd)) {
351 rpmlog(RPMLOG_ERR, _("Unable to open temp file.\n"));
355 fdInitDigest(fd, PGPHASHALGO_SHA1, 0);
356 if (headerWrite(fd, h, HEADER_MAGIC_YES)) {
358 rpmlog(RPMLOG_ERR, _("Unable to write temp header\n"));
359 } else { /* Write the archive and get the size */
361 fdFiniDigest(fd, PGPHASHALGO_SHA1, (void **)&SHA1, NULL, 1);
362 if (csa->cpioList != NULL) {
363 rc = cpio_doio(fd, h, csa, rpmio_flags);
366 rpmlog(RPMLOG_ERR, _("Bad CSA data\n"));
375 (void) unlink(fileName);
377 /* Generate the signature */
378 (void) fflush(stdout);
379 sig = rpmNewSignature();
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
389 if (csa->cpioArchiveSize < UINT32_MAX) {
390 sizetag = RPMSIGTAG_SIZE;
391 payloadtag = RPMSIGTAG_PAYLOADSIZE;
393 sizetag = RPMSIGTAG_LONGSIZE;
394 payloadtag = RPMSIGTAG_LONGARCHIVESIZE;
396 (void) rpmGenDigest(sig, sigtarget, sizetag);
397 (void) rpmGenDigest(sig, sigtarget, RPMSIGTAG_MD5);
400 /* XXX can't use rpmtdFromFoo() on RPMSIGTAG_* items */
402 td.tag = RPMSIGTAG_SHA1;
403 td.type = RPM_STRING_TYPE;
406 headerPut(sig, &td, HEADERPUT_DEFAULT);
411 /* XXX can't use headerPutType() on legacy RPMSIGTAG_* items */
415 if (payloadtag == RPMSIGTAG_PAYLOADSIZE) {
416 rpm_off_t asize = csa->cpioArchiveSize;
417 td.type = RPM_INT32_TYPE;
419 headerPut(sig, &td, HEADERPUT_DEFAULT);
421 rpm_loff_t asize = csa->cpioArchiveSize;
422 td.type = RPM_INT64_TYPE;
424 headerPut(sig, &td, HEADERPUT_DEFAULT);
428 /* Reallocate the signature into one contiguous region. */
429 sig = headerReload(sig, RPMTAG_HEADERSIGNATURES);
430 if (sig == NULL) { /* XXX can't happen */
432 rpmlog(RPMLOG_ERR, _("Unable to reload signature header.\n"));
436 /* Open the output file */
437 fd = Fopen(fileName, "w.ufdio");
438 if (fd == NULL || Ferror(fd)) {
440 rpmlog(RPMLOG_ERR, _("Could not open %s: %s\n"),
441 fileName, Fstrerror(fd));
445 /* Write the lead section into the package. */
447 rpmlead lead = rpmLeadFromHeader(h);
448 rc = rpmLeadWrite(fd, lead);
450 if (rc != RPMRC_OK) {
452 rpmlog(RPMLOG_ERR, _("Unable to write package: %s\n"),
458 /* Write the signature section into the package. */
459 if (rpmWriteSignature(fd, sig)) {
464 /* Append the header and archive */
465 ifd = Fopen(sigtarget, "r.ufdio");
466 if (ifd == NULL || Ferror(ifd)) {
468 rpmlog(RPMLOG_ERR, _("Unable to open sigtarget %s: %s\n"),
469 sigtarget, Fstrerror(ifd));
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);
479 rpmlog(RPMLOG_ERR, _("Unable to read header from %s: %s\n"),
480 sigtarget, Fstrerror(ifd));
484 xx = headerWrite(fd, nh, HEADER_MAGIC_YES);
489 rpmlog(RPMLOG_ERR, _("Unable to write header to %s: %s\n"),
490 fileName, Fstrerror(fd));
495 /* Write the payload into the package. */
496 rc = copyPayload(ifd, fileName, fd, sigtarget);
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;
513 rpmFreeSignature(sig);
518 (void) unlink(sigtarget);
523 rpmlog(RPMLOG_NOTICE, _("Wrote: %s\n"), fileName);
525 (void) unlink(fileName);
530 static const rpmTagVal copyTags[] = {
531 RPMTAG_CHANGELOGTIME,
532 RPMTAG_CHANGELOGNAME,
533 RPMTAG_CHANGELOGTEXT,
537 static rpmRC checkPackages(char *pkgcheck)
539 int fail = rpmExpandNumeric("%{?_nonzero_exit_pkgcheck_terminate_build}");
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;
548 if (WEXITSTATUS(xx) != 0) {
549 rpmlog(RPMLOG_ERR, _("Package check \"%s\" failed.\n"), pkgcheck);
550 if (fail) return RPMRC_FAIL;
556 static void trimChangelog(Header h)
559 static int cuttime, minnum, maxnum;
561 char ** names = 0, ** texts = 0;
562 int i, keep, count = 0;
565 char *binarychangelogtrim = rpmExpand("%{?_binarychangelogtrim}", NULL);
567 if (binarychangelogtrim && *binarychangelogtrim) {
568 maxnum = atoi(binarychangelogtrim);
569 binarychangelogtrim = strchr(binarychangelogtrim, ',');
570 if (binarychangelogtrim)
571 binarychangelogtrim++;
573 if (binarychangelogtrim && *binarychangelogtrim) {
574 cuttime = atoi(binarychangelogtrim);
575 binarychangelogtrim = strchr(binarychangelogtrim, ',');
576 if (binarychangelogtrim)
577 binarychangelogtrim++;
579 if (binarychangelogtrim && *binarychangelogtrim) {
580 minnum = atoi(binarychangelogtrim);
581 binarychangelogtrim = strchr(binarychangelogtrim, ',');
584 if (!cuttime && !minnum && !maxnum) {
587 if (!headerGetEntry(h, RPMTAG_CHANGELOGTIME, NULL, (void **) ×, &count))
589 if ((!cuttime || count <= minnum) && (!maxnum || count <= maxnum)) {
593 if (maxnum && keep > maxnum)
596 for (i = 0; i < keep; i++) {
597 if (i >= minnum && times[i] < cuttime)
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);
613 rpmRC packageBinaries(rpmSpec spec, const char *cookie, int cheating)
615 struct cpioSourceArchive_s csabuf;
618 const char *errorString;
620 char *pkglist = NULL;
622 trimChangelog(spec->packages->header);
623 for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
626 if (pkg->fileList == NULL)
629 if ((rc = processScriptFiles(spec, pkg)))
633 headerPutString(pkg->header, RPMTAG_COOKIE, cookie);
636 /* Copy changelog from src rpm */
637 headerCopyTags(spec->packages->header, pkg->header, copyTags);
639 headerPutString(pkg->header, RPMTAG_RPMVERSION, VERSION);
640 headerPutString(pkg->header, RPMTAG_BUILDHOST, buildHost());
641 headerPutUint32(pkg->header, RPMTAG_BUILDTIME, getBuildTime(), 1);
643 if (spec->sourcePkgId != NULL) {
644 headerPutBin(pkg->header, RPMTAG_SOURCEPKGID, spec->sourcePkgId,16);
648 (void) rpmlibNeedsFeature(pkg->header, "ShortCircuited", "4.9.0-1");
651 { char *binFormat = rpmGetPath("%{_rpmfilename}", NULL);
652 char *binRpm, *binDir;
653 binRpm = headerFormat(pkg->header, binFormat, &errorString);
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);
661 fn = rpmGetPath("%{_rpmdir}/", binRpm, NULL);
662 if ((binDir = strchr(binRpm, '/')) != NULL) {
666 dn = rpmGetPath("%{_rpmdir}/", binRpm, NULL);
667 if (stat(dn, &st) < 0) {
670 if (mkdir(dn, 0755) == 0)
673 rpmlog(RPMLOG_ERR,_("cannot create %s: %s\n"),
674 dn, strerror(errno));
683 memset(csa, 0, sizeof(*csa));
684 csa->cpioArchiveSize = 0;
685 csa->cpioList = rpmfiLink(pkg->cpioList);
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);
696 rstrcat(&pkglist, fn);
697 rstrcat(&pkglist, " ");
700 if (rc != RPMRC_OK) {
701 pkglist = _free(pkglist);
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);
713 pkglist = _free(pkglist);
719 rpmRC packageSources(rpmSpec spec, char **cookie)
721 struct cpioSourceArchive_s csabuf;
726 headerPutString(spec->sourceHeader, RPMTAG_RPMVERSION, VERSION);
727 headerPutString(spec->sourceHeader, RPMTAG_BUILDHOST, buildHost());
728 headerPutUint32(spec->sourceHeader, RPMTAG_BUILDTIME, getBuildTime(), 1);
730 /* XXX this should be %_srpmdir */
731 { char *fn = rpmGetPath("%{_srcrpmdir}/", spec->sourceRpmName,NULL);
732 char *pkgcheck = rpmExpand("%{?_build_pkgcheck_srpm} ", fn, NULL);
734 memset(csa, 0, sizeof(*csa));
735 csa->cpioArchiveSize = 0;
736 csa->cpioList = rpmfiLink(spec->sourceCpioList);
738 spec->sourcePkgId = NULL;
739 rc = writeRPM(&spec->sourceHeader, &spec->sourcePkgId, fn, csa, cookie);
741 /* Do check SRPM package if enabled */
742 if (rc == RPMRC_OK && pkgcheck[0] != ' ') {
743 rc = checkPackages(pkgcheck);
746 rpmfiFree(csa->cpioList);