rpm/build/spec.c

543 lines
11 KiB
C
Raw Normal View History

/** \ingroup rpmbuild
* \file build/spec.c
* Handle spec data structure.
*/
#include "system.h"
#include "rpmbuild.h"
#include "buildio.h"
extern int specedit;
extern MacroContext rpmGlobalMacroContext;
#define SKIPWHITE(_x) {while(*(_x) && (isspace(*_x) || *(_x) == ',')) (_x)++;}
#define SKIPNONWHITE(_x){while(*(_x) &&!(isspace(*_x) || *(_x) == ',')) (_x)++;}
static inline void freeTriggerFiles(/*@only@*/ struct TriggerFileEntry *p)
{
struct TriggerFileEntry *o, *q = p;
while (q != NULL) {
o = q;
q = q->next;
FREE(o->fileName);
FREE(o->script);
FREE(o->prog);
free(o);
}
}
static inline void freeCpioList(/*@only@*/ struct cpioFileMapping *cpioList, int cpioCount)
{
struct cpioFileMapping *p = cpioList;
while (cpioCount--) {
rpmMessage(RPMMESS_DEBUG, _("archive = %s, fs = %s\n"),
p->archivePath, p->fsPath);
FREE(p->archivePath);
FREE(p->fsPath);
p++;
}
FREE(cpioList);
}
static inline void freeSources(/*@only@*/ struct Source *s)
{
struct Source *r, *t = s;
while (t != NULL) {
r = t;
t = t->next;
FREE(r->fullSource);
free(r);
}
}
/** */
int lookupPackage(Spec spec, const char *name, int flag, /*@out@*/Package *pkg)
{
const char *pname;
const char *fullName;
Package p;
/* "main" package */
if (name == NULL) {
if (pkg)
*pkg = spec->packages;
return 0;
}
/* Construct package name */
{ char *n;
if (flag == PART_SUBNAME) {
headerNVR(spec->packages->header, &pname, NULL, NULL);
fullName = n = alloca(strlen(pname) + 1 + strlen(name) + 1);
while (*pname) *n++ = *pname++;
*n++ = '-';
} else {
fullName = n = alloca(strlen(name)+1);
}
strcpy(n, name);
}
/* Locate package with fullName */
for (p = spec->packages; p != NULL; p = p->next) {
headerNVR(p->header, &pname, NULL, NULL);
if (pname && (! strcmp(fullName, pname))) {
break;
}
}
if (pkg)
*pkg = p;
return ((p == NULL) ? 1 : 0);
}
/** */
Package newPackage(Spec spec)
{
Package p;
Package pp;
p = xmalloc(sizeof(*p));
p->header = headerNew();
p->icon = NULL;
p->autoProv = 1;
p->autoReq = 1;
#if 0
p->reqProv = NULL;
p->triggers = NULL;
p->triggerScripts = NULL;
#endif
p->triggerFiles = NULL;
p->fileFile = NULL;
p->fileList = NULL;
p->cpioList = NULL;
p->cpioCount = 0;
p->preInFile = NULL;
p->postInFile = NULL;
p->preUnFile = NULL;
p->postUnFile = NULL;
p->verifyFile = NULL;
p->specialDoc = NULL;
if (spec->packages == NULL) {
spec->packages = p;
} else {
/* Always add package to end of list */
for (pp = spec->packages; pp->next != NULL; pp = pp->next)
;
pp->next = p;
}
p->next = NULL;
return p;
}
/** */
void freePackage(/*@only@*/ Package p)
{
if (p == NULL)
return;
FREE(p->preInFile);
FREE(p->postInFile);
FREE(p->preUnFile);
FREE(p->postUnFile);
FREE(p->verifyFile);
headerFree(p->header);
freeStringBuf(p->fileList);
FREE(p->fileFile);
freeCpioList(p->cpioList, p->cpioCount);
freeStringBuf(p->specialDoc);
freeSources(p->icon);
freeTriggerFiles(p->triggerFiles);
free(p);
}
/** */
void freePackages(Spec spec)
{
Package p;
while ((p = spec->packages) != NULL) {
spec->packages = p->next;
p->next = NULL;
freePackage(p);
}
}
static inline /*@owned@*/ struct Source *findSource(Spec spec, int num, int flag)
{
struct Source *p;
for (p = spec->sources; p != NULL; p = p->next) {
if ((num == p->num) && (p->flags & flag)) {
return p;
}
}
return NULL;
}
#ifdef UNUSED
static char *getSourceAux(Spec spec, int num, int flag, int full)
{
struct Source *p = spec->sources;
p = findSource(spec, num, flag);
return (p) ? (full ? p->fullSource : p->source) : NULL;
}
static char *getSource(Spec spec, int num, int flag)
{
return getSourceAux(spec, num, flag, 0);
}
static char *getFullSource(Spec spec, int num, int flag)
{
return getSourceAux(spec, num, flag, 1);
}
#endif /* UNUSED */
/** */
int parseNoSource(Spec spec, const char *field, int tag)
{
const char *f, *fe;
const char *name;
int num, flag;
if (tag == RPMTAG_NOSOURCE) {
flag = RPMBUILD_ISSOURCE;
name = "source";
} else {
flag = RPMBUILD_ISPATCH;
name = "patch";
}
fe = field;
for (f = fe; *f; f = fe) {
struct Source *p;
SKIPWHITE(f);
if (*f == '\0')
break;
fe = f;
SKIPNONWHITE(fe);
if (*fe) fe++;
if (parseNum(f, &num)) {
rpmError(RPMERR_BADSPEC, _("line %d: Bad number: %s"),
spec->lineNum, f);
return RPMERR_BADSPEC;
}
if (! (p = findSource(spec, num, flag))) {
rpmError(RPMERR_BADSPEC, _("line %d: Bad no%s number: %d"),
spec->lineNum, name, num);
return RPMERR_BADSPEC;
}
p->flags |= RPMBUILD_ISNO;
}
return 0;
}
/** */
int addSource(Spec spec, Package pkg, const char *field, int tag)
{
struct Source *p;
int flag = 0;
char *name = NULL;
char *nump;
const char *fieldp = NULL;
char buf[BUFSIZ];
int num = 0;
switch (tag) {
case RPMTAG_SOURCE:
flag = RPMBUILD_ISSOURCE;
name = "source";
fieldp = spec->line + 6;
break;
case RPMTAG_PATCH:
flag = RPMBUILD_ISPATCH;
name = "patch";
fieldp = spec->line + 5;
break;
case RPMTAG_ICON:
flag = RPMBUILD_ISICON;
fieldp = NULL;
break;
}
/* Get the number */
if (tag != RPMTAG_ICON) {
/* We already know that a ':' exists, and that there */
/* are no spaces before it. */
/* This also now allows for spaces and tabs between */
/* the number and the ':' */
nump = buf;
while ((*fieldp != ':') && (*fieldp != ' ') && (*fieldp != '\t')) {
*nump++ = *fieldp++;
}
*nump = '\0';
nump = buf;
SKIPSPACE(nump);
if (! *nump) {
num = 0;
} else {
if (parseNum(buf, &num)) {
rpmError(RPMERR_BADSPEC, _("line %d: Bad %s number: %s\n"),
spec->lineNum, name, spec->line);
return RPMERR_BADSPEC;
}
}
}
/* Create the entry and link it in */
p = xmalloc(sizeof(struct Source));
p->num = num;
p->fullSource = xstrdup(field);
p->source = strrchr(p->fullSource, '/');
p->flags = flag;
if (p->source) {
p->source++;
} else {
p->source = p->fullSource;
}
if (tag != RPMTAG_ICON) {
p->next = spec->sources;
spec->sources = p;
} else {
p->next = pkg->icon;
pkg->icon = p;
}
spec->numSources++;
if (tag != RPMTAG_ICON) {
const char *body = rpmGetPath("%{_sourcedir}/", p->source, NULL);
sprintf(buf, "%s%d",
(flag & RPMBUILD_ISPATCH) ? "PATCH" : "SOURCE", num);
addMacro(spec->macros, buf, NULL, body, RMIL_SPEC);
sprintf(buf, "%sURL%d",
(flag & RPMBUILD_ISPATCH) ? "PATCH" : "SOURCE", num);
addMacro(spec->macros, buf, NULL, p->fullSource, RMIL_SPEC);
xfree(body);
}
return 0;
}
static inline struct speclines * newSl(void)
{
struct speclines *sl = NULL;
if (specedit) {
sl = xmalloc(sizeof(struct speclines));
sl->sl_lines = NULL;
sl->sl_nalloc = 0;
sl->sl_nlines = 0;
}
return sl;
}
static inline void freeSl(/*@only@*/struct speclines *sl)
{
int i;
if (sl == NULL)
return;
for (i = 0; i < sl->sl_nlines; i++)
FREE(sl->sl_lines[i]);
FREE(sl->sl_lines);
free(sl);
}
static inline struct spectags * newSt(void)
{
struct spectags *st = NULL;
if (specedit) {
st = xmalloc(sizeof(struct spectags));
st->st_t = NULL;
st->st_nalloc = 0;
st->st_ntags = 0;
}
return st;
}
static inline void freeSt(/*@only@*/struct spectags *st)
{
int i;
if (st == NULL)
return;
for (i = 0; i < st->st_ntags; i++) {
struct spectag *t = st->st_t + i;
FREE(t->t_lang);
FREE(t->t_msgid);
}
FREE(st->st_t);
free(st);
}
/** */
Spec newSpec(void)
{
Spec spec;
spec = (Spec)xmalloc(sizeof *spec);
spec->specFile = NULL;
spec->sourceRpmName = NULL;
spec->sl = newSl();
spec->st = newSt();
spec->fileStack = NULL;
spec->lbuf[0] = '\0';
spec->line = spec->lbuf;
spec->nextline = NULL;
spec->nextpeekc = '\0';
spec->lineNum = 0;
spec->readStack = xmalloc(sizeof(struct ReadLevelEntry));
spec->readStack->next = NULL;
spec->readStack->reading = 1;
spec->rootURL = NULL;
spec->prep = NULL;
spec->build = NULL;
spec->install = NULL;
spec->clean = NULL;
spec->sources = NULL;
spec->packages = NULL;
spec->noSource = 0;
spec->numSources = 0;
spec->sourceHeader = NULL;
spec->sourceCpioCount = 0;
spec->sourceCpioList = NULL;
spec->gotBuildRootURL = 0;
spec->buildRootURL = NULL;
spec->buildSubdir = NULL;
spec->passPhrase = NULL;
spec->timeCheck = 0;
spec->cookie = NULL;
spec->buildRestrictions = headerNew();
spec->buildArchitectures = NULL;
spec->buildArchitectureCount = 0;
spec->inBuildArchitectures = 0;
spec->buildArchitectureSpecs = NULL;
spec->force = 0;
spec->anyarch = 0;
spec->macros = &rpmGlobalMacroContext;
return spec;
}
/** */
void freeSpec(/*@only@*/ Spec spec)
{
struct OpenFileInfo *ofi;
struct ReadLevelEntry *rl;
freeSl(spec->sl); spec->sl = NULL;
freeSt(spec->st); spec->st = NULL;
freeStringBuf(spec->prep); spec->prep = NULL;
freeStringBuf(spec->build); spec->build = NULL;
freeStringBuf(spec->install); spec->install = NULL;
freeStringBuf(spec->clean); spec->clean = NULL;
FREE(spec->buildRootURL);
FREE(spec->buildSubdir);
FREE(spec->specFile);
FREE(spec->sourceRpmName);
while (spec->fileStack) {
ofi = spec->fileStack;
spec->fileStack = spec->fileStack->next;
ofi->next = NULL;
FREE(ofi->fileName);
free(ofi);
}
while (spec->readStack) {
rl = spec->readStack;
spec->readStack = spec->readStack->next;
rl->next = NULL;
free(rl);
}
if (spec->sourceHeader != NULL) {
headerFree(spec->sourceHeader);
spec->sourceHeader = NULL;
}
freeCpioList(spec->sourceCpioList, spec->sourceCpioCount);
spec->sourceCpioList = NULL;
headerFree(spec->buildRestrictions);
spec->buildRestrictions = NULL;
if (!spec->inBuildArchitectures) {
while (spec->buildArchitectureCount--) {
freeSpec(
spec->buildArchitectureSpecs[spec->buildArchitectureCount]);
}
FREE(spec->buildArchitectureSpecs);
}
FREE(spec->buildArchitectures);
FREE(spec->passPhrase);
FREE(spec->cookie);
freeSources(spec->sources); spec->sources = NULL;
freePackages(spec);
closeSpec(spec);
free(spec);
}
/** */
/*@only@*/ struct OpenFileInfo * newOpenFileInfo(void)
{
struct OpenFileInfo *ofi;
ofi = xmalloc(sizeof(struct OpenFileInfo));
ofi->fd = NULL;
ofi->fileName = NULL;
ofi->lineNum = 0;
ofi->readBuf[0] = '\0';
ofi->readPtr = NULL;
ofi->next = NULL;
return ofi;
}