They are first written to a temporary file10:
/*
* Write the header+archive into a temp file so that the size of
* archive (after compression) can be added to the header.
*/
if (makeTempFile(NULL, &sigtarget, &fd)) {
rc = RPMERR_CREATE;
rpmError(RPMERR_CREATE, _("Unable to open temp file.\n"));
goto exit;
}
fdInitDigest(fd, PGPHASHALGO_SHA1, 0);
if (headerWrite(fd, h, HEADER_MAGIC_YES)) {
rc = RPMERR_NOSPACE;
rpmError(RPMERR_NOSPACE, _("Unable to write temp header\n"));
} else { /* Write the archive and get the size */
(void) Fflush(fd);
fdFiniDigest(fd, PGPHASHALGO_SHA1, (void **)&SHA1, NULL, 1);
if (csa->cpioList != NULL) {
rc = cpio_doio(fd, h, csa, rpmio_flags);
} else if (Fileno(csa->cpioFdIn) >= 0) {
rc = cpio_copy(fd, csa);
} else {
rc = RPMERR_BADARG;
rpmError(RPMERR_BADARG, _("Bad CSA data\n"));
}
}
rpmio_flags = _free(rpmio_flags);
Then, the Signature is generated:
/* Generate the signature */
(void) fflush(stdout);
sig = rpmNewSignature();
(void) rpmAddSignature(sig, sigtarget, RPMSIGTAG_SIZE, passPhrase);
(void) rpmAddSignature(sig, sigtarget, RPMSIGTAG_MD5, passPhrase);
if ((sigtag = rpmLookupSignatureType(RPMLOOKUPSIG_QUERY)) > 0) {
rpmMessage(RPMMESS_NORMAL, _("Generating signature: %d\n"), sigtag);
(void) rpmAddSignature(sig, sigtarget, sigtag, passPhrase);
}
if (SHA1) {
(void) headerAddEntry(sig, RPMSIGTAG_SHA1, RPM_STRING_TYPE, SHA1, 1);
SHA1 = _free(SHA1);
}
{ int_32 payloadSize = csa->cpioArchiveSize;
(void) headerAddEntry(sig, RPMSIGTAG_PAYLOADSIZE, RPM_INT32_TYPE,
&payloadSize, 1);
}
/* Reallocate the signature into one contiguous region. */
sig = headerReload(sig, RPMTAG_HEADERSIGNATURES);
if (sig == NULL) { /* XXX can't happen */
rc = RPMERR_RELOAD;
rpmError(RPMERR_RELOAD, _("Unable to reload signature header.\n"));
goto exit;
}
Finally, the RPM is written. First, the Lead is generated and dumped:
/* Write the lead section into the package. */
{ int archnum = -1;
int osnum = -1;
struct rpmlead lead;
if (Fileno(csa->cpioFdIn) < 0) {
#ifndef DYING
rpmGetArchInfo(NULL, &archnum);
rpmGetOsInfo(NULL, &osnum);
#endif
} else if (csa->lead != NULL) {
archnum = csa->lead->archnum;
osnum = csa->lead->osnum;
}
memset(&lead, 0, sizeof(lead));
lead.major = rpmLeadVersion();
lead.minor = 0;
lead.type = type;
lead.archnum = archnum;
lead.osnum = osnum;
lead.signature_type = RPMSIGTYPE_HEADERSIG;
{ const char *name, *version, *release;
(void) headerNVR(h, &name, &version, &release);
sprintf(buf, "%s-%s-%s", name, version, release);
strncpy(lead.name, buf, sizeof(lead.name));
}
if (writeLead(fd, &lead) != RPMRC_OK) {
rc = RPMERR_NOSPACE;
rpmError(RPMERR_NOSPACE, _("Unable to write package: %s\n"),
Fstrerror(fd));
goto exit;
}
}
Then the signature is also dumped:
/* Write the signature section into the package. */
rc = rpmWriteSignature(fd, sig);
if (rc)
goto exit;
Finally, the Header and Payload are appended:
/* Add signatures to header, and write header into the package. */
/* XXX header+payload digests/signatures might be checked again here. */
{ Header nh = headerRead(ifd, HEADER_MAGIC_YES);
if (nh == NULL) {
rc = RPMERR_READ;
rpmError(RPMERR_READ, _("Unable to read header from %s: %s\n"),
sigtarget, Fstrerror(ifd));
goto exit;
}
#ifdef NOTYET
(void) headerMergeLegacySigs(nh, sig);
#endif
rc = headerWrite(fd, nh, HEADER_MAGIC_YES);
nh = headerFree(nh);
if (rc) {
rc = RPMERR_NOSPACE;
rpmError(RPMERR_NOSPACE, _("Unable to write header to %s: %s\n"),
fileName, Fstrerror(fd));
goto exit;
}
}
/* Write the payload into the package. */
while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), ifd)) > 0) {
if (count == -1) {
rc = RPMERR_READ;
rpmError(RPMERR_READ, _("Unable to read payload from %s: %s\n"),
sigtarget, Fstrerror(ifd));
goto exit;
}
if (Fwrite(buf, sizeof(buf[0]), count, fd) != count) {
rc = RPMERR_NOSPACE;
rpmError(RPMERR_NOSPACE, _("Unable to write payload to %s: %s\n"),
fileName, Fstrerror(fd));
goto exit;
}
}
rc = 0;
build.c contains the function to generate the archive. build will call successively buildForTarget for each target specified. Let's study buildForTarget in more details.
The first step is to retrieve the Spec file, which contains metadata about the package to build (see below for more details):
specDir = rpmGetPath("%{_specdir}", NULL);
tmpSpecFile = rpmGetPath("%{_specdir}/", "rpm-spec.XXXXXX", NULL);
#if defined(HAVE_MKSTEMP)
(void) close(mkstemp(tmpSpecFile));
#else
(void) mktemp(tmpSpecFile);
#endif
(void) isCompressed(arg, &res);
cmd = alloca(strlen(arg) + 50 + strlen(tmpSpecFile));
sprintf(cmd, "%s < %s | tar xOvf - Specfile 2>&1 > %s",
zcmds[res & 0x3], arg, tmpSpecFile);
if (!(fp = popen(cmd, "r"))) {
rpmError(RPMERR_POPEN, _("Failed to open tar pipe: %m\n"));
specDir = _free(specDir);
tmpSpecFile = _free(tmpSpecFile);
return 1;
}
if ((!fgets(buf, sizeof(buf) - 1, fp)) || !strchr(buf, '/')) {
/* Try again */
(void) pclose(fp);
sprintf(cmd, "%s < %s | tar xOvf - --wildcards \\*.spec 2>&1 > %s",
zcmds[res & 0x3], arg, tmpSpecFile);
if (!(fp = popen(cmd, "r"))) {
rpmError(RPMERR_POPEN, _("Failed to open tar pipe: %m\n"));
specDir = _free(specDir);
tmpSpecFile = _free(tmpSpecFile);
return 1;
}
if (!fgets(buf, sizeof(buf) - 1, fp)) {
/* Give up */
rpmError(RPMERR_READ, _("Failed to read spec file from %s\n"),
arg);
(void) unlink(tmpSpecFile);
specDir = _free(specDir);
tmpSpecFile = _free(tmpSpecFile);
return 1;
}
}
(void) pclose(fp);
Some sanity checks are performed (by calling isSpecFile ) before parsing it. buildSpec will finally perform the operations specified in the Spec file.
Let's see now how to create a RPM package from a higher point of view.