|
|
2ff057 |
/** \ingroup rpmbuild
|
|
|
2ff057 |
* \file build/parseSpec.c
|
|
|
2ff057 |
* Top level dispatcher for spec file parsing.
|
|
|
2ff057 |
*/
|
|
|
2ff057 |
|
|
|
2ff057 |
#include "system.h"
|
|
|
2ff057 |
|
|
|
2ff057 |
#include <errno.h>
|
|
|
2ff057 |
#ifdef HAVE_ICONV
|
|
|
2ff057 |
#include <iconv.h>
|
|
|
2ff057 |
#endif
|
|
|
2ff057 |
|
|
|
2ff057 |
#include <rpm/rpmtypes.h>
|
|
|
2ff057 |
#include <rpm/rpmlib.h> /* RPM_MACHTABLE & related */
|
|
|
2ff057 |
#include <rpm/rpmds.h>
|
|
|
2ff057 |
#include <rpm/rpmts.h>
|
|
|
2ff057 |
#include <rpm/rpmlog.h>
|
|
|
2ff057 |
#include <rpm/rpmfileutil.h>
|
|
|
2ff057 |
#include "build/rpmbuild_internal.h"
|
|
|
2ff057 |
#include "build/rpmbuild_misc.h"
|
|
|
2ff057 |
#include "debug.h"
|
|
|
2ff057 |
|
|
|
2ff057 |
#define SKIPSPACE(s) { while (*(s) && risspace(*(s))) (s)++; }
|
|
|
2ff057 |
#define SKIPNONSPACE(s) { while (*(s) && !risspace(*(s))) (s)++; }
|
|
|
2ff057 |
#define ISMACRO(s,m) (rstreqn((s), (m), sizeof((m))-1) && !risalpha((s)[sizeof((m))-1]))
|
|
|
2ff057 |
#define ISMACROWITHARG(s,m) (rstreqn((s), (m), sizeof((m))-1) && (risblank((s)[sizeof((m))-1]) || !(s)[sizeof((m))-1]))
|
|
|
2ff057 |
|
|
|
2ff057 |
#define LEN_AND_STR(_tag) (sizeof(_tag)-1), (_tag)
|
|
|
2ff057 |
|
|
|
2ff057 |
typedef struct OpenFileInfo {
|
|
|
2ff057 |
char * fileName;
|
|
|
2ff057 |
FILE *fp;
|
|
|
2ff057 |
int lineNum;
|
|
|
2ff057 |
char *readBuf;
|
|
|
2ff057 |
size_t readBufLen;
|
|
|
2ff057 |
const char * readPtr;
|
|
|
2ff057 |
struct OpenFileInfo * next;
|
|
|
2ff057 |
} OFI_t;
|
|
|
2ff057 |
|
|
|
2ff057 |
static const struct PartRec {
|
|
|
2ff057 |
int part;
|
|
|
2ff057 |
size_t len;
|
|
|
2ff057 |
const char * token;
|
|
|
2ff057 |
} partList[] = {
|
|
|
2ff057 |
{ PART_PREAMBLE, LEN_AND_STR("%package")},
|
|
|
2ff057 |
{ PART_PREP, LEN_AND_STR("%prep")},
|
|
|
2ff057 |
{ PART_BUILD, LEN_AND_STR("%build")},
|
|
|
2ff057 |
{ PART_INSTALL, LEN_AND_STR("%install")},
|
|
|
2ff057 |
{ PART_CHECK, LEN_AND_STR("%check")},
|
|
|
2ff057 |
{ PART_CLEAN, LEN_AND_STR("%clean")},
|
|
|
2ff057 |
{ PART_PREUN, LEN_AND_STR("%preun")},
|
|
|
2ff057 |
{ PART_POSTUN, LEN_AND_STR("%postun")},
|
|
|
2ff057 |
{ PART_PRETRANS, LEN_AND_STR("%pretrans")},
|
|
|
2ff057 |
{ PART_POSTTRANS, LEN_AND_STR("%posttrans")},
|
|
|
2ff057 |
{ PART_PRE, LEN_AND_STR("%pre")},
|
|
|
2ff057 |
{ PART_POST, LEN_AND_STR("%post")},
|
|
|
2ff057 |
{ PART_FILES, LEN_AND_STR("%files")},
|
|
|
2ff057 |
{ PART_CHANGELOG, LEN_AND_STR("%changelog")},
|
|
|
2ff057 |
{ PART_DESCRIPTION, LEN_AND_STR("%description")},
|
|
|
2ff057 |
{ PART_TRIGGERPOSTUN, LEN_AND_STR("%triggerpostun")},
|
|
|
2ff057 |
{ PART_TRIGGERPREIN, LEN_AND_STR("%triggerprein")},
|
|
|
2ff057 |
{ PART_TRIGGERUN, LEN_AND_STR("%triggerun")},
|
|
|
2ff057 |
{ PART_TRIGGERIN, LEN_AND_STR("%triggerin")},
|
|
|
2ff057 |
{ PART_TRIGGERIN, LEN_AND_STR("%trigger")},
|
|
|
2ff057 |
{ PART_VERIFYSCRIPT, LEN_AND_STR("%verifyscript")},
|
|
|
2ff057 |
{ PART_POLICIES, LEN_AND_STR("%sepolicy")},
|
|
|
2ff057 |
{ PART_FILETRIGGERIN, LEN_AND_STR("%filetriggerin")},
|
|
|
2ff057 |
{ PART_FILETRIGGERIN, LEN_AND_STR("%filetrigger")},
|
|
|
2ff057 |
{ PART_FILETRIGGERUN, LEN_AND_STR("%filetriggerun")},
|
|
|
2ff057 |
{ PART_FILETRIGGERPOSTUN, LEN_AND_STR("%filetriggerpostun")},
|
|
|
2ff057 |
{ PART_TRANSFILETRIGGERIN, LEN_AND_STR("%transfiletriggerin")},
|
|
|
2ff057 |
{ PART_TRANSFILETRIGGERIN, LEN_AND_STR("%transfiletrigger")},
|
|
|
2ff057 |
{ PART_TRANSFILETRIGGERUN, LEN_AND_STR("%transfiletriggerun")},
|
|
|
2ff057 |
{ PART_TRANSFILETRIGGERUN, LEN_AND_STR("%transfiletriggerun")},
|
|
|
2ff057 |
{ PART_TRANSFILETRIGGERPOSTUN, LEN_AND_STR("%transfiletriggerpostun")},
|
|
|
2ff057 |
{ PART_EMPTY, LEN_AND_STR("%end")},
|
|
|
2ff057 |
{0, 0, 0}
|
|
|
2ff057 |
};
|
|
|
2ff057 |
|
|
|
2ff057 |
int isPart(const char *line)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
const struct PartRec *p;
|
|
|
2ff057 |
|
|
|
2ff057 |
for (p = partList; p->token != NULL; p++) {
|
|
|
2ff057 |
char c;
|
|
|
2ff057 |
if (rstrncasecmp(line, p->token, p->len))
|
|
|
2ff057 |
continue;
|
|
|
2ff057 |
c = *(line + p->len);
|
|
|
2ff057 |
if (c == '\0' || risspace(c))
|
|
|
2ff057 |
break;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
return (p->token ? p->part : PART_NONE);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
/**
|
|
|
2ff057 |
*/
|
|
|
2ff057 |
static int matchTok(const char *token, const char *line)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
const char *b, *be = line;
|
|
|
2ff057 |
size_t toklen = strlen(token);
|
|
|
2ff057 |
int rc = 0;
|
|
|
2ff057 |
|
|
|
2ff057 |
while ( *(b = be) != '\0' ) {
|
|
|
2ff057 |
SKIPSPACE(b);
|
|
|
2ff057 |
be = b;
|
|
|
2ff057 |
SKIPNONSPACE(be);
|
|
|
2ff057 |
if (be == b)
|
|
|
2ff057 |
break;
|
|
|
2ff057 |
if (toklen != (be-b) || rstrncasecmp(token, b, (be-b)))
|
|
|
2ff057 |
continue;
|
|
|
2ff057 |
rc = 1;
|
|
|
2ff057 |
break;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
return rc;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
int handleComments(char *s)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
SKIPSPACE(s);
|
|
|
2ff057 |
if (*s == '#') {
|
|
|
2ff057 |
*s = '\0';
|
|
|
2ff057 |
return 1;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
return 0;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
/* Push a file to spec's file stack, return the newly pushed entry */
|
|
|
2ff057 |
static OFI_t * pushOFI(rpmSpec spec, const char *fn)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
OFI_t *ofi = xcalloc(1, sizeof(*ofi));
|
|
|
2ff057 |
|
|
|
2ff057 |
ofi->fp = NULL;
|
|
|
2ff057 |
ofi->fileName = xstrdup(fn);
|
|
|
2ff057 |
ofi->lineNum = 0;
|
|
|
2ff057 |
ofi->readBufLen = BUFSIZ;
|
|
|
2ff057 |
ofi->readBuf = xmalloc(ofi->readBufLen);
|
|
|
2ff057 |
ofi->readBuf[0] = '\0';
|
|
|
2ff057 |
ofi->readPtr = NULL;
|
|
|
2ff057 |
ofi->next = spec->fileStack;
|
|
|
2ff057 |
|
|
|
2ff057 |
spec->fileStack = ofi;
|
|
|
2ff057 |
return spec->fileStack;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
/* Pop from spec's file stack */
|
|
|
2ff057 |
static OFI_t * popOFI(rpmSpec spec)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
if (spec->fileStack) {
|
|
|
2ff057 |
OFI_t * ofi = spec->fileStack;
|
|
|
2ff057 |
|
|
|
2ff057 |
spec->fileStack = ofi->next;
|
|
|
2ff057 |
if (ofi->fp)
|
|
|
2ff057 |
fclose(ofi->fp);
|
|
|
2ff057 |
free(ofi->fileName);
|
|
|
2ff057 |
free(ofi->readBuf);
|
|
|
2ff057 |
free(ofi);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
return spec->fileStack;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
static int restoreFirstChar(rpmSpec spec)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
/* Restore 1st char in (possible) next line */
|
|
|
2ff057 |
if (spec->nextline != NULL && spec->nextpeekc != '\0') {
|
|
|
2ff057 |
*spec->nextline = spec->nextpeekc;
|
|
|
2ff057 |
spec->nextpeekc = '\0';
|
|
|
2ff057 |
return 1;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
return 0;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
static int expandMacrosInSpecBuf(rpmSpec spec, int strip)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
char *lbuf = NULL;
|
|
|
2ff057 |
int isComment = 0;
|
|
|
2ff057 |
|
|
|
2ff057 |
/* Don't expand macros (eg. %define) in false branch of %if clause */
|
|
|
2ff057 |
if (!spec->readStack->reading)
|
|
|
2ff057 |
return 0;
|
|
|
2ff057 |
|
|
|
2ff057 |
lbuf = spec->lbuf;
|
|
|
2ff057 |
SKIPSPACE(lbuf);
|
|
|
2ff057 |
if (lbuf[0] == '#')
|
|
|
2ff057 |
isComment = 1;
|
|
|
2ff057 |
|
|
|
2ff057 |
|
|
|
2ff057 |
if (rpmExpandMacros(spec->macros, spec->lbuf, &lbuf, 0) < 0) {
|
|
|
2ff057 |
rpmlog(RPMLOG_ERR, _("line %d: %s\n"),
|
|
|
2ff057 |
spec->lineNum, spec->lbuf);
|
|
|
2ff057 |
return 1;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
if (strip & STRIP_COMMENTS && isComment) {
|
|
|
2ff057 |
char *bufA = spec->lbuf;
|
|
|
2ff057 |
char *bufB = lbuf;
|
|
|
2ff057 |
|
|
|
2ff057 |
while (*bufA != '\0' && *bufB != '\0') {
|
|
|
2ff057 |
if (*bufA == '%' && *(bufA + 1) == '%')
|
|
|
2ff057 |
bufA++;
|
|
|
2ff057 |
|
|
|
2ff057 |
if (*bufA != *bufB)
|
|
|
2ff057 |
break;
|
|
|
2ff057 |
|
|
|
2ff057 |
bufA++;
|
|
|
2ff057 |
bufB++;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
if (*bufA != '\0' || *bufB != '\0')
|
|
|
2ff057 |
rpmlog(RPMLOG_WARNING,
|
|
|
2ff057 |
_("Macro expanded in comment on line %d: %s\n"),
|
|
|
2ff057 |
spec->lineNum, bufA);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
free(spec->lbuf);
|
|
|
2ff057 |
spec->lbuf = lbuf;
|
|
|
2ff057 |
spec->lbufSize = strlen(spec->lbuf) + 1;
|
|
|
2ff057 |
|
|
|
2ff057 |
return 0;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
/* Return zero on success, 1 if we need to read more and -1 on errors. */
|
|
|
2ff057 |
static int copyNextLineFromOFI(rpmSpec spec, OFI_t *ofi, int strip)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
/* Expand next line from file into line buffer */
|
|
|
2ff057 |
if (!(spec->nextline && *spec->nextline)) {
|
|
|
2ff057 |
int pc = 0, bc = 0, nc = 0;
|
|
|
2ff057 |
const char *from = ofi->readPtr;
|
|
|
2ff057 |
char ch = ' ';
|
|
|
2ff057 |
while (from && *from && ch != '\n') {
|
|
|
2ff057 |
ch = spec->lbuf[spec->lbufOff] = *from;
|
|
|
2ff057 |
spec->lbufOff++; from++;
|
|
|
2ff057 |
|
|
|
2ff057 |
if (spec->lbufOff >= spec->lbufSize) {
|
|
|
2ff057 |
spec->lbufSize += BUFSIZ;
|
|
|
2ff057 |
spec->lbuf = realloc(spec->lbuf, spec->lbufSize);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
}
|
|
|
2ff057 |
spec->lbuf[spec->lbufOff] = '\0';
|
|
|
2ff057 |
ofi->readPtr = from;
|
|
|
2ff057 |
|
|
|
2ff057 |
/* Check if we need another line before expanding the buffer. */
|
|
|
2ff057 |
for (const char *p = spec->lbuf; *p; p++) {
|
|
|
2ff057 |
switch (*p) {
|
|
|
2ff057 |
case '\\':
|
|
|
2ff057 |
switch (*(p+1)) {
|
|
|
2ff057 |
case '\n': p++, nc = 1; break;
|
|
|
2ff057 |
case '\0': break;
|
|
|
2ff057 |
default: p++; break;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
break;
|
|
|
2ff057 |
case '\n': nc = 0; break;
|
|
|
2ff057 |
case '%':
|
|
|
2ff057 |
switch (*(p+1)) {
|
|
|
2ff057 |
case '{': p++, bc++; break;
|
|
|
2ff057 |
case '(': p++, pc++; break;
|
|
|
2ff057 |
case '%': p++; break;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
break;
|
|
|
2ff057 |
case '{': if (bc > 0) bc++; break;
|
|
|
2ff057 |
case '}': if (bc > 0) bc--; break;
|
|
|
2ff057 |
case '(': if (pc > 0) pc++; break;
|
|
|
2ff057 |
case ')': if (pc > 0) pc--; break;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
/* If it doesn't, ask for one more line. */
|
|
|
2ff057 |
if (pc || bc || nc ) {
|
|
|
2ff057 |
spec->nextline = "";
|
|
|
2ff057 |
return 1;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
spec->lbufOff = 0;
|
|
|
2ff057 |
|
|
|
2ff057 |
if (expandMacrosInSpecBuf(spec, strip))
|
|
|
2ff057 |
return -1;
|
|
|
2ff057 |
|
|
|
2ff057 |
spec->nextline = spec->lbuf;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
return 0;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
static void copyNextLineFinish(rpmSpec spec, int strip)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
char *last;
|
|
|
2ff057 |
char ch;
|
|
|
2ff057 |
|
|
|
2ff057 |
/* Find next line in expanded line buffer */
|
|
|
2ff057 |
spec->line = last = spec->nextline;
|
|
|
2ff057 |
ch = ' ';
|
|
|
2ff057 |
while (*spec->nextline && ch != '\n') {
|
|
|
2ff057 |
ch = *spec->nextline++;
|
|
|
2ff057 |
if (!risspace(ch))
|
|
|
2ff057 |
last = spec->nextline;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
/* Save 1st char of next line in order to terminate current line. */
|
|
|
2ff057 |
if (*spec->nextline != '\0') {
|
|
|
2ff057 |
spec->nextpeekc = *spec->nextline;
|
|
|
2ff057 |
*spec->nextline = '\0';
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
if (strip & STRIP_COMMENTS)
|
|
|
2ff057 |
handleComments(spec->line);
|
|
|
2ff057 |
|
|
|
2ff057 |
if (strip & STRIP_TRAILINGSPACE)
|
|
|
2ff057 |
*last = '\0';
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
static int readLineFromOFI(rpmSpec spec, OFI_t *ofi)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
retry:
|
|
|
2ff057 |
/* Make sure the current file is open */
|
|
|
2ff057 |
if (ofi->fp == NULL) {
|
|
|
2ff057 |
ofi->fp = fopen(ofi->fileName, "r");
|
|
|
2ff057 |
if (ofi->fp == NULL) {
|
|
|
2ff057 |
rpmlog(RPMLOG_ERR, _("Unable to open %s: %s\n"),
|
|
|
2ff057 |
ofi->fileName, strerror(errno));
|
|
|
2ff057 |
return PART_ERROR;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
spec->lineNum = ofi->lineNum = 0;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
/* Make sure we have something in the read buffer */
|
|
|
2ff057 |
if (!(ofi->readPtr && *(ofi->readPtr))) {
|
|
|
2ff057 |
if (getline(&ofi->readBuf, &ofi->readBufLen, ofi->fp) <= 0) {
|
|
|
2ff057 |
/* EOF, remove this file from the stack */
|
|
|
2ff057 |
ofi = popOFI(spec);
|
|
|
2ff057 |
|
|
|
2ff057 |
/* only on last file do we signal EOF to caller */
|
|
|
2ff057 |
if (ofi == NULL)
|
|
|
2ff057 |
return 1;
|
|
|
2ff057 |
|
|
|
2ff057 |
/* otherwise, go back and try the read again. */
|
|
|
2ff057 |
goto retry;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
ofi->readPtr = ofi->readBuf;
|
|
|
2ff057 |
ofi->lineNum++;
|
|
|
2ff057 |
spec->lineNum = ofi->lineNum;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
return 0;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
#define ARGMATCH(s,token,match) \
|
|
|
2ff057 |
do { \
|
|
|
2ff057 |
char *os = s; \
|
|
|
2ff057 |
char *exp = rpmExpand(token, NULL); \
|
|
|
2ff057 |
while (*s && !risblank(*s)) s++; \
|
|
|
2ff057 |
while (*s && risblank(*s)) s++; \
|
|
|
2ff057 |
if (!*s) { \
|
|
|
2ff057 |
rpmlog(RPMLOG_ERR, _("%s:%d: Argument expected for %s\n"), ofi->fileName, ofi->lineNum, os); \
|
|
|
2ff057 |
free(exp); \
|
|
|
2ff057 |
return PART_ERROR; \
|
|
|
2ff057 |
} \
|
|
|
2ff057 |
match = matchTok(exp, s); \
|
|
|
2ff057 |
free(exp); \
|
|
|
2ff057 |
} while (0)
|
|
|
2ff057 |
|
|
|
2ff057 |
|
|
|
2ff057 |
int readLine(rpmSpec spec, int strip)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
char *s;
|
|
|
2ff057 |
int match;
|
|
|
2ff057 |
struct ReadLevelEntry *rl;
|
|
|
2ff057 |
OFI_t *ofi = spec->fileStack;
|
|
|
2ff057 |
int rc;
|
|
|
2ff057 |
int startLine = 0;
|
|
|
2ff057 |
|
|
|
2ff057 |
if (!restoreFirstChar(spec)) {
|
|
|
2ff057 |
retry:
|
|
|
2ff057 |
if ((rc = readLineFromOFI(spec, ofi)) != 0) {
|
|
|
2ff057 |
if (spec->readStack->next) {
|
|
|
2ff057 |
rpmlog(RPMLOG_ERR, _("line %d: Unclosed %%if\n"),
|
|
|
2ff057 |
spec->readStack->lineNum);
|
|
|
2ff057 |
rc = PART_ERROR;
|
|
|
2ff057 |
} else if (startLine > 0) {
|
|
|
2ff057 |
rpmlog(RPMLOG_ERR,
|
|
|
2ff057 |
_("line %d: unclosed macro or bad line continuation\n"),
|
|
|
2ff057 |
startLine);
|
|
|
2ff057 |
rc = PART_ERROR;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
return rc;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
ofi = spec->fileStack;
|
|
|
2ff057 |
|
|
|
2ff057 |
/* Copy next file line into the spec line buffer */
|
|
|
2ff057 |
rc = copyNextLineFromOFI(spec, ofi, strip);
|
|
|
2ff057 |
if (rc > 0) {
|
|
|
2ff057 |
if (startLine == 0)
|
|
|
2ff057 |
startLine = spec->lineNum;
|
|
|
2ff057 |
goto retry;
|
|
|
2ff057 |
} else if (rc < 0) {
|
|
|
2ff057 |
return PART_ERROR;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
copyNextLineFinish(spec, strip);
|
|
|
2ff057 |
|
|
|
2ff057 |
s = spec->line;
|
|
|
2ff057 |
SKIPSPACE(s);
|
|
|
2ff057 |
|
|
|
2ff057 |
match = -1;
|
|
|
2ff057 |
if (!spec->readStack->reading && ISMACROWITHARG(s, "%if")) {
|
|
|
2ff057 |
match = 0;
|
|
|
2ff057 |
} else if (ISMACROWITHARG(s, "%ifarch")) {
|
|
|
2ff057 |
ARGMATCH(s, "%{_target_cpu}", match);
|
|
|
2ff057 |
} else if (ISMACROWITHARG(s, "%ifnarch")) {
|
|
|
2ff057 |
ARGMATCH(s, "%{_target_cpu}", match);
|
|
|
2ff057 |
match = !match;
|
|
|
2ff057 |
} else if (ISMACROWITHARG(s, "%ifos")) {
|
|
|
2ff057 |
ARGMATCH(s, "%{_target_os}", match);
|
|
|
2ff057 |
} else if (ISMACROWITHARG(s, "%ifnos")) {
|
|
|
2ff057 |
ARGMATCH(s, "%{_target_os}", match);
|
|
|
2ff057 |
match = !match;
|
|
|
2ff057 |
} else if (ISMACROWITHARG(s, "%if")) {
|
|
|
2ff057 |
s += 3;
|
|
|
2ff057 |
match = parseExpressionBoolean(s);
|
|
|
2ff057 |
if (match < 0) {
|
|
|
2ff057 |
rpmlog(RPMLOG_ERR,
|
|
|
2ff057 |
_("%s:%d: bad %%if condition\n"),
|
|
|
2ff057 |
ofi->fileName, ofi->lineNum);
|
|
|
2ff057 |
return PART_ERROR;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
} else if (ISMACRO(s, "%else")) {
|
|
|
2ff057 |
if (! spec->readStack->next) {
|
|
|
2ff057 |
/* Got an else with no %if ! */
|
|
|
2ff057 |
rpmlog(RPMLOG_ERR,
|
|
|
2ff057 |
_("%s:%d: Got a %%else with no %%if\n"),
|
|
|
2ff057 |
ofi->fileName, ofi->lineNum);
|
|
|
2ff057 |
return PART_ERROR;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
spec->readStack->reading =
|
|
|
2ff057 |
spec->readStack->next->reading && ! spec->readStack->reading;
|
|
|
2ff057 |
spec->line[0] = '\0';
|
|
|
2ff057 |
} else if (ISMACRO(s, "%endif")) {
|
|
|
2ff057 |
if (! spec->readStack->next) {
|
|
|
2ff057 |
/* Got an end with no %if ! */
|
|
|
2ff057 |
rpmlog(RPMLOG_ERR,
|
|
|
2ff057 |
_("%s:%d: Got a %%endif with no %%if\n"),
|
|
|
2ff057 |
ofi->fileName, ofi->lineNum);
|
|
|
2ff057 |
return PART_ERROR;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
rl = spec->readStack;
|
|
|
2ff057 |
spec->readStack = spec->readStack->next;
|
|
|
2ff057 |
free(rl);
|
|
|
2ff057 |
spec->line[0] = '\0';
|
|
|
2ff057 |
} else if (spec->readStack->reading && ISMACROWITHARG(s, "%include")) {
|
|
|
2ff057 |
char *fileName, *endFileName, *p;
|
|
|
2ff057 |
|
|
|
2ff057 |
fileName = s+8;
|
|
|
2ff057 |
SKIPSPACE(fileName);
|
|
|
2ff057 |
endFileName = fileName;
|
|
|
2ff057 |
do {
|
|
|
2ff057 |
SKIPNONSPACE(endFileName);
|
|
|
2ff057 |
p = endFileName;
|
|
|
2ff057 |
SKIPSPACE(p);
|
|
|
2ff057 |
if (*p != '\0') endFileName = p;
|
|
|
2ff057 |
} while (*p != '\0');
|
|
|
2ff057 |
if (*fileName == '\0') {
|
|
|
2ff057 |
rpmlog(RPMLOG_ERR, _("%s:%d: malformed %%include statement\n"),
|
|
|
2ff057 |
ofi->fileName, ofi->lineNum);
|
|
|
2ff057 |
return PART_ERROR;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
*endFileName = '\0';
|
|
|
2ff057 |
|
|
|
2ff057 |
ofi = pushOFI(spec, fileName);
|
|
|
2ff057 |
goto retry;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
if (match != -1) {
|
|
|
2ff057 |
rl = xmalloc(sizeof(*rl));
|
|
|
2ff057 |
rl->reading = spec->readStack->reading && match;
|
|
|
2ff057 |
rl->next = spec->readStack;
|
|
|
2ff057 |
rl->lineNum = ofi->lineNum;
|
|
|
2ff057 |
spec->readStack = rl;
|
|
|
2ff057 |
spec->line[0] = '\0';
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
if (! spec->readStack->reading) {
|
|
|
2ff057 |
spec->line[0] = '\0';
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
/* Collect parsed line */
|
|
|
2ff057 |
if (spec->parsed == NULL)
|
|
|
2ff057 |
spec->parsed = newStringBuf();
|
|
|
2ff057 |
appendStringBufAux(spec->parsed, spec->line,(strip & STRIP_TRAILINGSPACE));
|
|
|
2ff057 |
|
|
|
2ff057 |
/* FIX: spec->readStack->next should be dependent */
|
|
|
2ff057 |
return 0;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
void closeSpec(rpmSpec spec)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
while (popOFI(spec)) {};
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
static const rpmTagVal sourceTags[] = {
|
|
|
2ff057 |
RPMTAG_NAME,
|
|
|
2ff057 |
RPMTAG_VERSION,
|
|
|
2ff057 |
RPMTAG_RELEASE,
|
|
|
2ff057 |
RPMTAG_EPOCH,
|
|
|
2ff057 |
RPMTAG_SUMMARY,
|
|
|
2ff057 |
RPMTAG_DESCRIPTION,
|
|
|
2ff057 |
RPMTAG_PACKAGER,
|
|
|
2ff057 |
RPMTAG_DISTRIBUTION,
|
|
|
2ff057 |
RPMTAG_DISTURL,
|
|
|
2ff057 |
RPMTAG_DISTTAG,
|
|
|
2ff057 |
RPMTAG_VENDOR,
|
|
|
2ff057 |
RPMTAG_LICENSE,
|
|
|
2ff057 |
RPMTAG_GROUP,
|
|
|
2ff057 |
RPMTAG_OS,
|
|
|
2ff057 |
RPMTAG_ARCH,
|
|
|
2ff057 |
RPMTAG_CHANGELOGTIME,
|
|
|
2ff057 |
RPMTAG_CHANGELOGNAME,
|
|
|
2ff057 |
RPMTAG_CHANGELOGTEXT,
|
|
|
2ff057 |
RPMTAG_URL,
|
|
|
2ff057 |
RPMTAG_BUGURL,
|
|
|
2ff057 |
RPMTAG_HEADERI18NTABLE,
|
|
|
2ff057 |
RPMTAG_VCS,
|
|
|
2ff057 |
0
|
|
|
2ff057 |
};
|
|
|
2ff057 |
|
|
|
2ff057 |
static void initSourceHeader(rpmSpec spec)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
Package sourcePkg = spec->sourcePackage;
|
|
|
2ff057 |
struct Source *srcPtr;
|
|
|
2ff057 |
|
|
|
2ff057 |
if (headerIsEntry(sourcePkg->header, RPMTAG_NAME))
|
|
|
2ff057 |
return;
|
|
|
2ff057 |
|
|
|
2ff057 |
/* Only specific tags are added to the source package header */
|
|
|
2ff057 |
headerCopyTags(spec->packages->header, sourcePkg->header, sourceTags);
|
|
|
2ff057 |
|
|
|
2ff057 |
/* Add the build restrictions */
|
|
|
2ff057 |
for (int i=0; i
|
|
|
2ff057 |
rpmdsPutToHeader(sourcePkg->dependencies[i], sourcePkg->header);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
{
|
|
|
2ff057 |
HeaderIterator hi = headerInitIterator(spec->buildRestrictions);
|
|
|
2ff057 |
struct rpmtd_s td;
|
|
|
2ff057 |
while (headerNext(hi, &td)) {
|
|
|
2ff057 |
if (rpmtdCount(&td) > 0) {
|
|
|
2ff057 |
(void) headerPut(sourcePkg->header, &td, HEADERPUT_DEFAULT);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
rpmtdFreeData(&td);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
headerFreeIterator(hi);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
if (spec->BANames && spec->BACount > 0) {
|
|
|
2ff057 |
headerPutStringArray(sourcePkg->header, RPMTAG_BUILDARCHS,
|
|
|
2ff057 |
spec->BANames, spec->BACount);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
/* Add tags for sources and patches */
|
|
|
2ff057 |
for (srcPtr = spec->sources; srcPtr != NULL; srcPtr = srcPtr->next) {
|
|
|
2ff057 |
if (srcPtr->flags & RPMBUILD_ISSOURCE) {
|
|
|
2ff057 |
headerPutString(sourcePkg->header, RPMTAG_SOURCE, srcPtr->source);
|
|
|
2ff057 |
if (srcPtr->flags & RPMBUILD_ISNO) {
|
|
|
2ff057 |
headerPutUint32(sourcePkg->header, RPMTAG_NOSOURCE,
|
|
|
2ff057 |
&srcPtr->num, 1);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
}
|
|
|
2ff057 |
if (srcPtr->flags & RPMBUILD_ISPATCH) {
|
|
|
2ff057 |
headerPutString(sourcePkg->header, RPMTAG_PATCH, srcPtr->source);
|
|
|
2ff057 |
if (srcPtr->flags & RPMBUILD_ISNO) {
|
|
|
2ff057 |
headerPutUint32(sourcePkg->header, RPMTAG_NOPATCH,
|
|
|
2ff057 |
&srcPtr->num, 1);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
}
|
|
|
2ff057 |
}
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
/* Add extra provides to package. */
|
|
|
2ff057 |
void addPackageProvides(Package pkg)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
const char *arch, *name;
|
|
|
2ff057 |
char *evr, *isaprov;
|
|
|
2ff057 |
rpmsenseFlags pflags = RPMSENSE_EQUAL;
|
|
|
2ff057 |
|
|
|
2ff057 |
/* <name> = <evr> provide */
|
|
|
2ff057 |
name = headerGetString(pkg->header, RPMTAG_NAME);
|
|
|
2ff057 |
arch = headerGetString(pkg->header, RPMTAG_ARCH);
|
|
|
2ff057 |
evr = headerGetAsString(pkg->header, RPMTAG_EVR);
|
|
|
2ff057 |
addReqProv(pkg, RPMTAG_PROVIDENAME, name, evr, pflags, 0);
|
|
|
2ff057 |
|
|
|
2ff057 |
/*
|
|
|
2ff057 |
* <name>(<isa>) = <evr> provide
|
|
|
2ff057 |
* FIXME: noarch needs special casing for now as BuildArch: noarch doesn't
|
|
|
2ff057 |
* cause reading in the noarch macros :-/
|
|
|
2ff057 |
*/
|
|
|
2ff057 |
isaprov = rpmExpand(name, "%{?_isa}", NULL);
|
|
|
2ff057 |
if (!rstreq(arch, "noarch") && !rstreq(name, isaprov)) {
|
|
|
2ff057 |
addReqProv(pkg, RPMTAG_PROVIDENAME, isaprov, evr, pflags, 0);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
free(isaprov);
|
|
|
2ff057 |
free(evr);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
static void addTargets(Package Pkgs)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
char *platform = rpmExpand("%{_target_platform}", NULL);
|
|
|
2ff057 |
char *arch = rpmExpand("%{_target_cpu}", NULL);
|
|
|
2ff057 |
char *os = rpmExpand("%{_target_os}", NULL);
|
|
|
2ff057 |
char *optflags = rpmExpand("%{optflags}", NULL);
|
|
|
2ff057 |
|
|
|
2ff057 |
for (Package pkg = Pkgs; pkg != NULL; pkg = pkg->next) {
|
|
|
2ff057 |
headerPutString(pkg->header, RPMTAG_OS, os);
|
|
|
2ff057 |
/* noarch subpackages already have arch set here, leave it alone */
|
|
|
2ff057 |
if (!headerIsEntry(pkg->header, RPMTAG_ARCH)) {
|
|
|
2ff057 |
headerPutString(pkg->header, RPMTAG_ARCH, arch);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
headerPutString(pkg->header, RPMTAG_PLATFORM, platform);
|
|
|
2ff057 |
headerPutString(pkg->header, RPMTAG_OPTFLAGS, optflags);
|
|
|
2ff057 |
|
|
|
2ff057 |
/* Add manual dependencies early for rpmspec etc to look at */
|
|
|
2ff057 |
addPackageProvides(pkg);
|
|
|
2ff057 |
for (int i=0; i
|
|
|
2ff057 |
rpmdsPutToHeader(pkg->dependencies[i], pkg->header);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
pkg->ds = rpmdsThis(pkg->header, RPMTAG_REQUIRENAME, RPMSENSE_EQUAL);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
free(platform);
|
|
|
2ff057 |
free(arch);
|
|
|
2ff057 |
free(os);
|
|
|
2ff057 |
free(optflags);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
rpmRC checkForEncoding(Header h, int addtag)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
rpmRC rc = RPMRC_OK;
|
|
|
2ff057 |
#if HAVE_ICONV
|
|
|
2ff057 |
const char *encoding = "utf-8";
|
|
|
2ff057 |
rpmTagVal tag;
|
|
|
2ff057 |
iconv_t ic;
|
|
|
2ff057 |
char *dest = NULL;
|
|
|
2ff057 |
size_t destlen = 0;
|
|
|
2ff057 |
int strict = rpmExpandNumeric("%{_invalid_encoding_terminates_build}");
|
|
|
2ff057 |
HeaderIterator hi = headerInitIterator(h);
|
|
|
2ff057 |
|
|
|
2ff057 |
ic = iconv_open(encoding, encoding);
|
|
|
2ff057 |
if (ic == (iconv_t) -1) {
|
|
|
2ff057 |
rpmlog(RPMLOG_WARNING,
|
|
|
2ff057 |
_("encoding %s not supported by system\n"), encoding);
|
|
|
2ff057 |
goto exit;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
while ((tag = headerNextTag(hi)) != RPMTAG_NOT_FOUND) {
|
|
|
2ff057 |
struct rpmtd_s td;
|
|
|
2ff057 |
const char *src = NULL;
|
|
|
2ff057 |
|
|
|
2ff057 |
if (rpmTagGetClass(tag) != RPM_STRING_CLASS)
|
|
|
2ff057 |
continue;
|
|
|
2ff057 |
|
|
|
2ff057 |
headerGet(h, tag, &td, (HEADERGET_RAW|HEADERGET_MINMEM));
|
|
|
2ff057 |
while ((src = rpmtdNextString(&td)) != NULL) {
|
|
|
2ff057 |
size_t srclen = strlen(src);
|
|
|
2ff057 |
size_t outlen, inlen = srclen;
|
|
|
2ff057 |
char *out, *in = (char *) src;
|
|
|
2ff057 |
|
|
|
2ff057 |
if (destlen < srclen) {
|
|
|
2ff057 |
destlen = srclen * 2;
|
|
|
2ff057 |
dest = xrealloc(dest, destlen);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
out = dest;
|
|
|
2ff057 |
outlen = destlen;
|
|
|
2ff057 |
|
|
|
2ff057 |
/* reset conversion state */
|
|
|
2ff057 |
iconv(ic, NULL, &inlen, &out, &outlen);
|
|
|
2ff057 |
|
|
|
2ff057 |
if (iconv(ic, &in, &inlen, &out, &outlen) == (size_t) -1) {
|
|
|
2ff057 |
rpmlog(strict ? RPMLOG_ERR : RPMLOG_WARNING,
|
|
|
2ff057 |
_("Package %s: invalid %s encoding in %s: %s - %s\n"),
|
|
|
2ff057 |
headerGetString(h, RPMTAG_NAME),
|
|
|
2ff057 |
encoding, rpmTagGetName(tag), src, strerror(errno));
|
|
|
2ff057 |
rc = RPMRC_FAIL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
}
|
|
|
2ff057 |
rpmtdFreeData(&td);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
/* Stomp "known good utf" mark in header if requested */
|
|
|
2ff057 |
if (rc == RPMRC_OK && addtag)
|
|
|
2ff057 |
headerPutString(h, RPMTAG_ENCODING, encoding);
|
|
|
2ff057 |
if (!strict)
|
|
|
2ff057 |
rc = RPMRC_OK;
|
|
|
2ff057 |
|
|
|
2ff057 |
exit:
|
|
|
2ff057 |
if (ic != (iconv_t) -1)
|
|
|
2ff057 |
iconv_close(ic);
|
|
|
2ff057 |
headerFreeIterator(hi);
|
|
|
2ff057 |
free(dest);
|
|
|
2ff057 |
#endif /* HAVE_ICONV */
|
|
|
2ff057 |
|
|
|
2ff057 |
return rc;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
static int parseEmpty(rpmSpec spec, int prevParsePart)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
int res = PART_ERROR;
|
|
|
2ff057 |
int nextPart, rc;
|
|
|
2ff057 |
char *line;
|
|
|
2ff057 |
|
|
|
2ff057 |
line = spec->line + sizeof("%end") - 1;
|
|
|
2ff057 |
SKIPSPACE(line);
|
|
|
2ff057 |
if (line[0] != '\0') {
|
|
|
2ff057 |
rpmlog(RPMLOG_ERR,
|
|
|
2ff057 |
_("line %d: %%end doesn't take any arguments: %s\n"),
|
|
|
2ff057 |
spec->lineNum, spec->line);
|
|
|
2ff057 |
goto exit;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
if (prevParsePart == PART_EMPTY) {
|
|
|
2ff057 |
rpmlog(RPMLOG_ERR,
|
|
|
2ff057 |
_("line %d: %%end not expected here, no section to close: %s\n"),
|
|
|
2ff057 |
spec->lineNum, spec->line);
|
|
|
2ff057 |
goto exit;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
if ((rc = readLine(spec, STRIP_TRAILINGSPACE|STRIP_COMMENTS)) > 0) {
|
|
|
2ff057 |
nextPart = PART_NONE;
|
|
|
2ff057 |
} else if (rc < 0) {
|
|
|
2ff057 |
goto exit;
|
|
|
2ff057 |
} else {
|
|
|
2ff057 |
while (! (nextPart = isPart(spec->line))) {
|
|
|
2ff057 |
line = spec->line;
|
|
|
2ff057 |
SKIPSPACE(line);
|
|
|
2ff057 |
|
|
|
2ff057 |
if (line[0] != '\0') {
|
|
|
2ff057 |
rpmlog(RPMLOG_ERR,
|
|
|
2ff057 |
_("line %d doesn't belong to any section: %s\n"),
|
|
|
2ff057 |
spec->lineNum, spec->line);
|
|
|
2ff057 |
goto exit;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
if ((rc = readLine(spec, STRIP_TRAILINGSPACE|STRIP_COMMENTS)) > 0) {
|
|
|
2ff057 |
nextPart = PART_NONE;
|
|
|
2ff057 |
break;
|
|
|
2ff057 |
} else if (rc < 0) {
|
|
|
2ff057 |
goto exit;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
}
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
res = nextPart;
|
|
|
2ff057 |
|
|
|
2ff057 |
exit:
|
|
|
2ff057 |
return res;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
static rpmSpec parseSpec(const char *specFile, rpmSpecFlags flags,
|
|
|
2ff057 |
const char *buildRoot, int recursing)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
int parsePart = PART_PREAMBLE;
|
|
|
2ff057 |
int prevParsePart = PART_EMPTY;
|
|
|
2ff057 |
int storedParsePart;
|
|
|
2ff057 |
int initialPackage = 1;
|
|
|
2ff057 |
rpmSpec spec;
|
|
|
2ff057 |
|
|
|
2ff057 |
/* Set up a new Spec structure with no packages. */
|
|
|
2ff057 |
spec = newSpec();
|
|
|
2ff057 |
|
|
|
2ff057 |
spec->specFile = rpmGetPath(specFile, NULL);
|
|
|
2ff057 |
pushOFI(spec, spec->specFile);
|
|
|
2ff057 |
/* If buildRoot not specified, use default %{buildroot} */
|
|
|
2ff057 |
if (buildRoot) {
|
|
|
2ff057 |
spec->buildRoot = xstrdup(buildRoot);
|
|
|
2ff057 |
} else {
|
|
|
2ff057 |
spec->buildRoot = rpmGetPath("%{?buildroot:%{buildroot}}", NULL);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
rpmPushMacro(NULL, "_docdir", NULL, "%{_defaultdocdir}", RMIL_SPEC);
|
|
|
2ff057 |
rpmPushMacro(NULL, "_licensedir", NULL, "%{_defaultlicensedir}", RMIL_SPEC);
|
|
|
2ff057 |
spec->recursing = recursing;
|
|
|
2ff057 |
spec->flags = flags;
|
|
|
2ff057 |
|
|
|
2ff057 |
/* All the parse*() functions expect to have a line pre-read */
|
|
|
2ff057 |
/* in the spec's line buffer. Except for parsePreamble(), */
|
|
|
2ff057 |
/* which handles the initial entry into a spec file. */
|
|
|
2ff057 |
|
|
|
2ff057 |
while (parsePart != PART_NONE) {
|
|
|
2ff057 |
int goterror = 0;
|
|
|
2ff057 |
storedParsePart = parsePart;
|
|
|
2ff057 |
switch (parsePart) {
|
|
|
2ff057 |
case PART_ERROR: /* fallthrough */
|
|
|
2ff057 |
default:
|
|
|
2ff057 |
goterror = 1;
|
|
|
2ff057 |
break;
|
|
|
2ff057 |
case PART_EMPTY:
|
|
|
2ff057 |
parsePart = parseEmpty(spec, prevParsePart);
|
|
|
2ff057 |
break;
|
|
|
2ff057 |
case PART_PREAMBLE:
|
|
|
2ff057 |
parsePart = parsePreamble(spec, initialPackage);
|
|
|
2ff057 |
initialPackage = 0;
|
|
|
2ff057 |
break;
|
|
|
2ff057 |
case PART_PREP:
|
|
|
2ff057 |
parsePart = parsePrep(spec);
|
|
|
2ff057 |
break;
|
|
|
2ff057 |
case PART_BUILD:
|
|
|
2ff057 |
case PART_INSTALL:
|
|
|
2ff057 |
case PART_CHECK:
|
|
|
2ff057 |
case PART_CLEAN:
|
|
|
2ff057 |
parsePart = parseBuildInstallClean(spec, parsePart);
|
|
|
2ff057 |
break;
|
|
|
2ff057 |
case PART_CHANGELOG:
|
|
|
2ff057 |
parsePart = parseChangelog(spec);
|
|
|
2ff057 |
break;
|
|
|
2ff057 |
case PART_DESCRIPTION:
|
|
|
2ff057 |
parsePart = parseDescription(spec);
|
|
|
2ff057 |
break;
|
|
|
2ff057 |
|
|
|
2ff057 |
case PART_PRE:
|
|
|
2ff057 |
case PART_POST:
|
|
|
2ff057 |
case PART_PREUN:
|
|
|
2ff057 |
case PART_POSTUN:
|
|
|
2ff057 |
case PART_PRETRANS:
|
|
|
2ff057 |
case PART_POSTTRANS:
|
|
|
2ff057 |
case PART_VERIFYSCRIPT:
|
|
|
2ff057 |
case PART_TRIGGERPREIN:
|
|
|
2ff057 |
case PART_TRIGGERIN:
|
|
|
2ff057 |
case PART_TRIGGERUN:
|
|
|
2ff057 |
case PART_TRIGGERPOSTUN:
|
|
|
2ff057 |
case PART_FILETRIGGERIN:
|
|
|
2ff057 |
case PART_FILETRIGGERUN:
|
|
|
2ff057 |
case PART_FILETRIGGERPOSTUN:
|
|
|
2ff057 |
case PART_TRANSFILETRIGGERIN:
|
|
|
2ff057 |
case PART_TRANSFILETRIGGERUN:
|
|
|
2ff057 |
case PART_TRANSFILETRIGGERPOSTUN:
|
|
|
2ff057 |
parsePart = parseScript(spec, parsePart);
|
|
|
2ff057 |
break;
|
|
|
2ff057 |
|
|
|
2ff057 |
case PART_FILES:
|
|
|
2ff057 |
parsePart = parseFiles(spec);
|
|
|
2ff057 |
break;
|
|
|
2ff057 |
|
|
|
2ff057 |
case PART_POLICIES:
|
|
|
2ff057 |
parsePart = parsePolicies(spec);
|
|
|
2ff057 |
break;
|
|
|
2ff057 |
|
|
|
2ff057 |
case PART_NONE: /* XXX avoid gcc whining */
|
|
|
2ff057 |
case PART_LAST:
|
|
|
2ff057 |
case PART_BUILDARCHITECTURES:
|
|
|
2ff057 |
break;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
prevParsePart = storedParsePart;
|
|
|
2ff057 |
|
|
|
2ff057 |
if (goterror || parsePart >= PART_LAST) {
|
|
|
2ff057 |
goto errxit;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
if (parsePart == PART_BUILDARCHITECTURES) {
|
|
|
2ff057 |
int index;
|
|
|
2ff057 |
int x;
|
|
|
2ff057 |
|
|
|
2ff057 |
closeSpec(spec);
|
|
|
2ff057 |
|
|
|
2ff057 |
spec->BASpecs = xcalloc(spec->BACount, sizeof(*spec->BASpecs));
|
|
|
2ff057 |
index = 0;
|
|
|
2ff057 |
if (spec->BANames != NULL)
|
|
|
2ff057 |
for (x = 0; x < spec->BACount; x++) {
|
|
|
2ff057 |
|
|
|
2ff057 |
/* Skip if not arch is not compatible. */
|
|
|
2ff057 |
if (!rpmMachineScore(RPM_MACHTABLE_BUILDARCH, spec->BANames[x]))
|
|
|
2ff057 |
continue;
|
|
|
2ff057 |
rpmPushMacro(NULL, "_target_cpu", NULL, spec->BANames[x], RMIL_RPMRC);
|
|
|
2ff057 |
spec->BASpecs[index] = parseSpec(specFile, flags, buildRoot, 1);
|
|
|
2ff057 |
if (spec->BASpecs[index] == NULL) {
|
|
|
2ff057 |
spec->BACount = index;
|
|
|
2ff057 |
goto errxit;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
rpmPopMacro(NULL, "_target_cpu");
|
|
|
2ff057 |
index++;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
spec->BACount = index;
|
|
|
2ff057 |
if (! index) {
|
|
|
2ff057 |
rpmlog(RPMLOG_ERR,
|
|
|
2ff057 |
_("No compatible architectures found for build\n"));
|
|
|
2ff057 |
goto errxit;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
/*
|
|
|
2ff057 |
* Return the 1st child's fully parsed Spec structure.
|
|
|
2ff057 |
* The restart of the parse when encountering BuildArch
|
|
|
2ff057 |
* causes problems for "rpm -q --specfile". This is
|
|
|
2ff057 |
* still a hack because there may be more than 1 arch
|
|
|
2ff057 |
* specified (unlikely but possible.) There's also the
|
|
|
2ff057 |
* further problem that the macro context, particularly
|
|
|
2ff057 |
* %{_target_cpu}, disagrees with the info in the header.
|
|
|
2ff057 |
*/
|
|
|
2ff057 |
if (spec->BACount >= 1) {
|
|
|
2ff057 |
rpmSpec nspec = spec->BASpecs[0];
|
|
|
2ff057 |
spec->BASpecs = _free(spec->BASpecs);
|
|
|
2ff057 |
rpmSpecFree(spec);
|
|
|
2ff057 |
spec = nspec;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
goto exit;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
if (spec->clean == NULL) {
|
|
|
2ff057 |
char *body = rpmExpand("%{?buildroot: %{__rm} -rf %{buildroot}}", NULL);
|
|
|
2ff057 |
spec->clean = newStringBuf();
|
|
|
2ff057 |
appendLineStringBuf(spec->clean, body);
|
|
|
2ff057 |
free(body);
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
/* Check for description in each package */
|
|
|
2ff057 |
for (Package pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
|
|
|
2ff057 |
if (!headerIsEntry(pkg->header, RPMTAG_DESCRIPTION)) {
|
|
|
2ff057 |
rpmlog(RPMLOG_ERR, _("Package has no %%description: %s\n"),
|
|
|
2ff057 |
headerGetString(pkg->header, RPMTAG_NAME));
|
|
|
2ff057 |
goto errxit;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
/* Add arch, os and platform, self-provides etc for each package */
|
|
|
2ff057 |
addTargets(spec->packages);
|
|
|
2ff057 |
|
|
|
2ff057 |
/* Check for encoding in each package unless disabled */
|
|
|
2ff057 |
if (!(spec->flags & RPMSPEC_NOUTF8)) {
|
|
|
2ff057 |
int badenc = 0;
|
|
|
2ff057 |
for (Package pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
|
|
|
2ff057 |
if (checkForEncoding(pkg->header, 0) != RPMRC_OK) {
|
|
|
2ff057 |
badenc = 1;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
}
|
|
|
2ff057 |
if (badenc)
|
|
|
2ff057 |
goto errxit;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
closeSpec(spec);
|
|
|
2ff057 |
exit:
|
|
|
2ff057 |
/* Assemble source header from parsed components */
|
|
|
2ff057 |
initSourceHeader(spec);
|
|
|
2ff057 |
|
|
|
2ff057 |
return spec;
|
|
|
2ff057 |
|
|
|
2ff057 |
errxit:
|
|
|
2ff057 |
rpmSpecFree(spec);
|
|
|
2ff057 |
return NULL;
|
|
|
2ff057 |
}
|
|
|
2ff057 |
|
|
|
2ff057 |
rpmSpec rpmSpecParse(const char *specFile, rpmSpecFlags flags,
|
|
|
2ff057 |
const char *buildRoot)
|
|
|
2ff057 |
{
|
|
|
2ff057 |
return parseSpec(specFile, flags, buildRoot, 0);
|
|
|
2ff057 |
}
|