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);
335 * Add system-wide Tizen build information
337 char *buildinfo = rpmExpand("%{?_buildinfo}", NULL);
338 if (buildinfo && *buildinfo) {
341 char **strings = NULL;
343 if ((err = poptParseArgvString(buildinfo, &count, &strings))) {
344 rpmlog(RPMLOG_ERR, _("Can't parse BUILDINFO tag: %s\n"), poptStrerror(xx));
349 headerPutStringArray(h, RPMTAG_BUILDINFO, strings, count);
351 strings = _free(strings);
355 /* Reallocate the header into one contiguous region. */
356 h = headerReload(h, RPMTAG_HEADERIMMUTABLE);
357 if (h == NULL) { /* XXX can't happen */
359 rpmlog(RPMLOG_ERR, _("Unable to create immutable header region.\n"));
362 /* Re-reference reallocated header. */
363 *hdrp = headerLink(h);
366 * Write the header+archive into a temp file so that the size of
367 * archive (after compression) can be added to the header.
369 fd = rpmMkTempFile(NULL, &sigtarget);
370 if (fd == NULL || Ferror(fd)) {
372 rpmlog(RPMLOG_ERR, _("Unable to open temp file.\n"));
376 fdInitDigest(fd, PGPHASHALGO_SHA1, 0);
377 if (headerWrite(fd, h, HEADER_MAGIC_YES)) {
379 rpmlog(RPMLOG_ERR, _("Unable to write temp header\n"));
380 } else { /* Write the archive and get the size */
382 fdFiniDigest(fd, PGPHASHALGO_SHA1, (void **)&SHA1, NULL, 1);
383 if (csa->cpioList != NULL) {
384 rc = cpio_doio(fd, h, csa, rpmio_flags);
387 rpmlog(RPMLOG_ERR, _("Bad CSA data\n"));
396 (void) unlink(fileName);
398 /* Generate the signature */
399 (void) fflush(stdout);
400 sig = rpmNewSignature();
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
410 if (csa->cpioArchiveSize < UINT32_MAX) {
411 sizetag = RPMSIGTAG_SIZE;
412 payloadtag = RPMSIGTAG_PAYLOADSIZE;
414 sizetag = RPMSIGTAG_LONGSIZE;
415 payloadtag = RPMSIGTAG_LONGARCHIVESIZE;
417 (void) rpmGenDigest(sig, sigtarget, sizetag);
418 (void) rpmGenDigest(sig, sigtarget, RPMSIGTAG_MD5);
421 /* XXX can't use rpmtdFromFoo() on RPMSIGTAG_* items */
423 td.tag = RPMSIGTAG_SHA1;
424 td.type = RPM_STRING_TYPE;
427 headerPut(sig, &td, HEADERPUT_DEFAULT);
432 /* XXX can't use headerPutType() on legacy RPMSIGTAG_* items */
436 if (payloadtag == RPMSIGTAG_PAYLOADSIZE) {
437 rpm_off_t asize = csa->cpioArchiveSize;
438 td.type = RPM_INT32_TYPE;
440 headerPut(sig, &td, HEADERPUT_DEFAULT);
442 rpm_loff_t asize = csa->cpioArchiveSize;
443 td.type = RPM_INT64_TYPE;
445 headerPut(sig, &td, HEADERPUT_DEFAULT);
449 /* Reallocate the signature into one contiguous region. */
450 sig = headerReload(sig, RPMTAG_HEADERSIGNATURES);
451 if (sig == NULL) { /* XXX can't happen */
453 rpmlog(RPMLOG_ERR, _("Unable to reload signature header.\n"));
457 /* Open the output file */
458 fd = Fopen(fileName, "w.ufdio");
459 if (fd == NULL || Ferror(fd)) {
461 rpmlog(RPMLOG_ERR, _("Could not open %s: %s\n"),
462 fileName, Fstrerror(fd));
466 /* Write the lead section into the package. */
468 rpmlead lead = rpmLeadFromHeader(h);
469 rc = rpmLeadWrite(fd, lead);
471 if (rc != RPMRC_OK) {
473 rpmlog(RPMLOG_ERR, _("Unable to write package: %s\n"),
479 /* Write the signature section into the package. */
480 if (rpmWriteSignature(fd, sig)) {
485 /* Append the header and archive */
486 ifd = Fopen(sigtarget, "r.ufdio");
487 if (ifd == NULL || Ferror(ifd)) {
489 rpmlog(RPMLOG_ERR, _("Unable to open sigtarget %s: %s\n"),
490 sigtarget, Fstrerror(ifd));
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);
500 rpmlog(RPMLOG_ERR, _("Unable to read header from %s: %s\n"),
501 sigtarget, Fstrerror(ifd));
505 xx = headerWrite(fd, nh, HEADER_MAGIC_YES);
510 rpmlog(RPMLOG_ERR, _("Unable to write header to %s: %s\n"),
511 fileName, Fstrerror(fd));
516 /* Write the payload into the package. */
517 rc = copyPayload(ifd, fileName, fd, sigtarget);
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;
534 rpmFreeSignature(sig);
539 (void) unlink(sigtarget);
544 rpmlog(RPMLOG_NOTICE, _("Wrote: %s\n"), fileName);
546 (void) unlink(fileName);
551 static const rpmTagVal copyTags[] = {
552 RPMTAG_CHANGELOGTIME,
553 RPMTAG_CHANGELOGNAME,
554 RPMTAG_CHANGELOGTEXT,
558 static rpmRC checkPackages(char *pkgcheck)
560 int fail = rpmExpandNumeric("%{?_nonzero_exit_pkgcheck_terminate_build}");
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;
569 if (WEXITSTATUS(xx) != 0) {
570 rpmlog(RPMLOG_ERR, _("Package check \"%s\" failed.\n"), pkgcheck);
571 if (fail) return RPMRC_FAIL;
577 static void trimChangelog(Header h)
580 static int cuttime, minnum, maxnum;
582 char ** names = 0, ** texts = 0;
583 int i, keep, count = 0;
586 char *binarychangelogtrim = rpmExpand("%{?_binarychangelogtrim}", NULL);
588 if (binarychangelogtrim && *binarychangelogtrim) {
589 maxnum = atoi(binarychangelogtrim);
590 binarychangelogtrim = strchr(binarychangelogtrim, ',');
591 if (binarychangelogtrim)
592 binarychangelogtrim++;
594 if (binarychangelogtrim && *binarychangelogtrim) {
595 cuttime = atoi(binarychangelogtrim);
596 binarychangelogtrim = strchr(binarychangelogtrim, ',');
597 if (binarychangelogtrim)
598 binarychangelogtrim++;
600 if (binarychangelogtrim && *binarychangelogtrim) {
601 minnum = atoi(binarychangelogtrim);
602 binarychangelogtrim = strchr(binarychangelogtrim, ',');
605 if (!cuttime && !minnum && !maxnum) {
608 if (!headerGetEntry(h, RPMTAG_CHANGELOGTIME, NULL, (void **) ×, &count))
610 if ((!cuttime || count <= minnum) && (!maxnum || count <= maxnum)) {
614 if (maxnum && keep > maxnum)
617 for (i = 0; i < keep; i++) {
618 if (i >= minnum && times[i] < cuttime)
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);
634 rpmRC packageBinaries(rpmSpec spec, const char *cookie, int cheating)
636 struct cpioSourceArchive_s csabuf;
639 const char *errorString;
641 char *pkglist = NULL;
643 trimChangelog(spec->packages->header);
644 for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
647 if (pkg->fileList == NULL)
650 if ((rc = processScriptFiles(spec, pkg)))
654 headerPutString(pkg->header, RPMTAG_COOKIE, cookie);
657 /* Copy changelog from src rpm */
658 headerCopyTags(spec->packages->header, pkg->header, copyTags);
660 headerPutString(pkg->header, RPMTAG_RPMVERSION, VERSION);
661 headerPutString(pkg->header, RPMTAG_BUILDHOST, buildHost());
662 headerPutUint32(pkg->header, RPMTAG_BUILDTIME, getBuildTime(), 1);
664 if (spec->sourcePkgId != NULL) {
665 headerPutBin(pkg->header, RPMTAG_SOURCEPKGID, spec->sourcePkgId,16);
669 (void) rpmlibNeedsFeature(pkg->header, "ShortCircuited", "4.9.0-1");
672 { char *binFormat = rpmGetPath("%{_rpmfilename}", NULL);
673 char *binRpm, *binDir;
674 binRpm = headerFormat(pkg->header, binFormat, &errorString);
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);
682 fn = rpmGetPath("%{_rpmdir}/", binRpm, NULL);
683 if ((binDir = strchr(binRpm, '/')) != NULL) {
687 dn = rpmGetPath("%{_rpmdir}/", binRpm, NULL);
688 if (stat(dn, &st) < 0) {
691 if (mkdir(dn, 0755) == 0)
694 rpmlog(RPMLOG_ERR,_("cannot create %s: %s\n"),
695 dn, strerror(errno));
704 memset(csa, 0, sizeof(*csa));
705 csa->cpioArchiveSize = 0;
706 csa->cpioList = rpmfiLink(pkg->cpioList);
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);
717 rstrcat(&pkglist, fn);
718 rstrcat(&pkglist, " ");
721 if (rc != RPMRC_OK) {
722 pkglist = _free(pkglist);
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);
734 pkglist = _free(pkglist);
740 rpmRC packageSources(rpmSpec spec, char **cookie)
742 struct cpioSourceArchive_s csabuf;
747 headerPutString(spec->sourceHeader, RPMTAG_RPMVERSION, VERSION);
748 headerPutString(spec->sourceHeader, RPMTAG_BUILDHOST, buildHost());
749 headerPutUint32(spec->sourceHeader, RPMTAG_BUILDTIME, getBuildTime(), 1);
751 /* XXX this should be %_srpmdir */
752 { char *fn = rpmGetPath("%{_srcrpmdir}/", spec->sourceRpmName,NULL);
753 char *pkgcheck = rpmExpand("%{?_build_pkgcheck_srpm} ", fn, NULL);
755 memset(csa, 0, sizeof(*csa));
756 csa->cpioArchiveSize = 0;
757 csa->cpioList = rpmfiLink(spec->sourceCpioList);
759 spec->sourcePkgId = NULL;
760 rc = writeRPM(&spec->sourceHeader, &spec->sourcePkgId, fn, csa, cookie);
762 /* Do check SRPM package if enabled */
763 if (rc == RPMRC_OK && pkgcheck[0] != ' ') {
764 rc = checkPackages(pkgcheck);
767 rpmfiFree(csa->cpioList);