3
* Assemble components of an RPM package.
8
#include <rpmio_internal.h>
13
#include "signature.h"
18
extern int _noDirTokens;
21
/*@access StringBuf @*/ /* compared with NULL */
22
/*@access TFI_t @*/ /* compared with NULL */
23
/*@access Header @*/ /* compared with NULL */
24
/*@access FD_t @*/ /* compared with NULL */
29
static inline int genSourceRpmName(Spec spec)
30
/*@modifies spec->sourceRpmName @*/
32
if (spec->sourceRpmName == NULL) {
33
const char *name, *version, *release;
34
char fileName[BUFSIZ];
36
(void) headerNVR(spec->packages->header, &name, &version, &release);
37
sprintf(fileName, "%s-%s-%s.%ssrc.rpm", name, version, release,
38
spec->noSource ? "no" : "");
39
spec->sourceRpmName = xstrdup(fileName);
46
* @todo Create transaction set *much* earlier.
48
static int cpio_doio(FD_t fdo, /*@unused@*/ Header h, CSA_t csa,
49
const char * fmodeMacro)
50
/*@modifies fdo, csa, fileSystem @*/
52
const char * rootDir = "/";
54
rpmTransactionSet ts = rpmtransCreateSet(rpmdb, rootDir);
55
TFI_t fi = csa->cpioList;
56
const char *failedFile = NULL;
60
{ const char *fmode = rpmExpand(fmodeMacro, NULL);
61
if (!(fmode && fmode[0] == 'w'))
62
fmode = xstrdup("w9.gzdio");
65
cfd = Fdopen(fdDup(Fileno(fdo)), fmode);
72
rc = fsmSetup(fi->fsm, FSM_PKGBUILD, ts, fi, cfd,
73
&csa->cpioArchiveSize, &failedFile);
75
ec = fsmTeardown(fi->fsm);
80
rpmError(RPMERR_CPIO, _("create archive failed on file %s: %s\n"),
81
failedFile, cpioStrerror(rc));
83
rpmError(RPMERR_CPIO, _("create archive failed: %s\n"),
88
failedFile = _free(failedFile);
89
ts = rpmtransFree(ts);
96
static int cpio_copy(FD_t fdo, CSA_t csa)
97
/*@modifies fdo, csa, fileSystem @*/
102
while((nb = Fread(buf, sizeof(buf[0]), sizeof(buf), csa->cpioFdIn)) > 0) {
103
if (Fwrite(buf, sizeof(buf[0]), nb, fdo) != nb) {
104
rpmError(RPMERR_CPIO, _("cpio_copy write failed: %s\n"),
108
csa->cpioArchiveSize += nb;
110
if (Ferror(csa->cpioFdIn)) {
111
rpmError(RPMERR_CPIO, _("cpio_copy read failed: %s\n"),
112
Fstrerror(csa->cpioFdIn));
120
static /*@only@*/ /*@null@*/ StringBuf addFileToTagAux(Spec spec,
121
const char * file, /*@only@*/ StringBuf sb)
122
/*@modifies fileSystem @*/
125
const char * fn = buf;
129
/* XXX use rpmGenPath(rootdir, "%{_buildir}/%{_buildsubdir}/", file) */
130
fn = rpmGetPath("%{_builddir}/", spec->buildSubdir, "/", file, NULL);
132
fd = Fopen(fn, "r.ufdio");
133
if (fn != buf) fn = _free(fn);
134
if (fd == NULL || Ferror(fd)) {
135
sb = freeStringBuf(sb);
138
if ((f = fdGetFp(fd)) != NULL)
139
while (fgets(buf, sizeof(buf), f)) {
140
/* XXX display fn in error msg */
141
if (expandMacros(spec, spec->macros, buf, sizeof(buf))) {
142
rpmError(RPMERR_BADSPEC, _("line: %s\n"), buf);
143
sb = freeStringBuf(sb);
146
appendStringBuf(sb, buf);
155
static int addFileToTag(Spec spec, const char * file, Header h, int tag)
156
/*@modifies h, fileSystem @*/
158
HGE_t hge = (HGE_t)headerGetEntryMinMemory;
159
StringBuf sb = newStringBuf();
162
if (hge(h, tag, NULL, (void **)&s, NULL)) {
163
appendLineStringBuf(sb, s);
164
(void) headerRemoveEntry(h, tag);
167
if ((sb = addFileToTagAux(spec, file, sb)) == NULL)
170
(void) headerAddEntry(h, tag, RPM_STRING_TYPE, getStringBuf(sb), 1);
172
sb = freeStringBuf(sb);
178
static int addFileToArrayTag(Spec spec, const char *file, Header h, int tag)
179
/*@modifies h, fileSystem @*/
181
StringBuf sb = newStringBuf();
184
if ((sb = addFileToTagAux(spec, file, sb)) == NULL)
187
s = getStringBuf(sb);
188
(void) headerAddOrAppendEntry(h, tag, RPM_STRING_ARRAY_TYPE, &s, 1);
190
sb = freeStringBuf(sb);
196
static int processScriptFiles(Spec spec, Package pkg)
197
/*@modifies pkg->header, fileSystem @*/
199
struct TriggerFileEntry *p;
201
if (pkg->preInFile) {
202
if (addFileToTag(spec, pkg->preInFile, pkg->header, RPMTAG_PREIN)) {
203
rpmError(RPMERR_BADFILENAME,
204
_("Could not open PreIn file: %s\n"), pkg->preInFile);
205
return RPMERR_BADFILENAME;
208
if (pkg->preUnFile) {
209
if (addFileToTag(spec, pkg->preUnFile, pkg->header, RPMTAG_PREUN)) {
210
rpmError(RPMERR_BADFILENAME,
211
_("Could not open PreUn file: %s\n"), pkg->preUnFile);
212
return RPMERR_BADFILENAME;
215
if (pkg->postInFile) {
216
if (addFileToTag(spec, pkg->postInFile, pkg->header, RPMTAG_POSTIN)) {
217
rpmError(RPMERR_BADFILENAME,
218
_("Could not open PostIn file: %s\n"), pkg->postInFile);
219
return RPMERR_BADFILENAME;
222
if (pkg->postUnFile) {
223
if (addFileToTag(spec, pkg->postUnFile, pkg->header, RPMTAG_POSTUN)) {
224
rpmError(RPMERR_BADFILENAME,
225
_("Could not open PostUn file: %s\n"), pkg->postUnFile);
226
return RPMERR_BADFILENAME;
229
if (pkg->verifyFile) {
230
if (addFileToTag(spec, pkg->verifyFile, pkg->header,
231
RPMTAG_VERIFYSCRIPT)) {
232
rpmError(RPMERR_BADFILENAME,
233
_("Could not open VerifyScript file: %s\n"), pkg->verifyFile);
234
return RPMERR_BADFILENAME;
238
for (p = pkg->triggerFiles; p != NULL; p = p->next) {
239
(void) headerAddOrAppendEntry(pkg->header, RPMTAG_TRIGGERSCRIPTPROG,
240
RPM_STRING_ARRAY_TYPE, &(p->prog), 1);
242
(void) headerAddOrAppendEntry(pkg->header, RPMTAG_TRIGGERSCRIPTS,
243
RPM_STRING_ARRAY_TYPE, &(p->script), 1);
244
} else if (p->fileName) {
245
if (addFileToArrayTag(spec, p->fileName, pkg->header,
246
RPMTAG_TRIGGERSCRIPTS)) {
247
rpmError(RPMERR_BADFILENAME,
248
_("Could not open Trigger script file: %s\n"),
250
return RPMERR_BADFILENAME;
253
/* This is dumb. When the header supports NULL string */
254
/* this will go away. */
256
(void) headerAddOrAppendEntry(pkg->header, RPMTAG_TRIGGERSCRIPTS,
257
RPM_STRING_ARRAY_TYPE, &bull, 1);
264
int readRPM(const char *fileName, Spec *specp, struct rpmlead *lead,
265
Header *sigs, CSA_t csa)
271
fdi = (fileName != NULL)
272
? Fopen(fileName, "r.ufdio")
273
: fdDup(STDIN_FILENO);
275
if (fdi == NULL || Ferror(fdi)) {
276
rpmError(RPMERR_BADMAGIC, _("readRPM: open %s: %s\n"),
277
(fileName ? fileName : "<stdin>"),
279
if (fdi) (void) Fclose(fdi);
280
return RPMERR_BADMAGIC;
283
/* Get copy of lead */
284
if ((rc = Fread(lead, sizeof(char), sizeof(*lead), fdi)) != sizeof(*lead)) {
285
rpmError(RPMERR_BADMAGIC, _("readRPM: read %s: %s\n"),
286
(fileName ? fileName : "<stdin>"),
288
return RPMERR_BADMAGIC;
291
/* XXX FIXME: EPIPE on <stdin> */
292
if (Fseek(fdi, 0, SEEK_SET) == -1) {
293
rpmError(RPMERR_FSEEK, _("%s: Fseek failed: %s\n"),
294
(fileName ? fileName : "<stdin>"), Fstrerror(fdi));
298
/* Reallocate build data structures */
300
spec->packages = newPackage(spec);
302
/* XXX the header just allocated will be allocated again */
303
spec->packages->header = headerFree(spec->packages->header);
305
/* Read the rpm lead, signatures, and header */
306
rc = rpmReadPackageInfo(fdi, sigs, &spec->packages->header);
309
rpmError(RPMERR_BADMAGIC, _("readRPM: %s is not an RPM package\n"),
310
(fileName ? fileName : "<stdin>"));
311
return RPMERR_BADMAGIC;
316
case RPMRC_SHORTREAD:
318
rpmError(RPMERR_BADMAGIC, _("readRPM: reading header from %s\n"),
319
(fileName ? fileName : "<stdin>"));
320
return RPMERR_BADMAGIC;
321
/*@notreached@*/ break;
327
spec = freeSpec(spec);
337
static unsigned char header_magic[8] = {
338
0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00
341
#define RPMPKGVERSION_MIN 30004
342
#define RPMPKGVERSION_MAX 40003
343
static int rpmpkg_version = -1;
345
static int rpmLeadVersion(void)
349
/* Intitialize packaging version from macro configuration. */
350
if (rpmpkg_version < 0) {
351
rpmpkg_version = rpmExpandNumeric("%{_package_version}");
352
if (rpmpkg_version < RPMPKGVERSION_MIN)
353
rpmpkg_version = RPMPKGVERSION_MIN;
354
if (rpmpkg_version > RPMPKGVERSION_MAX)
355
rpmpkg_version = RPMPKGVERSION_MAX;
358
rpmlead_version = rpmpkg_version / 10000;
359
if (_noDirTokens || (rpmlead_version < 3 || rpmlead_version > 4))
361
return rpmlead_version;
364
int writeRPM(Header *hdrp, const char *fileName, int type,
365
CSA_t csa, char *passPhrase, const char **cookie)
370
const char * sigtarget;
371
const char * rpmio_flags = NULL;
372
const char * sha1 = NULL;
379
/* Transfer header reference form *hdrp to h. */
380
h = headerLink(*hdrp);
381
*hdrp = headerFree(*hdrp);
383
if (Fileno(csa->cpioFdIn) < 0) {
384
csa->cpioArchiveSize = 0;
385
/* Add a bogus archive size to the Header */
386
(void) headerAddEntry(h, RPMTAG_ARCHIVESIZE, RPM_INT32_TYPE,
387
&csa->cpioArchiveSize, 1);
390
/* Binary packages now have explicit Provides: name = version-release. */
391
if (type == RPMLEAD_BINARY)
392
providePackageNVR(h);
394
/* Save payload information */
397
rpmio_flags = rpmExpand("%{?_source_payload:%{_source_payload}}", NULL);
400
rpmio_flags = rpmExpand("%{?_binary_payload:%{_binary_payload}}", NULL);
403
if (!(rpmio_flags && *rpmio_flags)) {
404
rpmio_flags = _free(rpmio_flags);
405
rpmio_flags = xstrdup("w9.gzdio");
407
s = strchr(rpmio_flags, '.');
409
(void) headerAddEntry(h, RPMTAG_PAYLOADFORMAT, RPM_STRING_TYPE, "cpio", 1);
410
if (s[1] == 'g' && s[2] == 'z')
411
(void) headerAddEntry(h, RPMTAG_PAYLOADCOMPRESSOR, RPM_STRING_TYPE,
413
if (s[1] == 'b' && s[2] == 'z') {
414
(void) headerAddEntry(h, RPMTAG_PAYLOADCOMPRESSOR, RPM_STRING_TYPE,
416
/* Add prereq on rpm version that understands bzip2 payloads */
417
(void) rpmlibNeedsFeature(h, "PayloadIsBzip2", "3.0.5-1");
419
strcpy(buf, rpmio_flags);
420
buf[s - rpmio_flags] = '\0';
421
(void) headerAddEntry(h, RPMTAG_PAYLOADFLAGS, RPM_STRING_TYPE, buf+1, 1);
424
/* Create and add the cookie */
426
sprintf(buf, "%s %d", buildHost(), (int) time(NULL));
427
*cookie = xstrdup(buf);
428
(void) headerAddEntry(h, RPMTAG_COOKIE, RPM_STRING_TYPE, *cookie, 1);
431
/* Reallocate the header into one contiguous region. */
432
h = headerReload(h, RPMTAG_HEADERIMMUTABLE);
433
if (h == NULL) { /* XXX can't happen */
435
rpmError(RPMERR_RELOAD, _("Unable to create immutable header region.\n"));
438
/* Re-reference reallocated header. */
439
*hdrp = headerLink(h);
442
* Write the header+archive into a temp file so that the size of
443
* archive (after compression) can be added to the header.
445
if (makeTempFile(NULL, &sigtarget, &fd)) {
447
rpmError(RPMERR_CREATE, _("Unable to open temp file.\n"));
451
if (headerWrite(fd, h, HEADER_MAGIC_YES)) {
453
rpmError(RPMERR_NOSPACE, _("Unable to write temp header\n"));
454
} else { /* Write the archive and get the size */
455
if (csa->cpioList != NULL) {
456
rc = cpio_doio(fd, h, csa, rpmio_flags);
457
} else if (Fileno(csa->cpioFdIn) >= 0) {
458
rc = cpio_copy(fd, csa);
461
rpmError(RPMERR_BADARG, _("Bad CSA data\n"));
464
rpmio_flags = _free(rpmio_flags);
470
* Set the actual archive size, and rewrite the header.
471
* This used to be done using headerModifyEntry(), but now that headers
472
* have regions, the value is scribbled directly into the header data
473
* area. Some new scheme for adding the final archive size will have
474
* to be devised if headerGetEntryMinMemory() ever changes to return
475
* a pointer to memory not in the region, probably by appending
476
* the archive size to the header region rather than including the
477
* archive size within the header region.
479
if (Fileno(csa->cpioFdIn) < 0) {
480
HGE_t hge = (HGE_t)headerGetEntryMinMemory;
481
int_32 * archiveSize;
482
if (hge(h, RPMTAG_ARCHIVESIZE, NULL, (void *)&archiveSize, NULL))
483
*archiveSize = csa->cpioArchiveSize;
487
if (Fseek(fd, sizeof(header_magic), SEEK_SET) == -1) {
489
rpmError(RPMERR_FSEEK, _("%s: Fseek failed: %s\n"),
490
sigtarget, Fstrerror(fd));
494
if (headerWrite(fd, h, HEADER_MAGIC_NO)) {
496
rpmError(RPMERR_NOSPACE, _("Unable to write final header\n"));
499
fdFiniSHA1(fd, (void **)&sha1, NULL, 1);
503
(void) Unlink(fileName);
508
/* Generate the signature */
509
(void) fflush(stdout);
510
sig = rpmNewSignature();
511
(void) rpmAddSignature(sig, sigtarget, RPMSIGTAG_SIZE, passPhrase);
512
(void) rpmAddSignature(sig, sigtarget, RPMSIGTAG_MD5, passPhrase);
513
if ((sigtype = rpmLookupSignatureType(RPMLOOKUPSIG_QUERY)) > 0) {
514
rpmMessage(RPMMESS_NORMAL, _("Generating signature: %d\n"), sigtype);
515
(void) rpmAddSignature(sig, sigtarget, sigtype, passPhrase);
519
(void) headerAddEntry(sig, RPMTAG_SHA1HEADER, RPM_STRING_TYPE, sha1, 1);
523
/* Reallocate the signature into one contiguous region. */
524
sig = headerReload(sig, RPMTAG_HEADERSIGNATURES);
525
if (sig == NULL) { /* XXX can't happen */
527
rpmError(RPMERR_RELOAD, _("Unable to reload signature header.\n"));
531
/* Open the output file */
532
fd = Fopen(fileName, "w.ufdio");
533
if (fd == NULL || Ferror(fd)) {
535
rpmError(RPMERR_CREATE, _("Could not open %s: %s\n"),
536
fileName, Fstrerror(fd));
540
/* Write the lead section into the package. */
545
if (Fileno(csa->cpioFdIn) < 0) {
547
rpmGetArchInfo(NULL, &archnum);
548
rpmGetOsInfo(NULL, &osnum);
550
} else if (csa->lead != NULL) {
551
archnum = csa->lead->archnum;
552
osnum = csa->lead->osnum;
555
memset(&lead, 0, sizeof(lead));
556
lead.major = rpmLeadVersion();
559
lead.archnum = archnum;
561
lead.signature_type = RPMSIGTYPE_HEADERSIG;
563
{ const char *name, *version, *release;
564
(void) headerNVR(h, &name, &version, &release);
565
sprintf(buf, "%s-%s-%s", name, version, release);
566
strncpy(lead.name, buf, sizeof(lead.name));
569
if (writeLead(fd, &lead)) {
571
rpmError(RPMERR_NOSPACE, _("Unable to write package: %s\n"),
577
/* Write the signature section into the package. */
578
rc = rpmWriteSignature(fd, sig);
582
/* Append the header and archive */
583
ifd = Fopen(sigtarget, "r.ufdio");
584
if (ifd == NULL || Ferror(ifd)) {
586
rpmError(RPMERR_READ, _("Unable to open sigtarget %s: %s\n"),
587
sigtarget, Fstrerror(ifd));
591
/* Add signatures to header, and write header into the package. */
592
{ Header nh = headerRead(ifd, HEADER_MAGIC_YES);
596
rpmError(RPMERR_READ, _("Unable to read header from %s: %s\n"),
597
sigtarget, Fstrerror(ifd));
602
(void) headerMergeLegacySigs(nh, sig);
605
rc = headerWrite(fd, nh, HEADER_MAGIC_YES);
610
rpmError(RPMERR_NOSPACE, _("Unable to write header to %s: %s\n"),
611
fileName, Fstrerror(fd));
616
/* Write the payload into the package. */
617
while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), ifd)) > 0) {
620
rpmError(RPMERR_READ, _("Unable to read payload from %s: %s\n"),
621
sigtarget, Fstrerror(ifd));
624
if (Fwrite(buf, sizeof(buf[0]), count, fd) != count) {
626
rpmError(RPMERR_NOSPACE, _("Unable to write payload to %s: %s\n"),
627
fileName, Fstrerror(fd));
636
sig = rpmFreeSignature(sig);
646
(void) Unlink(sigtarget);
647
sigtarget = _free(sigtarget);
651
rpmMessage(RPMMESS_NORMAL, _("Wrote: %s\n"), fileName);
653
(void) Unlink(fileName);
658
static int_32 copyTags[] = {
659
RPMTAG_CHANGELOGTIME,
660
RPMTAG_CHANGELOGNAME,
661
RPMTAG_CHANGELOGTEXT,
665
int packageBinaries(Spec spec)
667
struct cpioSourceArchive_s csabuf;
670
const char *errorString;
673
for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
676
if (pkg->fileList == NULL)
679
if ((rc = processScriptFiles(spec, pkg)))
683
(void) headerAddEntry(pkg->header, RPMTAG_COOKIE,
684
RPM_STRING_TYPE, spec->cookie, 1);
687
/* Copy changelog from src rpm */
688
headerCopyTags(spec->packages->header, pkg->header, copyTags);
690
(void) headerAddEntry(pkg->header, RPMTAG_RPMVERSION,
691
RPM_STRING_TYPE, VERSION, 1);
692
(void) headerAddEntry(pkg->header, RPMTAG_BUILDHOST,
693
RPM_STRING_TYPE, buildHost(), 1);
694
(void) headerAddEntry(pkg->header, RPMTAG_BUILDTIME,
695
RPM_INT32_TYPE, getBuildTime(), 1);
697
providePackageNVR(pkg->header);
699
{ const char * optflags = rpmExpand("%{optflags}", NULL);
700
(void) headerAddEntry(pkg->header, RPMTAG_OPTFLAGS, RPM_STRING_TYPE,
702
optflags = _free(optflags);
705
(void) genSourceRpmName(spec);
706
(void) headerAddEntry(pkg->header, RPMTAG_SOURCERPM, RPM_STRING_TYPE,
707
spec->sourceRpmName, 1);
709
{ const char *binFormat = rpmGetPath("%{_rpmfilename}", NULL);
710
char *binRpm, *binDir;
711
binRpm = headerSprintf(pkg->header, binFormat, rpmTagTable,
712
rpmHeaderFormats, &errorString);
713
binFormat = _free(binFormat);
714
if (binRpm == NULL) {
716
(void) headerNVR(pkg->header, &name, NULL, NULL);
717
rpmError(RPMERR_BADFILENAME, _("Could not generate output "
718
"filename for package %s: %s\n"), name, errorString);
719
return RPMERR_BADFILENAME;
721
fn = rpmGetPath("%{_rpmdir}/", binRpm, NULL);
722
if ((binDir = strchr(binRpm, '/')) != NULL) {
726
dn = rpmGetPath("%{_rpmdir}/", binRpm, NULL);
727
if (Stat(dn, &st) < 0) {
730
if (Mkdir(dn, 0755) == 0)
734
rpmError(RPMERR_BADFILENAME,_("cannot create %s: %s\n"),
735
dn, strerror(errno));
741
binRpm = _free(binRpm);
744
memset(csa, 0, sizeof(*csa));
745
csa->cpioArchiveSize = 0;
746
csa->cpioFdIn = fdNew("init (packageBinaries)");
747
csa->cpioList = pkg->cpioList;
749
rc = writeRPM(&pkg->header, fn, RPMLEAD_BINARY,
750
csa, spec->passPhrase, NULL);
751
csa->cpioFdIn = fdFree(csa->cpioFdIn, "init (packageBinaries)");
760
int packageSources(Spec spec)
762
struct cpioSourceArchive_s csabuf;
767
(void) headerAddEntry(spec->sourceHeader, RPMTAG_RPMVERSION,
768
RPM_STRING_TYPE, VERSION, 1);
769
(void) headerAddEntry(spec->sourceHeader, RPMTAG_BUILDHOST,
770
RPM_STRING_TYPE, buildHost(), 1);
771
(void) headerAddEntry(spec->sourceHeader, RPMTAG_BUILDTIME,
772
RPM_INT32_TYPE, getBuildTime(), 1);
774
(void) genSourceRpmName(spec);
776
spec->cookie = _free(spec->cookie);
778
/* XXX this should be %_srpmdir */
779
{ const char *fn = rpmGetPath("%{_srcrpmdir}/", spec->sourceRpmName,NULL);
781
memset(csa, 0, sizeof(*csa));
782
csa->cpioArchiveSize = 0;
783
csa->cpioFdIn = fdNew("init (packageSources)");
784
csa->cpioList = spec->sourceCpioList;
786
rc = writeRPM(&spec->sourceHeader, fn, RPMLEAD_SOURCE,
787
csa, spec->passPhrase, &(spec->cookie));
788
csa->cpioFdIn = fdFree(csa->cpioFdIn, "init (packageSources)");