From 55c12c3e283d39e412642e317cd89a2a5d577e0a Mon Sep 17 00:00:00 2001 From: Florian Festi Date: Fri, 16 Feb 2024 14:02:15 +0100 Subject: [PATCH] No build directives in generated spec parts Many things need to be known before the build can be started. Make declaring these sections or directives an error when encountered parsing the generated Spec parts. Resolves: #2693 --- build/parsePreamble.c | 39 +++++++++++++++++++++++++++++++---- build/parseSpec.c | 33 ++++++++++++++++++++++++++++- docs/manual/dynamic_specs.md | 11 ++++++++++ tests/data/SPECS/dynamic.spec | 2 ++ tests/rpmbuild.at | 34 ++++++++++++++++++++++++++++++ 5 files changed, 114 insertions(+), 5 deletions(-) diff --git a/build/parsePreamble.c b/build/parsePreamble.c index a23e5a8f65..afc0603f53 100644 --- a/build/parsePreamble.c +++ b/build/parsePreamble.c @@ -797,8 +797,9 @@ static int addBuildOption(rpmSpec spec, const char *sect, const char *opt) return rc; } -static rpmRC handlePreambleTag(rpmSpec spec, Package pkg, rpmTagVal tag, - const char *macro, const char *lang) +static rpmRC handlePreambleTag(rpmSpec spec, enum parseStages stage, + Package pkg, rpmTagVal tag, + const char *macro, const char *lang) { char * field = spec->line; char * end; @@ -1009,6 +1010,14 @@ static rpmRC handlePreambleTag(rpmSpec spec, Package pkg, rpmTagVal tag, BANames = _free(BANames); goto exit; } + if (stage == GENERATED && + (BACount != 1 || !rstreq(BANames[0], "noarch"))) { + rpmlog(RPMLOG_ERR, + _("line %d: Only noarch is allowed after the build: %s\n"), + spec->lineNum, spec->line); + BANames = _free(BANames); + goto exit; + } spec->BACount = BACount; spec->BANames = BANames; } else { @@ -1179,7 +1188,7 @@ static int findPreambleTag(rpmSpec spec,rpmTagVal * tag, return 0; } -int parsePreamble(rpmSpec spec, int initialPackage) +int parsePreamble(rpmSpec spec, int initialPackage, enum parseStages stage) { int nextPart = PART_ERROR; int res = PART_ERROR; /* assume failure */ @@ -1248,7 +1257,29 @@ int parsePreamble(rpmSpec spec, int initialPackage) spec->lineNum, spec->line); goto exit; } - if (handlePreambleTag(spec, pkg, tag, macro, lang)) { + if (stage == GENERATED) { + switch (tag) { + case RPMTAG_SOURCE: + case RPMTAG_PATCH: + case RPMTAG_NOSOURCE: + case RPMTAG_NOPATCH: + case RPMTAG_EXCLUDEARCH: + case RPMTAG_EXCLUSIVEARCH: + case RPMTAG_EXCLUDEOS: + case RPMTAG_EXCLUSIVEOS: + case RPMTAG_BUILDROOT: + case RPMTAG_BUILDCONFLICTS: + case RPMTAG_BUILDOPTION: + case RPMTAG_BUILDPREREQ: + case RPMTAG_BUILDREQUIRES: + case RPMTAG_BUILDSYSTEM: + rpmlog(RPMLOG_ERR, _("line %d: Tag not allowed after build is done: %s\n"), + spec->lineNum, spec->line); + goto exit; + default: ; + } + } + if (handlePreambleTag(spec, stage, pkg, tag, macro, lang)) { goto exit; } if (spec->BANames && !spec->recursing) { diff --git a/build/parseSpec.c b/build/parseSpec.c index 6baaffde5c..146deceba3 100644 --- a/build/parseSpec.c +++ b/build/parseSpec.c @@ -100,6 +100,18 @@ int isPart(const char *line) return (p->token ? p->part : PART_NONE); } +static const char * partName(int part) +{ + const struct PartRec *p; + + for (p = partList; p->token != NULL; p++) { + if (p->part == part) { + return p->token; + } + } + return NULL; +} + /** */ static int matchTok(const char *token, const char *line) @@ -1022,7 +1034,7 @@ static rpmRC parseSpecSection(rpmSpec *specptr, enum parseStages stage) parsePart = parseEmpty(spec, prevParsePart); break; case PART_PREAMBLE: - parsePart = parsePreamble(spec, initialPackage); + parsePart = parsePreamble(spec, initialPackage, stage); initialPackage = 0; break; case PART_PATCHLIST: @@ -1111,6 +1123,25 @@ static rpmRC parseSpecSection(rpmSpec *specptr, enum parseStages stage) goto errxit; } + if (stage == GENERATED) { + switch (parsePart) { + case PART_PREP: + case PART_BUILD: + case PART_INSTALL: + case PART_CHECK: + case PART_CLEAN: /* ???? */ + case PART_BUILDARCHITECTURES: + case PART_PATCHLIST: + case PART_SOURCELIST: + case PART_BUILDREQUIRES: + case PART_CONF: + rpmlog(RPMLOG_ERR, _("Section %s is not allowed after build is done!\n"), partName(parsePart)); + goto errxit; + break; + default: + ; + } + } if (parsePart == PART_BUILDARCHITECTURES) { int index; int x; diff --git a/docs/manual/dynamic_specs.md b/docs/manual/dynamic_specs.md index 44e6ca2fc4..2084028707 100644 --- a/docs/manual/dynamic_specs.md +++ b/docs/manual/dynamic_specs.md @@ -34,3 +34,14 @@ interpreted right away. [Example](https://github.com/rpm-software-management/rpm/blob/master/tests/data/SPECS/dynamic.spec) from our tests set. + +As dynamic spec parts are generate during build they cannot include +directives that are needed for or influence building. This includes +all build scripts, sources and patches, Build dependencies, tags +regarding the build environment (**ExcludeArch**, **ExclusiveArch**, +**ExcludeOS**, **ExclusiveOS**), **BuildArch** except for declaring +sub packages **noarch** and **BuildSystem**. These will create an +error if encountered in a dynamically generated spec part. + +While declaring macros used in the build scripts are not an error they +won't have an influence on the build for obvious reasons. diff --git a/tests/data/SPECS/dynamic.spec b/tests/data/SPECS/dynamic.spec index ce31ed2828..511675d051 100644 --- a/tests/data/SPECS/dynamic.spec +++ b/tests/data/SPECS/dynamic.spec @@ -41,6 +41,8 @@ echo "LicenseToKill: True" >> %{specpartsdir}/mainpkg.specpart echo "%package docs" >> %{specpartsdir}/docs.specpart %{?!FAIL:echo "Summary: Documentation for dynamic spec" >> %{specpartsdir}/docs.specpart} echo "BuildArch: noarch" >> %{specpartsdir}/docs.specpart +%{?FORBIDDENTAG:echo "BuildRequires: python3" >> %{specpartsdir}/docs.specpart} +%{?FORBIDDENSECTION:echo "%check" >> %{specpartsdir}/docs.specpart} echo "%description docs" >> %{specpartsdir}/docs.specpart echo "Test for dynamically generated spec files" >> %{specpartsdir}/docs.specpart echo "%files docs" >> $RPM_SPECPARTS_DIR/docs.specpart diff --git a/tests/rpmbuild.at b/tests/rpmbuild.at index c47a532e9b..0857e76d8d 100644 --- a/tests/rpmbuild.at +++ b/tests/rpmbuild.at @@ -2764,6 +2764,40 @@ error: parsing failed RPMTEST_CLEANUP +# ------------------------------ +# Check failing dynamic spec generation +AT_SETUP([rpmbuild with dynamic spec generation fail]) +AT_KEYWORDS([build]) +RPMDB_INIT +RPMTEST_CHECK([ + +runroot rpmbuild --quiet -D "FULLDYNAMIC 1" -D "FORBIDDENSECTION 1" -ba /data/SPECS/dynamic.spec +], +[1], +[], +[error: Section %check is not allowed after build is done! +error: parsing failed +]) + +RPMTEST_CLEANUP + +# ------------------------------ +# Check failing dynamic spec generation +AT_SETUP([rpmbuild with dynamic spec generation fail]) +AT_KEYWORDS([build]) +RPMDB_INIT +RPMTEST_CHECK([ + +runroot rpmbuild --quiet -D "FULLDYNAMIC 1" -D "FORBIDDENTAG 1" -ba /data/SPECS/dynamic.spec +], +[1], +[], +[error: line 4: Tag not allowed after build is done: BuildRequires: python3 +error: parsing failed +]) + +RPMTEST_CLEANUP + # ------------------------------ # Check source name with space