rpmRC writeRPM(Header *hdrp, unsigned char ** pkgidp, const char *fileName, CSA_t csa, char *passPhrase, char **cookie) { FD_t fd = NULL; FD_t ifd = NULL; ssize_t count; rpmSigTag sigtag; char * sigtarget = NULL;; char * rpmio_flags = NULL; char * SHA1 = NULL; char *s; char *buf = NULL; Header h; Header sig = NULL; int xx; rpmRC rc = RPMRC_OK; struct rpmtd_s td; rpmSigTag sizetag; rpmTag payloadtag; /* Transfer header reference form *hdrp to h. */ h = headerLink(*hdrp); *hdrp = headerFree(*hdrp); if (pkgidp) *pkgidp = NULL; /* Save payload information */ if (headerIsSource(h)) rpmio_flags = rpmExpand("%{?_source_payload}", NULL); else rpmio_flags = rpmExpand("%{?_binary_payload}", NULL); if (!(rpmio_flags && *rpmio_flags)) { rpmio_flags = _free(rpmio_flags); rpmio_flags = xstrdup("w9.gzdio"); } s = strchr(rpmio_flags, '.'); if (s) { const char *compr = NULL; headerPutString(h, RPMTAG_PAYLOADFORMAT, "cpio"); if (strcmp(s+1, "gzdio") == 0) { compr = "gzip"; } else if (strcmp(s+1, "bzdio") == 0) { compr = "bzip2"; /* Add prereq on rpm version that understands bzip2 payloads */ (void) rpmlibNeedsFeature(h, "PayloadIsBzip2", "3.0.5-1"); } else if (strcmp(s+1, "lzdio") == 0) { compr = "lzma"; (void) rpmlibNeedsFeature(h, "PayloadIsLzma", "4.4.90-1"); } else { rpmlog(RPMLOG_ERR, _("Unknown payload compression: %s\n"), rpmio_flags); rc = RPMRC_FAIL; goto exit; } headerPutString(h, RPMTAG_PAYLOADCOMPRESSOR, compr); buf = xstrdup(rpmio_flags); buf[s - rpmio_flags] = '\0'; headerPutString(h, RPMTAG_PAYLOADFLAGS, buf+1); free(buf); } /* Create and add the cookie */ if (cookie) { rasprintf(cookie, "%s %d", buildHost(), (int) (*getBuildTime())); headerPutString(h, RPMTAG_COOKIE, *cookie); } /* Reallocate the header into one contiguous region. */ h = headerReload(h, RPMTAG_HEADERIMMUTABLE); if (h == NULL) { /* XXX can't happen */ rc = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("Unable to create immutable header region.\n")); goto exit; } /* Re-reference reallocated header. */ *hdrp = headerLink(h); /* * Write the header+archive into a temp file so that the size of * archive (after compression) can be added to the header. */ fd = rpmMkTempFile(NULL, &sigtarget); if (fd == NULL || Ferror(fd)) { rc = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("Unable to open temp file.\n")); goto exit; } fdInitDigest(fd, PGPHASHALGO_SHA1, 0); if (headerWrite(fd, h, HEADER_MAGIC_YES)) { rc = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("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 = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("Bad CSA data\n")); } } rpmio_flags = _free(rpmio_flags); if (rc != RPMRC_OK) goto exit; (void) Fclose(fd); fd = NULL; (void) unlink(fileName); /* Generate the signature */ (void) fflush(stdout); sig = rpmNewSignature(); /* * There should be rpmlib() dependency on this, but that doesn't * really do much good as these are signature tags that get read * way before dependency checking has a chance to figure out anything. * On the positive side, not inserting the 32bit tag at all means * older rpm will just bail out with error message on attempt to read * such a package. */ if (csa->cpioArchiveSize < UINT32_MAX) { sizetag = RPMSIGTAG_SIZE; payloadtag = RPMSIGTAG_PAYLOADSIZE; } else { sizetag = RPMSIGTAG_LONGSIZE; payloadtag = RPMSIGTAG_LONGARCHIVESIZE; } (void) rpmAddSignature(sig, sigtarget, sizetag, passPhrase); (void) rpmAddSignature(sig, sigtarget, RPMSIGTAG_MD5, passPhrase); if ((sigtag = rpmLookupSignatureType(RPMLOOKUPSIG_QUERY)) > 0) { rpmlog(RPMLOG_NOTICE, _("Generating signature: %d\n"), sigtag); (void) rpmAddSignature(sig, sigtarget, sigtag, passPhrase); } if (SHA1) { /* XXX can't use rpmtdFromFoo() on RPMSIGTAG_* items */ rpmtdReset(&td); td.tag = RPMSIGTAG_SHA1; td.type = RPM_STRING_TYPE; td.data = SHA1; td.count = 1; headerPut(sig, &td, HEADERPUT_DEFAULT); SHA1 = _free(SHA1); } { /* XXX can't use headerPutType() on legacy RPMSIGTAG_* items */ rpmtdReset(&td); td.tag = payloadtag; td.count = 1; if (payloadtag == RPMSIGTAG_PAYLOADSIZE) { rpm_off_t asize = csa->cpioArchiveSize; td.type = RPM_INT32_TYPE; td.data = &asize; headerPut(sig, &td, HEADERPUT_DEFAULT); } else { rpm_loff_t asize = csa->cpioArchiveSize; td.type = RPM_INT64_TYPE; td.data = &asize; headerPut(sig, &td, HEADERPUT_DEFAULT); } } /* Reallocate the signature into one contiguous region. */ sig = headerReload(sig, RPMTAG_HEADERSIGNATURES); if (sig == NULL) { /* XXX can't happen */ rc = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("Unable to reload signature header.\n")); goto exit; } /* Open the output file */ fd = Fopen(fileName, "w.ufdio"); if (fd == NULL || Ferror(fd)) { rc = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("Could not open %s: %s\n"), fileName, Fstrerror(fd)); goto exit; } /* Write the lead section into the package. */ { rpmlead lead = rpmLeadFromHeader(h); rc = rpmLeadWrite(fd, lead); lead = rpmLeadFree(lead); if (rc != RPMRC_OK) { rc = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("Unable to write package: %s\n"), Fstrerror(fd)); goto exit; } } /* Write the signature section into the package. */ if (rpmWriteSignature(fd, sig)) { rc = RPMRC_FAIL; goto exit; } /* Append the header and archive */ ifd = Fopen(sigtarget, "r.ufdio"); if (ifd == NULL || Ferror(ifd)) { rc = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("Unable to open sigtarget %s: %s\n"), sigtarget, Fstrerror(ifd)); goto exit; } /* 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 = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("Unable to read header from %s: %s\n"), sigtarget, Fstrerror(ifd)); goto exit; } #ifdef NOTYET (void) headerMergeLegacySigs(nh, sig); #endif xx = headerWrite(fd, nh, HEADER_MAGIC_YES); nh = headerFree(nh); if (xx) { rc = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("Unable to write header to %s: %s\n"), fileName, Fstrerror(fd)); goto exit; } } /* Write the payload into the package. */ buf = xmalloc(BUFSIZ); while ((count = Fread(buf, 1, BUFSIZ, ifd)) > 0) { if (count == -1) { free(buf); rc = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("Unable to read payload from %s: %s\n"), sigtarget, Fstrerror(ifd)); goto exit; } if (Fwrite(buf, sizeof(buf[0]), count, fd) != count) { free(buf); rc = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("Unable to write payload to %s: %s\n"), fileName, Fstrerror(fd)); goto exit; } } free(buf); rc = RPMRC_OK; exit: SHA1 = _free(SHA1); h = headerFree(h); /* XXX Fish the pkgid out of the signature header. */ if (sig != NULL && pkgidp != NULL) { struct rpmtd_s md5tag; headerGet(sig, RPMSIGTAG_MD5, &md5tag, HEADERGET_DEFAULT); if (rpmtdType(&md5tag) == RPM_BIN_TYPE && md5tag.count == 16 && md5tag.data != NULL) { *pkgidp = md5tag.data; } } sig = rpmFreeSignature(sig); if (ifd) { (void) Fclose(ifd); ifd = NULL; } if (fd) { (void) Fclose(fd); fd = NULL; } if (sigtarget) { (void) unlink(sigtarget); sigtarget = _free(sigtarget); } if (rc == RPMRC_OK) rpmlog(RPMLOG_NOTICE, _("Wrote: %s\n"), fileName); else (void) unlink(fileName); return rc; }
static rpmRC handlePreambleTag(rpmSpec spec, Package pkg, rpmTagVal tag, const char *macro, const char *lang) { char * field = spec->line; char * end; int multiToken = 0; rpmsenseFlags tagflags = RPMSENSE_ANY; rpmRC rc = RPMRC_FAIL; if (field == NULL) /* XXX can't happen */ goto exit; /* Find the start of the "field" and strip trailing space */ while ((*field) && (*field != ':')) field++; if (*field != ':') { rpmlog(RPMLOG_ERR, _("line %d: Malformed tag: %s\n"), spec->lineNum, spec->line); goto exit; } field++; SKIPSPACE(field); if (!*field) { /* Empty field */ rpmlog(RPMLOG_ERR, _("line %d: Empty tag: %s\n"), spec->lineNum, spec->line); goto exit; } end = findLastChar(field); *(end+1) = '\0'; /* See if this is multi-token */ end = field; SKIPNONSPACE(end); if (*end != '\0') multiToken = 1; switch (tag) { case RPMTAG_NAME: SINGLE_TOKEN_ONLY; if (rpmCharCheck(spec, field, WHITELIST_NAME)) goto exit; headerPutString(pkg->header, tag, field); /* Main pkg name is unknown at the start, populate as soon as we can */ if (pkg == spec->packages) pkg->name = rpmstrPoolId(spec->pool, field, 1); break; case RPMTAG_VERSION: case RPMTAG_RELEASE: SINGLE_TOKEN_ONLY; if (rpmCharCheck(spec, field, "._+%{}~")) goto exit; headerPutString(pkg->header, tag, field); break; case RPMTAG_URL: case RPMTAG_DISTTAG: case RPMTAG_BUGURL: /* XXX TODO: validate format somehow */ case RPMTAG_VCS: SINGLE_TOKEN_ONLY; headerPutString(pkg->header, tag, field); break; case RPMTAG_GROUP: case RPMTAG_SUMMARY: case RPMTAG_DISTRIBUTION: case RPMTAG_VENDOR: case RPMTAG_LICENSE: case RPMTAG_PACKAGER: if (addLangTag(spec, pkg->header, tag, field, lang)) goto exit; break; case RPMTAG_BUILDROOT: /* just silently ignore BuildRoot */ macro = NULL; break; case RPMTAG_PREFIXES: { struct rpmtd_s td; const char *str; if (addOrAppendListEntry(pkg->header, tag, field)) goto exit; headerGet(pkg->header, tag, &td, HEADERGET_MINMEM); while ((str = rpmtdNextString(&td))) { size_t len = strlen(str); if (len > 1 && str[len-1] == '/') { rpmlog(RPMLOG_ERR, _("line %d: Prefixes must not end with \"/\": %s\n"), spec->lineNum, spec->line); rpmtdFreeData(&td); goto exit; } } rpmtdFreeData(&td); break; } case RPMTAG_DOCDIR: SINGLE_TOKEN_ONLY; if (field[0] != '/') { rpmlog(RPMLOG_ERR, _("line %d: Docdir must begin with '/': %s\n"), spec->lineNum, spec->line); goto exit; } macro = NULL; rpmPopMacro(NULL, "_docdir"); rpmPushMacro(NULL, "_docdir", NULL, field, RMIL_SPEC); break; case RPMTAG_EPOCH: { SINGLE_TOKEN_ONLY; uint32_t epoch; if (parseUnsignedNum(field, &epoch)) { rpmlog(RPMLOG_ERR, _("line %d: Epoch field must be an unsigned number: %s\n"), spec->lineNum, spec->line); goto exit; } headerPutUint32(pkg->header, tag, &epoch, 1); break; } case RPMTAG_AUTOREQPROV: pkg->autoReq = parseYesNo(field); pkg->autoProv = pkg->autoReq; break; case RPMTAG_AUTOREQ: pkg->autoReq = parseYesNo(field); break; case RPMTAG_AUTOPROV: pkg->autoProv = parseYesNo(field); break; case RPMTAG_SOURCE: case RPMTAG_PATCH: macro = NULL; if (addSource(spec, pkg, field, tag)) goto exit; break; case RPMTAG_ICON: SINGLE_TOKEN_ONLY; if (addSource(spec, pkg, field, tag) || readIcon(pkg->header, field)) goto exit; break; case RPMTAG_NOSOURCE: case RPMTAG_NOPATCH: spec->noSource = 1; if (parseNoSource(spec, field, tag)) goto exit; break; case RPMTAG_ORDERFLAGS: case RPMTAG_REQUIREFLAGS: if (parseBits(lang, installScriptBits, &tagflags)) { rpmlog(RPMLOG_ERR, _("line %d: Bad %s: qualifiers: %s\n"), spec->lineNum, rpmTagGetName(tag), spec->line); goto exit; } /* fallthrough */ case RPMTAG_PREREQ: case RPMTAG_RECOMMENDFLAGS: case RPMTAG_SUGGESTFLAGS: case RPMTAG_SUPPLEMENTFLAGS: case RPMTAG_ENHANCEFLAGS: case RPMTAG_CONFLICTFLAGS: case RPMTAG_OBSOLETEFLAGS: case RPMTAG_PROVIDEFLAGS: if (parseRCPOT(spec, pkg, field, tag, 0, tagflags)) goto exit; break; case RPMTAG_BUILDPREREQ: case RPMTAG_BUILDREQUIRES: case RPMTAG_BUILDCONFLICTS: if (parseRCPOT(spec, spec->sourcePackage, field, tag, 0, tagflags)) goto exit; break; case RPMTAG_EXCLUDEARCH: case RPMTAG_EXCLUSIVEARCH: case RPMTAG_EXCLUDEOS: case RPMTAG_EXCLUSIVEOS: if (addOrAppendListEntry(spec->buildRestrictions, tag, field)) goto exit; break; case RPMTAG_BUILDARCHS: { int BACount; const char **BANames = NULL; if (poptParseArgvString(field, &BACount, &BANames)) { rpmlog(RPMLOG_ERR, _("line %d: Bad BuildArchitecture format: %s\n"), spec->lineNum, spec->line); goto exit; } if (spec->packages == pkg) { if (spec->BANames) { rpmlog(RPMLOG_ERR, _("line %d: Duplicate BuildArch entry: %s\n"), spec->lineNum, spec->line); BANames = _free(BANames); goto exit; } spec->BACount = BACount; spec->BANames = BANames; } else { if (BACount != 1 || !rstreq(BANames[0], "noarch")) { rpmlog(RPMLOG_ERR, _("line %d: Only noarch subpackages are supported: %s\n"), spec->lineNum, spec->line); BANames = _free(BANames); goto exit; } headerPutString(pkg->header, RPMTAG_ARCH, "noarch"); } if (!BACount) spec->BANames = _free(spec->BANames); break; } case RPMTAG_REMOVEPATHPOSTFIXES: argvSplit(&pkg->removePostfixes, field, ":"); break; default: rpmlog(RPMLOG_ERR, _("Internal error: Bogus tag %d\n"), tag); goto exit; } if (macro) { rpmPushMacro(spec->macros, macro, NULL, field, RMIL_SPEC); /* Add a separate uppercase macro for tags from the main package */ if (pkg == spec->packages) { char *m = xstrdup(macro); for (char *p = m; *p; ++p) *p = rtoupper(*p); rpmPushMacro(spec->macros, m, NULL, field, RMIL_SPEC); free(m); } } rc = RPMRC_OK; exit: return rc; }
static rpmRC processScriptFiles(rpmSpec spec, Package pkg) { struct TriggerFileEntry *p; if (pkg->preInFile) { if (addFileToTag(spec, pkg->preInFile, pkg->header, RPMTAG_PREIN)) { rpmlog(RPMLOG_ERR, _("Could not open PreIn file: %s\n"), pkg->preInFile); return RPMRC_FAIL; } } if (pkg->preUnFile) { if (addFileToTag(spec, pkg->preUnFile, pkg->header, RPMTAG_PREUN)) { rpmlog(RPMLOG_ERR, _("Could not open PreUn file: %s\n"), pkg->preUnFile); return RPMRC_FAIL; } } if (pkg->preTransFile) { if (addFileToTag(spec, pkg->preTransFile, pkg->header, RPMTAG_PRETRANS)) { rpmlog(RPMLOG_ERR, _("Could not open PreTrans file: %s\n"), pkg->preTransFile); return RPMRC_FAIL; } } if (pkg->postInFile) { if (addFileToTag(spec, pkg->postInFile, pkg->header, RPMTAG_POSTIN)) { rpmlog(RPMLOG_ERR, _("Could not open PostIn file: %s\n"), pkg->postInFile); return RPMRC_FAIL; } } if (pkg->postUnFile) { if (addFileToTag(spec, pkg->postUnFile, pkg->header, RPMTAG_POSTUN)) { rpmlog(RPMLOG_ERR, _("Could not open PostUn file: %s\n"), pkg->postUnFile); return RPMRC_FAIL; } } if (pkg->postTransFile) { if (addFileToTag(spec, pkg->postTransFile, pkg->header, RPMTAG_POSTTRANS)) { rpmlog(RPMLOG_ERR, _("Could not open PostTrans file: %s\n"), pkg->postTransFile); return RPMRC_FAIL; } } if (pkg->verifyFile) { if (addFileToTag(spec, pkg->verifyFile, pkg->header, RPMTAG_VERIFYSCRIPT)) { rpmlog(RPMLOG_ERR, _("Could not open VerifyScript file: %s\n"), pkg->verifyFile); return RPMRC_FAIL; } } for (p = pkg->triggerFiles; p != NULL; p = p->next) { headerPutString(pkg->header, RPMTAG_TRIGGERSCRIPTPROG, p->prog); if (p->script) { headerPutString(pkg->header, RPMTAG_TRIGGERSCRIPTS, p->script); } else if (p->fileName) { if (addFileToArrayTag(spec, p->fileName, pkg->header, RPMTAG_TRIGGERSCRIPTS)) { rpmlog(RPMLOG_ERR, _("Could not open Trigger script file: %s\n"), p->fileName); return RPMRC_FAIL; } } else { /* This is dumb. When the header supports NULL string */ /* this will go away. */ headerPutString(pkg->header, RPMTAG_TRIGGERSCRIPTS, ""); } } return RPMRC_OK; }
int parsePreamble(rpmSpec spec, int initialPackage) { int nextPart = PART_ERROR; int res = PART_ERROR; /* assume failure */ int rc; char *name, *linep; int flag = 0; Package pkg; char *NVR = NULL; char lang[BUFSIZ]; if (! initialPackage) { /* There is one option to %package: <pkg> or -n <pkg> */ if (parseSimplePart(spec->line, &name, &flag)) { rpmlog(RPMLOG_ERR, _("Bad package specification: %s\n"), spec->line); goto exit; } if (rpmCharCheck(spec, name, WHITELIST_NAME)) goto exit; if (!lookupPackage(spec, name, flag, NULL)) { free(name); goto exit; } /* Construct the package */ if (flag == PART_SUBNAME) { rasprintf(&NVR, "%s-%s", headerGetString(spec->packages->header, RPMTAG_NAME), name); } else NVR = xstrdup(name); free(name); pkg = newPackage(NVR, spec->pool, &spec->packages); headerPutString(pkg->header, RPMTAG_NAME, NVR); } else { NVR = xstrdup("(main package)"); pkg = newPackage(NULL, spec->pool, &spec->packages); spec->sourcePackage = newPackage(NULL, spec->pool, NULL); } if ((rc = readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) { nextPart = PART_NONE; } else if (rc < 0) { goto exit; } else { while (! (nextPart = isPart(spec->line))) { const char * macro; rpmTagVal tag; /* Skip blank lines */ linep = spec->line; SKIPSPACE(linep); if (*linep != '\0') { if (findPreambleTag(spec, &tag, ¯o, lang)) { if (spec->lineNum == 1 && (unsigned char)(spec->line[0]) == 0xed && (unsigned char)(spec->line[1]) == 0xab && (unsigned char)(spec->line[2]) == 0xee && (unsigned char)(spec->line[3]) == 0xdb) { rpmlog(RPMLOG_ERR, _("Binary rpm package found. Expected spec file!\n")); goto exit; } rpmlog(RPMLOG_ERR, _("line %d: Unknown tag: %s\n"), spec->lineNum, spec->line); goto exit; } if (handlePreambleTag(spec, pkg, tag, macro, lang)) { goto exit; } if (spec->BANames && !spec->recursing) { res = PART_BUILDARCHITECTURES; goto exit; } } if ((rc = readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) { nextPart = PART_NONE; break; } if (rc) { goto exit; } } } /* * Expand buildroot one more time to get %{version} and the like * from the main package, validate sanity. The spec->buildRoot could * still contain unexpanded macros but it cannot be empty or '/', and it * can't be messed with by anything spec does beyond this point. */ if (initialPackage) { char *buildRoot = rpmGetPath(spec->buildRoot, NULL); if (*buildRoot == '\0') { rpmlog(RPMLOG_ERR, _("%%{buildroot} couldn't be empty\n")); goto exit; } if (rstreq(buildRoot, "/")) { rpmlog(RPMLOG_ERR, _("%%{buildroot} can not be \"/\"\n")); goto exit; } free(spec->buildRoot); spec->buildRoot = buildRoot; rpmPushMacro(spec->macros, "buildroot", NULL, spec->buildRoot, RMIL_SPEC); } /* XXX Skip valid arch check if not building binary package */ if (!(spec->flags & RPMSPEC_ANYARCH) && checkForValidArchitectures(spec)) { goto exit; } /* It is the main package */ if (pkg == spec->packages) { fillOutMainPackage(pkg->header); /* Define group tag to something when group is undefined in main package*/ if (!headerIsEntry(pkg->header, RPMTAG_GROUP)) { headerPutString(pkg->header, RPMTAG_GROUP, "Unspecified"); } } if (checkForDuplicates(pkg->header, NVR)) { goto exit; } if (pkg != spec->packages) { headerCopyTags(spec->packages->header, pkg->header, (rpmTagVal *)copyTagsDuringParse); } if (checkForRequired(pkg->header, NVR)) { goto exit; } /* if we get down here nextPart has been set to non-error */ res = nextPart; exit: free(NVR); return res; }