rpm/build/parseSpec.c

729 lines
19 KiB
C
Raw Normal View History

/** \ingroup rpmbuild
* \file build/parseSpec.c
* Top level dispatcher for spec file parsing.
*/
#include "system.h"
#include <errno.h>
#include <rpm/rpmtypes.h>
#include <rpm/rpmlib.h> /* RPM_MACHTABLE & related */
#include <rpm/rpmds.h>
#include <rpm/rpmts.h>
#include <rpm/rpmlog.h>
#include <rpm/rpmfileutil.h>
#include "build/rpmbuild_internal.h"
#include "build/rpmbuild_misc.h"
#include "debug.h"
#define SKIPSPACE(s) { while (*(s) && risspace(*(s))) (s)++; }
#define SKIPNONSPACE(s) { while (*(s) && !risspace(*(s))) (s)++; }
#define ISMACRO(s,m) (rstreqn((s), (m), sizeof((m))-1) && !risalpha((s)[sizeof((m))-1]))
#define ISMACROWITHARG(s,m) (rstreqn((s), (m), sizeof((m))-1) && (risblank((s)[sizeof((m))-1]) || !(s)[sizeof((m))-1]))
2007-10-29 19:24:15 +08:00
#define LEN_AND_STR(_tag) (sizeof(_tag)-1), (_tag)
typedef struct OpenFileInfo {
char * fileName;
FILE *fp;
int lineNum;
char readBuf[BUFSIZ];
const char * readPtr;
struct OpenFileInfo * next;
} OFI_t;
static const struct PartRec {
int part;
2007-12-14 17:38:20 +08:00
size_t len;
const char * token;
} partList[] = {
{ PART_PREAMBLE, LEN_AND_STR("%package")},
{ PART_PREP, LEN_AND_STR("%prep")},
{ PART_BUILD, LEN_AND_STR("%build")},
{ PART_INSTALL, LEN_AND_STR("%install")},
{ PART_CHECK, LEN_AND_STR("%check")},
{ PART_CLEAN, LEN_AND_STR("%clean")},
{ PART_PREUN, LEN_AND_STR("%preun")},
{ PART_POSTUN, LEN_AND_STR("%postun")},
{ PART_PRETRANS, LEN_AND_STR("%pretrans")},
{ PART_POSTTRANS, LEN_AND_STR("%posttrans")},
{ PART_PRE, LEN_AND_STR("%pre")},
{ PART_POST, LEN_AND_STR("%post")},
{ PART_FILES, LEN_AND_STR("%files")},
{ PART_CHANGELOG, LEN_AND_STR("%changelog")},
{ PART_DESCRIPTION, LEN_AND_STR("%description")},
{ PART_TRIGGERPOSTUN, LEN_AND_STR("%triggerpostun")},
{ PART_TRIGGERPREIN, LEN_AND_STR("%triggerprein")},
{ PART_TRIGGERUN, LEN_AND_STR("%triggerun")},
{ PART_TRIGGERIN, LEN_AND_STR("%triggerin")},
{ PART_TRIGGERIN, LEN_AND_STR("%trigger")},
{ PART_VERIFYSCRIPT, LEN_AND_STR("%verifyscript")},
Add new %sepolicy section to the spec file format The %sepolicy section is used to describe SELinux policy to be included in a package. It's syntax is similar to other sections (%files, %pre, %post, etc.) in that you can provide a string and -n after the declaration to specify policy should be added to a subpackage. For example: %sepolicy # policy in this section will be added to the main package %sepolicy foo # policy in this section will be added to the '<mainpackage>-foo' subpackage %sepolicy -n bar # policy in this section will be added to the 'bar' subpackage The %sepolicy section contains zero or more %semodule directives, with the following format: %semodule [OPTIONS] path/to/module.pp The available options are: -b, --base The module is a base module -n, --name=NAME The name of the module. If not given, assumes the name is the basename of the module file with file extensions removed. -t, --types=TYPES One or more comma-separated strings specifying which policy types the module can work with. To explicitly state that a module can work with any policy type, "default" can be specified as the value. If not specified, assumes the module can work with any policy type, and assigns the types as "default". Below is an example of this new format: %sepolicy %semodule -n foo -t mls policy/foo.pp %semodule -n bar -t strict,targeted,mls -b policy/bar.pp This also adds new header tags to store the new information: RPMTAG_POLICYNAMES (string array) RPMTAG_POLICYTYPES (string array) RPMTAG_POLICYTYPESINDEXES (uint32 array) RPMTAG_POLICYFLAGS (uint32 array) The index of NAMES and FLAGS maps directly to the index of RPMTAG_POLICIES. However, because a single policy can have multiple types, the mapping for TYPES is not direct. For this, the index maps to TYPESINDEXES, which contains the index of the policy that the type maps to. This is similar to how DIRINDEXES is used to map DIRNAMES and BASENAMES. As an example, the previous %sepolicy section would have the following header tags: RPMTAG_POLICIES: 0: <foo.pp data, base64 encoded> 1: <bar.pp data, base64 encoded> RPMTAG_POLICYNAMES: 0: foo 1: bar RPMTAG_POLICYFLAGS: 0: 0 1: 1 # assumes flag 1 == BASE RPMTAG_POILCYTYPES: RPMTAG_POLICYTYPESINDEXES: 0: mls 0: 0 1: strict 1: 1 2: targeted 2: 1 3: mls 3: 1
2010-08-31 04:32:29 +08:00
{ PART_POLICIES, LEN_AND_STR("%sepolicy")},
{0, 0, 0}
};
int isPart(const char *line)
{
const struct PartRec *p;
for (p = partList; p->token != NULL; p++) {
char c;
if (rstrncasecmp(line, p->token, p->len))
continue;
c = *(line + p->len);
if (c == '\0' || risspace(c))
break;
}
return (p->token ? p->part : PART_NONE);
}
/**
*/
static int matchTok(const char *token, const char *line)
{
const char *b, *be = line;
size_t toklen = strlen(token);
int rc = 0;
while ( *(b = be) != '\0' ) {
SKIPSPACE(b);
be = b;
SKIPNONSPACE(be);
if (be == b)
break;
if (toklen != (be-b) || rstrncasecmp(token, b, (be-b)))
continue;
rc = 1;
break;
}
return rc;
}
void handleComments(char *s)
{
SKIPSPACE(s);
if (*s == '#')
*s = '\0';
}
/* Push a file to spec's file stack, return the newly pushed entry */
static OFI_t * pushOFI(rpmSpec spec, const char *fn)
{
OFI_t *ofi = xcalloc(1, sizeof(*ofi));
ofi->fp = NULL;
ofi->fileName = xstrdup(fn);
ofi->lineNum = 0;
ofi->readBuf[0] = '\0';
ofi->readPtr = NULL;
ofi->next = spec->fileStack;
spec->fileStack = ofi;
return spec->fileStack;
}
/* Pop from spec's file stack */
static OFI_t * popOFI(rpmSpec spec)
{
if (spec->fileStack) {
OFI_t * ofi = spec->fileStack;
spec->fileStack = ofi->next;
if (ofi->fp)
fclose(ofi->fp);
free(ofi->fileName);
free(ofi);
}
return spec->fileStack;
}
static int restoreFirstChar(rpmSpec spec)
{
/* Restore 1st char in (possible) next line */
if (spec->nextline != NULL && spec->nextpeekc != '\0') {
*spec->nextline = spec->nextpeekc;
spec->nextpeekc = '\0';
return 1;
}
return 0;
}
/* Return zero on success, 1 if we need to read more and -1 on errors. */
static int copyNextLineFromOFI(rpmSpec spec, OFI_t *ofi)
{
/* Expand next line from file into line buffer */
if (!(spec->nextline && *spec->nextline)) {
int pc = 0, bc = 0, nc = 0;
const char *from = ofi->readPtr;
char ch = ' ';
while (from && *from && ch != '\n') {
ch = spec->lbuf[spec->lbufOff] = *from;
spec->lbufOff++; from++;
if (spec->lbufOff >= spec->lbufSize) {
spec->lbufSize += BUFSIZ;
spec->lbuf = realloc(spec->lbuf, spec->lbufSize);
}
}
spec->lbuf[spec->lbufOff] = '\0';
ofi->readPtr = from;
/* Check if we need another line before expanding the buffer. */
for (const char *p = spec->lbuf; *p; p++) {
switch (*p) {
case '\\':
switch (*(p+1)) {
2007-09-12 05:03:27 +08:00
case '\n': p++, nc = 1; break;
case '\0': break;
default: p++; break;
}
2007-09-12 05:03:27 +08:00
break;
case '\n': nc = 0; break;
case '%':
switch (*(p+1)) {
2007-09-12 05:03:27 +08:00
case '{': p++, bc++; break;
case '(': p++, pc++; break;
case '%': p++; break;
}
2007-09-12 05:03:27 +08:00
break;
case '{': if (bc > 0) bc++; break;
case '}': if (bc > 0) bc--; break;
case '(': if (pc > 0) pc++; break;
case ')': if (pc > 0) pc--; break;
}
}
/* If it doesn't, ask for one more line. */
if (pc || bc || nc ) {
spec->nextline = "";
return 1;
}
spec->lbufOff = 0;
/* Don't expand macros (eg. %define) in false branch of %if clause */
if (spec->readStack->reading &&
expandMacros(spec, spec->macros, spec->lbuf, spec->lbufSize)) {
rpmlog(RPMLOG_ERR, _("line %d: %s\n"),
spec->lineNum, spec->lbuf);
return -1;
}
spec->nextline = spec->lbuf;
}
return 0;
}
static void copyNextLineFinish(rpmSpec spec, int strip)
{
char *last;
char ch;
/* Find next line in expanded line buffer */
spec->line = last = spec->nextline;
ch = ' ';
while (*spec->nextline && ch != '\n') {
ch = *spec->nextline++;
if (!risspace(ch))
last = spec->nextline;
}
/* Save 1st char of next line in order to terminate current line. */
if (*spec->nextline != '\0') {
spec->nextpeekc = *spec->nextline;
*spec->nextline = '\0';
}
if (strip & STRIP_COMMENTS)
handleComments(spec->line);
if (strip & STRIP_TRAILINGSPACE)
*last = '\0';
}
static int readLineFromOFI(rpmSpec spec, OFI_t *ofi)
{
retry:
/* Make sure the current file is open */
if (ofi->fp == NULL) {
ofi->fp = fopen(ofi->fileName, "r");
if (ofi->fp == NULL) {
rpmlog(RPMLOG_ERR, _("Unable to open %s: %s\n"),
ofi->fileName, strerror(errno));
return PART_ERROR;
}
spec->lineNum = ofi->lineNum = 0;
}
/* Make sure we have something in the read buffer */
if (!(ofi->readPtr && *(ofi->readPtr))) {
if (!fgets(ofi->readBuf, BUFSIZ, ofi->fp)) {
/* EOF, remove this file from the stack */
ofi = popOFI(spec);
/* only on last file do we signal EOF to caller */
if (ofi == NULL)
return 1;
/* otherwise, go back and try the read again. */
goto retry;
}
ofi->readPtr = ofi->readBuf;
ofi->lineNum++;
spec->lineNum = ofi->lineNum;
}
return 0;
}
#define ARGMATCH(s,token,match) \
do { \
char *os = s; \
char *exp = rpmExpand(token, NULL); \
while(*s && !risblank(*s)) s++; \
while(*s && risblank(*s)) s++; \
if (!*s) { \
rpmlog(RPMLOG_ERR, _("%s:%d: Argument expected for %s\n"), ofi->fileName, ofi->lineNum, os); \
free(exp); \
return PART_ERROR; \
} \
match = matchTok(exp, s); \
free(exp); \
} while (0)
int readLine(rpmSpec spec, int strip)
{
char *s;
int match;
struct ReadLevelEntry *rl;
OFI_t *ofi = spec->fileStack;
int rc;
int startLine = 0;
if (!restoreFirstChar(spec)) {
retry:
if ((rc = readLineFromOFI(spec, ofi)) != 0) {
if (spec->readStack->next) {
rpmlog(RPMLOG_ERR, _("line %d: Unclosed %%if\n"),
spec->readStack->lineNum);
rc = PART_ERROR;
} else if (startLine > 0) {
rpmlog(RPMLOG_ERR,
_("line %d: unclosed macro or bad line continuation\n"),
startLine);
rc = PART_ERROR;
}
2008-05-05 16:20:13 +08:00
return rc;
}
ofi = spec->fileStack;
2008-05-05 16:20:13 +08:00
/* Copy next file line into the spec line buffer */
rc = copyNextLineFromOFI(spec, ofi);
if (rc > 0) {
if (startLine == 0)
startLine = spec->lineNum;
goto retry;
} else if (rc < 0) {
return PART_ERROR;
2008-05-05 16:20:13 +08:00
}
}
copyNextLineFinish(spec, strip);
s = spec->line;
SKIPSPACE(s);
match = -1;
if (!spec->readStack->reading && ISMACROWITHARG(s, "%if")) {
match = 0;
} else if (ISMACROWITHARG(s, "%ifarch")) {
ARGMATCH(s, "%{_target_cpu}", match);
} else if (ISMACROWITHARG(s, "%ifnarch")) {
ARGMATCH(s, "%{_target_cpu}", match);
match = !match;
} else if (ISMACROWITHARG(s, "%ifos")) {
ARGMATCH(s, "%{_target_os}", match);
} else if (ISMACROWITHARG(s, "%ifnos")) {
ARGMATCH(s, "%{_target_os}", match);
match = !match;
} else if (ISMACROWITHARG(s, "%if")) {
s += 3;
match = parseExpressionBoolean(spec, s);
if (match < 0) {
rpmlog(RPMLOG_ERR,
_("%s:%d: bad %%if condition\n"),
ofi->fileName, ofi->lineNum);
return PART_ERROR;
}
} else if (ISMACRO(s, "%else")) {
if (! spec->readStack->next) {
/* Got an else with no %if ! */
rpmlog(RPMLOG_ERR,
_("%s:%d: Got a %%else with no %%if\n"),
ofi->fileName, ofi->lineNum);
return PART_ERROR;
}
spec->readStack->reading =
spec->readStack->next->reading && ! spec->readStack->reading;
spec->line[0] = '\0';
} else if (ISMACRO(s, "%endif")) {
if (! spec->readStack->next) {
/* Got an end with no %if ! */
rpmlog(RPMLOG_ERR,
_("%s:%d: Got a %%endif with no %%if\n"),
ofi->fileName, ofi->lineNum);
return PART_ERROR;
}
rl = spec->readStack;
spec->readStack = spec->readStack->next;
free(rl);
spec->line[0] = '\0';
} else if (spec->readStack->reading && ISMACROWITHARG(s, "%include")) {
char *fileName, *endFileName, *p;
fileName = s+8;
SKIPSPACE(fileName);
endFileName = fileName;
SKIPNONSPACE(endFileName);
p = endFileName;
SKIPSPACE(p);
if (*fileName == '\0' || *p != '\0') {
rpmlog(RPMLOG_ERR, _("%s:%d: malformed %%include statement\n"),
ofi->fileName, ofi->lineNum);
return PART_ERROR;
}
*endFileName = '\0';
ofi = pushOFI(spec, fileName);
goto retry;
}
if (match != -1) {
rl = xmalloc(sizeof(*rl));
rl->reading = spec->readStack->reading && match;
rl->next = spec->readStack;
rl->lineNum = ofi->lineNum;
spec->readStack = rl;
spec->line[0] = '\0';
}
if (! spec->readStack->reading) {
spec->line[0] = '\0';
}
/* Collect parsed line */
if (spec->parsed == NULL)
spec->parsed = newStringBuf();
appendStringBufAux(spec->parsed, spec->line,(strip & STRIP_TRAILINGSPACE));
2007-09-12 05:03:27 +08:00
/* FIX: spec->readStack->next should be dependent */
return 0;
}
2007-09-21 20:23:02 +08:00
void closeSpec(rpmSpec spec)
{
while (popOFI(spec)) {};
}
static const rpmTagVal sourceTags[] = {
RPMTAG_NAME,
RPMTAG_VERSION,
RPMTAG_RELEASE,
RPMTAG_EPOCH,
RPMTAG_SUMMARY,
RPMTAG_DESCRIPTION,
RPMTAG_PACKAGER,
RPMTAG_DISTRIBUTION,
RPMTAG_DISTURL,
RPMTAG_VENDOR,
RPMTAG_LICENSE,
RPMTAG_GROUP,
RPMTAG_OS,
RPMTAG_ARCH,
RPMTAG_CHANGELOGTIME,
RPMTAG_CHANGELOGNAME,
RPMTAG_CHANGELOGTEXT,
RPMTAG_URL,
RPMTAG_BUGURL,
RPMTAG_HEADERI18NTABLE,
0
};
static void initSourceHeader(rpmSpec spec)
{
Package sourcePkg = spec->sourcePackage;
struct Source *srcPtr;
if (headerIsEntry(sourcePkg->header, RPMTAG_NAME))
return;
/* Only specific tags are added to the source package header */
headerCopyTags(spec->packages->header, sourcePkg->header, sourceTags);
/* Add the build restrictions */
{
HeaderIterator hi = headerInitIterator(spec->buildRestrictions);
struct rpmtd_s td;
while (headerNext(hi, &td)) {
if (rpmtdCount(&td) > 0) {
(void) headerPut(sourcePkg->header, &td, HEADERPUT_DEFAULT);
}
rpmtdFreeData(&td);
}
headerFreeIterator(hi);
}
if (spec->BANames && spec->BACount > 0) {
headerPutStringArray(sourcePkg->header, RPMTAG_BUILDARCHS,
spec->BANames, spec->BACount);
}
/* Add tags for sources and patches */
for (srcPtr = spec->sources; srcPtr != NULL; srcPtr = srcPtr->next) {
if (srcPtr->flags & RPMBUILD_ISSOURCE) {
headerPutString(sourcePkg->header, RPMTAG_SOURCE, srcPtr->source);
if (srcPtr->flags & RPMBUILD_ISNO) {
headerPutUint32(sourcePkg->header, RPMTAG_NOSOURCE,
&srcPtr->num, 1);
}
}
if (srcPtr->flags & RPMBUILD_ISPATCH) {
headerPutString(sourcePkg->header, RPMTAG_PATCH, srcPtr->source);
if (srcPtr->flags & RPMBUILD_ISNO) {
headerPutUint32(sourcePkg->header, RPMTAG_NOPATCH,
&srcPtr->num, 1);
}
}
}
}
/* Add extra provides to package. */
static void addPackageProvides(Header h)
{
const char *arch, *name;
char *evr, *isaprov;
rpmsenseFlags pflags = RPMSENSE_EQUAL;
/* <name> = <evr> provide */
name = headerGetString(h, RPMTAG_NAME);
arch = headerGetString(h, RPMTAG_ARCH);
evr = headerGetAsString(h, RPMTAG_EVR);
headerPutString(h, RPMTAG_PROVIDENAME, name);
headerPutString(h, RPMTAG_PROVIDEVERSION, evr);
headerPutUint32(h, RPMTAG_PROVIDEFLAGS, &pflags, 1);
/*
* <name>(<isa>) = <evr> provide
* FIXME: noarch needs special casing for now as BuildArch: noarch doesn't
* cause reading in the noarch macros :-/
*/
isaprov = rpmExpand(name, "%{?_isa}", NULL);
if (!rstreq(arch, "noarch") && !rstreq(name, isaprov)) {
headerPutString(h, RPMTAG_PROVIDENAME, isaprov);
headerPutString(h, RPMTAG_PROVIDEVERSION, evr);
headerPutUint32(h, RPMTAG_PROVIDEFLAGS, &pflags, 1);
}
free(isaprov);
free(evr);
}
static void addTargets(Package Pkgs)
{
char *platform = rpmExpand("%{_target_platform}", NULL);
char *arch = rpmExpand("%{_target_cpu}", NULL);
char *os = rpmExpand("%{_target_os}", NULL);
char *optflags = rpmExpand("%{optflags}", NULL);
for (Package pkg = Pkgs; pkg != NULL; pkg = pkg->next) {
headerPutString(pkg->header, RPMTAG_OS, os);
/* noarch subpackages already have arch set here, leave it alone */
if (!headerIsEntry(pkg->header, RPMTAG_ARCH)) {
headerPutString(pkg->header, RPMTAG_ARCH, arch);
}
headerPutString(pkg->header, RPMTAG_PLATFORM, platform);
headerPutString(pkg->header, RPMTAG_OPTFLAGS, optflags);
pkg->ds = rpmdsThis(pkg->header, RPMTAG_REQUIRENAME, RPMSENSE_EQUAL);
addPackageProvides(pkg->header);
}
free(platform);
free(arch);
free(os);
free(optflags);
}
static rpmSpec parseSpec(const char *specFile, rpmSpecFlags flags,
const char *buildRoot, int recursing)
{
int parsePart = PART_PREAMBLE;
int initialPackage = 1;
2007-09-21 20:23:02 +08:00
rpmSpec spec;
/* Set up a new Spec structure with no packages. */
spec = newSpec();
spec->specFile = rpmGetPath(specFile, NULL);
pushOFI(spec, spec->specFile);
/* If buildRoot not specified, use default %{buildroot} */
if (buildRoot) {
spec->buildRoot = xstrdup(buildRoot);
} else {
spec->buildRoot = rpmGetPath("%{?buildroot:%{buildroot}}", NULL);
}
addMacro(NULL, "_docdir", NULL, "%{_defaultdocdir}", RMIL_SPEC);
addMacro(NULL, "_licensedir", NULL, "%{_defaultlicensedir}", RMIL_SPEC);
spec->recursing = recursing;
spec->flags = flags;
/* All the parse*() functions expect to have a line pre-read */
/* in the spec's line buffer. Except for parsePreamble(), */
/* which handles the initial entry into a spec file. */
while (parsePart != PART_NONE) {
int goterror = 0;
switch (parsePart) {
case PART_ERROR: /* fallthrough */
default:
goterror = 1;
break;
case PART_PREAMBLE:
parsePart = parsePreamble(spec, initialPackage);
initialPackage = 0;
2007-09-12 05:03:27 +08:00
break;
case PART_PREP:
parsePart = parsePrep(spec);
2007-09-12 05:03:27 +08:00
break;
case PART_BUILD:
case PART_INSTALL:
case PART_CHECK:
case PART_CLEAN:
parsePart = parseBuildInstallClean(spec, parsePart);
2007-09-12 05:03:27 +08:00
break;
case PART_CHANGELOG:
parsePart = parseChangelog(spec);
2007-09-12 05:03:27 +08:00
break;
case PART_DESCRIPTION:
parsePart = parseDescription(spec);
2007-09-12 05:03:27 +08:00
break;
case PART_PRE:
case PART_POST:
case PART_PREUN:
case PART_POSTUN:
case PART_PRETRANS:
case PART_POSTTRANS:
case PART_VERIFYSCRIPT:
case PART_TRIGGERPREIN:
case PART_TRIGGERIN:
case PART_TRIGGERUN:
case PART_TRIGGERPOSTUN:
parsePart = parseScript(spec, parsePart);
2007-09-12 05:03:27 +08:00
break;
case PART_FILES:
parsePart = parseFiles(spec);
2007-09-12 05:03:27 +08:00
break;
Add new %sepolicy section to the spec file format The %sepolicy section is used to describe SELinux policy to be included in a package. It's syntax is similar to other sections (%files, %pre, %post, etc.) in that you can provide a string and -n after the declaration to specify policy should be added to a subpackage. For example: %sepolicy # policy in this section will be added to the main package %sepolicy foo # policy in this section will be added to the '<mainpackage>-foo' subpackage %sepolicy -n bar # policy in this section will be added to the 'bar' subpackage The %sepolicy section contains zero or more %semodule directives, with the following format: %semodule [OPTIONS] path/to/module.pp The available options are: -b, --base The module is a base module -n, --name=NAME The name of the module. If not given, assumes the name is the basename of the module file with file extensions removed. -t, --types=TYPES One or more comma-separated strings specifying which policy types the module can work with. To explicitly state that a module can work with any policy type, "default" can be specified as the value. If not specified, assumes the module can work with any policy type, and assigns the types as "default". Below is an example of this new format: %sepolicy %semodule -n foo -t mls policy/foo.pp %semodule -n bar -t strict,targeted,mls -b policy/bar.pp This also adds new header tags to store the new information: RPMTAG_POLICYNAMES (string array) RPMTAG_POLICYTYPES (string array) RPMTAG_POLICYTYPESINDEXES (uint32 array) RPMTAG_POLICYFLAGS (uint32 array) The index of NAMES and FLAGS maps directly to the index of RPMTAG_POLICIES. However, because a single policy can have multiple types, the mapping for TYPES is not direct. For this, the index maps to TYPESINDEXES, which contains the index of the policy that the type maps to. This is similar to how DIRINDEXES is used to map DIRNAMES and BASENAMES. As an example, the previous %sepolicy section would have the following header tags: RPMTAG_POLICIES: 0: <foo.pp data, base64 encoded> 1: <bar.pp data, base64 encoded> RPMTAG_POLICYNAMES: 0: foo 1: bar RPMTAG_POLICYFLAGS: 0: 0 1: 1 # assumes flag 1 == BASE RPMTAG_POILCYTYPES: RPMTAG_POLICYTYPESINDEXES: 0: mls 0: 0 1: strict 1: 1 2: targeted 2: 1 3: mls 3: 1
2010-08-31 04:32:29 +08:00
case PART_POLICIES:
parsePart = parsePolicies(spec);
break;
case PART_NONE: /* XXX avoid gcc whining */
case PART_LAST:
case PART_BUILDARCHITECTURES:
2007-09-12 05:03:27 +08:00
break;
}
if (goterror || parsePart >= PART_LAST) {
goto errxit;
}
if (parsePart == PART_BUILDARCHITECTURES) {
int index;
int x;
closeSpec(spec);
spec->BASpecs = xcalloc(spec->BACount, sizeof(*spec->BASpecs));
index = 0;
if (spec->BANames != NULL)
for (x = 0; x < spec->BACount; x++) {
/* Skip if not arch is not compatible. */
if (!rpmMachineScore(RPM_MACHTABLE_BUILDARCH, spec->BANames[x]))
2007-09-12 05:03:27 +08:00
continue;
addMacro(NULL, "_target_cpu", NULL, spec->BANames[x], RMIL_RPMRC);
spec->BASpecs[index] = parseSpec(specFile, flags, buildRoot, 1);
if (spec->BASpecs[index] == NULL) {
spec->BACount = index;
goto errxit;
}
delMacro(NULL, "_target_cpu");
index++;
}
spec->BACount = index;
if (! index) {
rpmlog(RPMLOG_ERR,
_("No compatible architectures found for build\n"));
goto errxit;
}
/*
* Return the 1st child's fully parsed Spec structure.
* The restart of the parse when encountering BuildArch
* causes problems for "rpm -q --specfile". This is
* still a hack because there may be more than 1 arch
* specified (unlikely but possible.) There's also the
* further problem that the macro context, particularly
* %{_target_cpu}, disagrees with the info in the header.
*/
if (spec->BACount >= 1) {
2007-09-21 20:23:02 +08:00
rpmSpec nspec = spec->BASpecs[0];
spec->BASpecs = _free(spec->BASpecs);
rpmSpecFree(spec);
spec = nspec;
}
goto exit;
}
}
if (spec->clean == NULL) {
char *body = rpmExpand("%{?buildroot: %{__rm} -rf %{buildroot}}", NULL);
spec->clean = newStringBuf();
appendLineStringBuf(spec->clean, body);
free(body);
}
/* Check for description in each package */
for (Package pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
if (!headerIsEntry(pkg->header, RPMTAG_DESCRIPTION)) {
rpmlog(RPMLOG_ERR, _("Package has no %%description: %s\n"),
headerGetString(pkg->header, RPMTAG_NAME));
goto errxit;
}
}
/* Add arch, os and platform, self-provides etc for each package */
addTargets(spec->packages);
closeSpec(spec);
exit:
/* Assemble source header from parsed components */
initSourceHeader(spec);
return spec;
errxit:
rpmSpecFree(spec);
return NULL;
}
rpmSpec rpmSpecParse(const char *specFile, rpmSpecFlags flags,
const char *buildRoot)
{
return parseSpec(specFile, flags, buildRoot, 0);
}