From b1eb41516fd8a6674f334502f98a99d3aa7f9a58 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 | 135 +++++++++++++++++++--------------- build/parseSpec.c | 33 ++++++++- docs/manual/dynamic_specs.md | 11 +++ tests/data/SPECS/dynamic.spec | 2 + tests/rpmbuild.at | 34 +++++++++ 5 files changed, 155 insertions(+), 60 deletions(-) diff --git a/build/parsePreamble.c b/build/parsePreamble.c index a23e5a8f65..29ba4a2d67 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 == PARSE_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 { @@ -1060,71 +1069,72 @@ typedef const struct PreambleRec_s { int type; int deprecated; int ismacro; + int notgenerated; size_t len; const char * token; } * PreambleRec; static struct PreambleRec_s const preambleList[] = { - {RPMTAG_NAME, 0, 0, 1, LEN_AND_STR("name")}, - {RPMTAG_VERSION, 0, 0, 1, LEN_AND_STR("version")}, - {RPMTAG_RELEASE, 0, 0, 1, LEN_AND_STR("release")}, - {RPMTAG_EPOCH, 0, 0, 1, LEN_AND_STR("epoch")}, - {RPMTAG_SUMMARY, 1, 0, 1, LEN_AND_STR("summary")}, - {RPMTAG_LICENSE, 0, 0, 1, LEN_AND_STR("license")}, - {RPMTAG_SOURCELICENSE, 0, 0, 1, LEN_AND_STR("sourcelicense")}, - {RPMTAG_DISTRIBUTION, 0, 0, 1, LEN_AND_STR("distribution")}, - {RPMTAG_DISTURL, 0, 0, 1, LEN_AND_STR("disturl")}, - {RPMTAG_VENDOR, 0, 0, 1, LEN_AND_STR("vendor")}, - {RPMTAG_GROUP, 1, 0, 1, LEN_AND_STR("group")}, - {RPMTAG_PACKAGER, 0, 0, 1, LEN_AND_STR("packager")}, - {RPMTAG_URL, 0, 0, 1, LEN_AND_STR("url")}, - {RPMTAG_VCS, 0, 0, 1, LEN_AND_STR("vcs")}, - {RPMTAG_SOURCE, 0, 0, 0, LEN_AND_STR("source")}, - {RPMTAG_PATCH, 0, 0, 0, LEN_AND_STR("patch")}, - {RPMTAG_NOSOURCE, 0, 0, 0, LEN_AND_STR("nosource")}, - {RPMTAG_NOPATCH, 0, 0, 0, LEN_AND_STR("nopatch")}, - {RPMTAG_EXCLUDEARCH, 0, 0, 0, LEN_AND_STR("excludearch")}, - {RPMTAG_EXCLUSIVEARCH, 0, 0, 0, LEN_AND_STR("exclusivearch")}, - {RPMTAG_EXCLUDEOS, 0, 0, 0, LEN_AND_STR("excludeos")}, - {RPMTAG_EXCLUSIVEOS, 0, 0, 0, LEN_AND_STR("exclusiveos")}, - {RPMTAG_ICON, 0, 0, 0, LEN_AND_STR("icon")}, - {RPMTAG_PROVIDENAME, 0, 0, 0, LEN_AND_STR("provides")}, - {RPMTAG_REQUIRENAME, 2, 0, 0, LEN_AND_STR("requires")}, - {RPMTAG_RECOMMENDNAME, 0, 0, 0, LEN_AND_STR("recommends")}, - {RPMTAG_SUGGESTNAME, 0, 0, 0, LEN_AND_STR("suggests")}, - {RPMTAG_SUPPLEMENTNAME, 0, 0, 0, LEN_AND_STR("supplements")}, - {RPMTAG_ENHANCENAME, 0, 0, 0, LEN_AND_STR("enhances")}, - {RPMTAG_PREREQ, 2, 1, 0, LEN_AND_STR("prereq")}, - {RPMTAG_CONFLICTNAME, 0, 0, 0, LEN_AND_STR("conflicts")}, - {RPMTAG_OBSOLETENAME, 0, 0, 0, LEN_AND_STR("obsoletes")}, - {RPMTAG_PREFIXES, 0, 0, 1, LEN_AND_STR("prefixes")}, - {RPMTAG_PREFIXES, 0, 0, 1, LEN_AND_STR("prefix")}, - {RPMTAG_BUILDROOT, 0, 0, 0, LEN_AND_STR("buildroot")}, - {RPMTAG_BUILDARCHS, 0, 0, 0, LEN_AND_STR("buildarchitectures")}, - {RPMTAG_BUILDARCHS, 0, 0, 0, LEN_AND_STR("buildarch")}, - {RPMTAG_BUILDCONFLICTS, 0, 0, 0, LEN_AND_STR("buildconflicts")}, - {RPMTAG_BUILDOPTION, 2, 0, 0, LEN_AND_STR("buildoption")}, - {RPMTAG_BUILDPREREQ, 0, 1, 0, LEN_AND_STR("buildprereq")}, - {RPMTAG_BUILDREQUIRES, 0, 0, 0, LEN_AND_STR("buildrequires")}, - {RPMTAG_BUILDSYSTEM, 0, 0, 1, LEN_AND_STR("buildsystem")}, - {RPMTAG_AUTOREQPROV, 0, 0, 0, LEN_AND_STR("autoreqprov")}, - {RPMTAG_AUTOREQ, 0, 0, 0, LEN_AND_STR("autoreq")}, - {RPMTAG_AUTOPROV, 0, 0, 0, LEN_AND_STR("autoprov")}, - {RPMTAG_DOCDIR, 0, 0, 0, LEN_AND_STR("docdir")}, - {RPMTAG_DISTTAG, 0, 0, 1, LEN_AND_STR("disttag")}, - {RPMTAG_BUGURL, 0, 0, 1, LEN_AND_STR("bugurl")}, - {RPMTAG_TRANSLATIONURL, 0, 0, 1, LEN_AND_STR("translationurl")}, - {RPMTAG_UPSTREAMRELEASES, 0, 0, 1, LEN_AND_STR("upstreamreleases")}, - {RPMTAG_ORDERNAME, 2, 0, 0, LEN_AND_STR("orderwithrequires")}, - {RPMTAG_REMOVEPATHPOSTFIXES,0, 0, 1, LEN_AND_STR("removepathpostfixes")}, - {RPMTAG_MODULARITYLABEL, 0, 0, 1, LEN_AND_STR("modularitylabel")}, + {RPMTAG_NAME, 0, 0, 1, 0, LEN_AND_STR("name")}, + {RPMTAG_VERSION, 0, 0, 1, 0, LEN_AND_STR("version")}, + {RPMTAG_RELEASE, 0, 0, 1, 0, LEN_AND_STR("release")}, + {RPMTAG_EPOCH, 0, 0, 1, 0, LEN_AND_STR("epoch")}, + {RPMTAG_SUMMARY, 1, 0, 1, 0, LEN_AND_STR("summary")}, + {RPMTAG_LICENSE, 0, 0, 1, 0, LEN_AND_STR("license")}, + {RPMTAG_SOURCELICENSE, 0, 0, 1, 0, LEN_AND_STR("sourcelicense")}, + {RPMTAG_DISTRIBUTION, 0, 0, 1, 0, LEN_AND_STR("distribution")}, + {RPMTAG_DISTURL, 0, 0, 1, 0, LEN_AND_STR("disturl")}, + {RPMTAG_VENDOR, 0, 0, 1, 0, LEN_AND_STR("vendor")}, + {RPMTAG_GROUP, 1, 0, 1, 0, LEN_AND_STR("group")}, + {RPMTAG_PACKAGER, 0, 0, 1, 0, LEN_AND_STR("packager")}, + {RPMTAG_URL, 0, 0, 1, 0, LEN_AND_STR("url")}, + {RPMTAG_VCS, 0, 0, 1, 0, LEN_AND_STR("vcs")}, + {RPMTAG_SOURCE, 0, 0, 0, 1, LEN_AND_STR("source")}, + {RPMTAG_PATCH, 0, 0, 0, 1, LEN_AND_STR("patch")}, + {RPMTAG_NOSOURCE, 0, 0, 0, 1, LEN_AND_STR("nosource")}, + {RPMTAG_NOPATCH, 0, 0, 0, 1, LEN_AND_STR("nopatch")}, + {RPMTAG_EXCLUDEARCH, 0, 0, 0, 1, LEN_AND_STR("excludearch")}, + {RPMTAG_EXCLUSIVEARCH, 0, 0, 0, 1, LEN_AND_STR("exclusivearch")}, + {RPMTAG_EXCLUDEOS, 0, 0, 0, 1, LEN_AND_STR("excludeos")}, + {RPMTAG_EXCLUSIVEOS, 0, 0, 0, 1, LEN_AND_STR("exclusiveos")}, + {RPMTAG_ICON, 0, 0, 0, 0, LEN_AND_STR("icon")}, + {RPMTAG_PROVIDENAME, 0, 0, 0, 0, LEN_AND_STR("provides")}, + {RPMTAG_REQUIRENAME, 2, 0, 0, 0, LEN_AND_STR("requires")}, + {RPMTAG_RECOMMENDNAME, 0, 0, 0, 0, LEN_AND_STR("recommends")}, + {RPMTAG_SUGGESTNAME, 0, 0, 0, 0, LEN_AND_STR("suggests")}, + {RPMTAG_SUPPLEMENTNAME, 0, 0, 0, 0, LEN_AND_STR("supplements")}, + {RPMTAG_ENHANCENAME, 0, 0, 0, 0, LEN_AND_STR("enhances")}, + {RPMTAG_PREREQ, 2, 1, 0, 0, LEN_AND_STR("prereq")}, + {RPMTAG_CONFLICTNAME, 0, 0, 0, 0, LEN_AND_STR("conflicts")}, + {RPMTAG_OBSOLETENAME, 0, 0, 0, 0, LEN_AND_STR("obsoletes")}, + {RPMTAG_PREFIXES, 0, 0, 1, 0, LEN_AND_STR("prefixes")}, + {RPMTAG_PREFIXES, 0, 0, 1, 0, LEN_AND_STR("prefix")}, + {RPMTAG_BUILDROOT, 0, 0, 0, 1, LEN_AND_STR("buildroot")}, + {RPMTAG_BUILDARCHS, 0, 0, 0, 0, LEN_AND_STR("buildarchitectures")}, + {RPMTAG_BUILDARCHS, 0, 0, 0, 0, LEN_AND_STR("buildarch")}, + {RPMTAG_BUILDCONFLICTS, 0, 0, 0, 1, LEN_AND_STR("buildconflicts")}, + {RPMTAG_BUILDOPTION, 2, 0, 0, 1, LEN_AND_STR("buildoption")}, + {RPMTAG_BUILDPREREQ, 0, 1, 0, 1, LEN_AND_STR("buildprereq")}, + {RPMTAG_BUILDREQUIRES, 0, 0, 0, 1, LEN_AND_STR("buildrequires")}, + {RPMTAG_BUILDSYSTEM, 0, 0, 1, 1, LEN_AND_STR("buildsystem")}, + {RPMTAG_AUTOREQPROV, 0, 0, 0, 0, LEN_AND_STR("autoreqprov")}, + {RPMTAG_AUTOREQ, 0, 0, 0, 0, LEN_AND_STR("autoreq")}, + {RPMTAG_AUTOPROV, 0, 0, 0, 0, LEN_AND_STR("autoprov")}, + {RPMTAG_DOCDIR, 0, 0, 0, 0, LEN_AND_STR("docdir")}, + {RPMTAG_DISTTAG, 0, 0, 1, 0, LEN_AND_STR("disttag")}, + {RPMTAG_BUGURL, 0, 0, 1, 0, LEN_AND_STR("bugurl")}, + {RPMTAG_TRANSLATIONURL, 0, 0, 1, 0, LEN_AND_STR("translationurl")}, + {RPMTAG_UPSTREAMRELEASES, 0, 0, 1, 0, LEN_AND_STR("upstreamreleases")}, + {RPMTAG_ORDERNAME, 2, 0, 0, 0, LEN_AND_STR("orderwithrequires")}, + {RPMTAG_REMOVEPATHPOSTFIXES,0, 0, 1, 0, LEN_AND_STR("removepathpostfixes")}, + {RPMTAG_MODULARITYLABEL, 0, 0, 1, 0, LEN_AND_STR("modularitylabel")}, {0, 0, 0, 0} }; /** */ static int findPreambleTag(rpmSpec spec,rpmTagVal * tag, - const char ** macro, char * lang) + const char ** macro, char * lang, int * notgenerated) { PreambleRec p; char *s; @@ -1176,10 +1186,11 @@ static int findPreambleTag(rpmSpec spec,rpmTagVal * tag, *tag = p->tag; *macro = p->ismacro ? p->token : NULL; + *notgenerated = p->notgenerated; 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 */ @@ -1235,7 +1246,8 @@ int parsePreamble(rpmSpec spec, int initialPackage) linep = spec->line; SKIPSPACE(linep); if (*linep != '\0') { - if (findPreambleTag(spec, &tag, ¯o, lang)) { + int notgenerated; + if (findPreambleTag(spec, &tag, ¯o, lang, ¬generated)) { if (spec->lineNum == 1 && (unsigned char)(spec->line[0]) == 0xed && (unsigned char)(spec->line[1]) == 0xab && @@ -1248,7 +1260,12 @@ int parsePreamble(rpmSpec spec, int initialPackage) spec->lineNum, spec->line); goto exit; } - if (handlePreambleTag(spec, pkg, tag, macro, lang)) { + if (stage == PARSE_GENERATED && notgenerated) { + rpmlog(RPMLOG_ERR, _("line %d: Tag not allowed after build is done: %s\n"), + spec->lineNum, spec->line); + goto exit; + } + 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 f456e77a11..4be57944b5 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 == PARSE_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