2002-03-25 23:16:26 +03:00
/** \ingroup rpmbuild
* \ file build / parsePreamble . c
* Parse tags in global section from spec file .
*/
# include "system.h"
2002-03-26 01:02:39 +03:00
# include "rpmio_internal.h"
# include "rpmbuild.h"
2002-03-25 23:16:26 +03:00
# include "debug.h"
/*@access FD_t @*/ /* compared with NULL */
/**
*/
/*@observer@*/ /*@unchecked@*/
static rpmTag copyTagsDuringParse [ ] = {
RPMTAG_EPOCH ,
RPMTAG_VERSION ,
RPMTAG_RELEASE ,
RPMTAG_LICENSE ,
RPMTAG_PACKAGER ,
RPMTAG_DISTRIBUTION ,
RPMTAG_DISTURL ,
RPMTAG_VENDOR ,
RPMTAG_ICON ,
RPMTAG_URL ,
2010-02-23 19:02:46 +03:00
RPMTAG_VCS ,
2002-03-25 23:16:26 +03:00
RPMTAG_CHANGELOGTIME ,
RPMTAG_CHANGELOGNAME ,
RPMTAG_CHANGELOGTEXT ,
RPMTAG_PREFIXES ,
2002-06-13 15:28:05 +04:00
RPMTAG_BUILDHOST ,
2014-05-16 16:45:38 +04:00
RPMTAG_DISTTAG ,
2002-03-25 23:16:26 +03:00
0
} ;
/**
*/
/*@observer@*/ /*@unchecked@*/
static rpmTag requiredTags [ ] = {
RPMTAG_NAME ,
RPMTAG_VERSION ,
RPMTAG_RELEASE ,
RPMTAG_SUMMARY ,
RPMTAG_GROUP ,
RPMTAG_LICENSE ,
0
} ;
/**
*/
static void addOrAppendListEntry ( Header h , int_32 tag , char * line )
/*@modifies h @*/
{
int xx ;
int argc ;
const char * * argv ;
xx = poptParseArgvString ( line , & argc , & argv ) ;
if ( argc )
xx = headerAddOrAppendEntry ( h , tag , RPM_STRING_ARRAY_TYPE , argv , argc ) ;
argv = _free ( argv ) ;
}
/* Parse a simple part line that only take -n <pkg> or <pkg> */
/* <pkg> is return in name as a pointer into a static buffer */
/**
*/
static int parseSimplePart ( char * line , /*@out@*/ char * * name , /*@out@*/ int * flag )
/*@globals internalState@*/
/*@modifies *name, *flag, internalState @*/
{
char * tok ;
char linebuf [ BUFSIZ ] ;
static char buf [ BUFSIZ ] ;
strcpy ( linebuf , line ) ;
/* Throw away the first token (the %xxxx) */
( void ) strtok ( linebuf , " \t \n " ) ;
if ( ! ( tok = strtok ( NULL , " \t \n " ) ) ) {
* name = NULL ;
return 0 ;
}
if ( ! strcmp ( tok , " -n " ) ) {
if ( ! ( tok = strtok ( NULL , " \t \n " ) ) )
return 1 ;
* flag = PART_NAME ;
} else {
* flag = PART_SUBNAME ;
}
strcpy ( buf , tok ) ;
* name = buf ;
return ( strtok ( NULL , " \t \n " ) ) ? 1 : 0 ;
}
/**
*/
2002-03-26 01:57:16 +03:00
static inline const char * parseReqProv ( const char * s )
2002-03-25 23:16:26 +03:00
{
2002-03-26 01:57:16 +03:00
if ( ! s | |
! strcasecmp ( s , " no " ) | |
! strcasecmp ( s , " false " ) | |
! strcasecmp ( s , " off " ) | |
! strcmp ( s , " 0 " ) ) {
return xstrdup ( " " ) ;
}
return xstrdup ( s ) ;
2002-03-25 23:16:26 +03:00
}
typedef struct tokenBits_s {
/*@observer@*/ /*@null@*/ const char * name ;
rpmsenseFlags bits ;
} * tokenBits ;
/**
*/
/*@observer@*/ /*@unchecked@*/
static struct tokenBits_s installScriptBits [ ] = {
{ " interp " , RPMSENSE_INTERP } ,
{ " preun " , RPMSENSE_SCRIPT_PREUN } ,
{ " pre " , RPMSENSE_SCRIPT_PRE } ,
{ " postun " , RPMSENSE_SCRIPT_POSTUN } ,
{ " post " , RPMSENSE_SCRIPT_POST } ,
{ " rpmlib " , RPMSENSE_RPMLIB } ,
{ " verify " , RPMSENSE_SCRIPT_VERIFY } ,
{ NULL , 0 }
} ;
/**
*/
/*@observer@*/ /*@unchecked@*/
static struct tokenBits_s buildScriptBits [ ] = {
{ " prep " , RPMSENSE_SCRIPT_PREP } ,
{ " build " , RPMSENSE_SCRIPT_BUILD } ,
{ " install " , RPMSENSE_SCRIPT_INSTALL } ,
{ " clean " , RPMSENSE_SCRIPT_CLEAN } ,
{ NULL , 0 }
} ;
/**
*/
static int parseBits ( const char * s , const tokenBits tokbits ,
/*@out@*/ rpmsenseFlags * bp )
/*@modifies *bp @*/
{
parseBits: disallow syntax errors and unknown qualifiers
The previous attempt to fail build in case of syntax errors
and unknown dependency qualifiers made in commit
rpm-4.8.0-beta1-385-gbf2bc18ebb325f081ade65adc2fbb6858f0b8396
missed the following classes of erroneous dependencies:
Requires(,) -- erroneously treated as Requires(),
Requires(;) -- erroneously treated as Requires(),
Requires(,pre) -- erroneously treated as Requires(),
Requires(;pre) -- erroneously treated as Requires(),
Requires(pre,) -- erroneously treated as Requires(pre),
Requires(pre,,postun) -- erroneously treated as Requires(pre),
Requires(pre,,junk) -- erroneously treated as Requires(pre),
Requires(pre;postun) -- erroneously treated as Requires(pre),
Requires(pre;junk) -- erroneously treated as Requires(pre).
Found by code inspection.
Fixes: bf2bc18ebb32 ("Always fail build on unknown dependency qualifiers")
(cherry picked from rpm.org commit aafb861846db97d78964e98d603b4e6cd88ed3ae)
The two last cases listed above have already been fixed by commit
f7280d830248756794ece55a502401af90bd8db1.
2019-01-14 23:56:55 +03:00
tokenBits tb = NULL ;
2002-03-25 23:16:26 +03:00
rpmsenseFlags bits = RPMSENSE_ANY ;
2019-01-14 23:56:55 +03:00
int rc = 0 ;
2002-03-25 23:16:26 +03:00
if ( s ) {
parseBits: disallow syntax errors and unknown qualifiers
The previous attempt to fail build in case of syntax errors
and unknown dependency qualifiers made in commit
rpm-4.8.0-beta1-385-gbf2bc18ebb325f081ade65adc2fbb6858f0b8396
missed the following classes of erroneous dependencies:
Requires(,) -- erroneously treated as Requires(),
Requires(;) -- erroneously treated as Requires(),
Requires(,pre) -- erroneously treated as Requires(),
Requires(;pre) -- erroneously treated as Requires(),
Requires(pre,) -- erroneously treated as Requires(pre),
Requires(pre,,postun) -- erroneously treated as Requires(pre),
Requires(pre,,junk) -- erroneously treated as Requires(pre),
Requires(pre;postun) -- erroneously treated as Requires(pre),
Requires(pre;junk) -- erroneously treated as Requires(pre).
Found by code inspection.
Fixes: bf2bc18ebb32 ("Always fail build on unknown dependency qualifiers")
(cherry picked from rpm.org commit aafb861846db97d78964e98d603b4e6cd88ed3ae)
The two last cases listed above have already been fixed by commit
f7280d830248756794ece55a502401af90bd8db1.
2019-01-14 23:56:55 +03:00
for ( ; ; ) {
2019-01-14 23:56:55 +03:00
int c = 0 ;
2002-03-25 23:16:26 +03:00
while ( ( c = * s ) & & xisspace ( c ) ) s + + ;
2019-01-14 23:56:55 +03:00
const char * se = s ;
2002-03-25 23:16:26 +03:00
while ( ( c = * se ) & & xisalpha ( c ) ) se + + ;
parseBits: disallow syntax errors and unknown qualifiers
The previous attempt to fail build in case of syntax errors
and unknown dependency qualifiers made in commit
rpm-4.8.0-beta1-385-gbf2bc18ebb325f081ade65adc2fbb6858f0b8396
missed the following classes of erroneous dependencies:
Requires(,) -- erroneously treated as Requires(),
Requires(;) -- erroneously treated as Requires(),
Requires(,pre) -- erroneously treated as Requires(),
Requires(;pre) -- erroneously treated as Requires(),
Requires(pre,) -- erroneously treated as Requires(pre),
Requires(pre,,postun) -- erroneously treated as Requires(pre),
Requires(pre,,junk) -- erroneously treated as Requires(pre),
Requires(pre;postun) -- erroneously treated as Requires(pre),
Requires(pre;junk) -- erroneously treated as Requires(pre).
Found by code inspection.
Fixes: bf2bc18ebb32 ("Always fail build on unknown dependency qualifiers")
(cherry picked from rpm.org commit aafb861846db97d78964e98d603b4e6cd88ed3ae)
The two last cases listed above have already been fixed by commit
f7280d830248756794ece55a502401af90bd8db1.
2019-01-14 23:56:55 +03:00
if ( s = = se ) {
if ( c | | tb )
rc = RPMERR_BADSPEC ;
2002-03-25 23:16:26 +03:00
break ;
parseBits: disallow syntax errors and unknown qualifiers
The previous attempt to fail build in case of syntax errors
and unknown dependency qualifiers made in commit
rpm-4.8.0-beta1-385-gbf2bc18ebb325f081ade65adc2fbb6858f0b8396
missed the following classes of erroneous dependencies:
Requires(,) -- erroneously treated as Requires(),
Requires(;) -- erroneously treated as Requires(),
Requires(,pre) -- erroneously treated as Requires(),
Requires(;pre) -- erroneously treated as Requires(),
Requires(pre,) -- erroneously treated as Requires(pre),
Requires(pre,,postun) -- erroneously treated as Requires(pre),
Requires(pre,,junk) -- erroneously treated as Requires(pre),
Requires(pre;postun) -- erroneously treated as Requires(pre),
Requires(pre;junk) -- erroneously treated as Requires(pre).
Found by code inspection.
Fixes: bf2bc18ebb32 ("Always fail build on unknown dependency qualifiers")
(cherry picked from rpm.org commit aafb861846db97d78964e98d603b4e6cd88ed3ae)
The two last cases listed above have already been fixed by commit
f7280d830248756794ece55a502401af90bd8db1.
2019-01-14 23:56:55 +03:00
}
2019-01-14 23:56:55 +03:00
2019-04-19 08:08:33 +03:00
tb = NULL ;
2019-01-14 23:56:55 +03:00
for ( tokenBits t = tokbits ; t - > name ; t + + ) {
if ( t - > name & & ! strncasecmp ( t - > name , s , ( se - s ) ) ) {
if ( ! t - > name [ se - s ] ) {
tb = t ;
break ;
}
if ( tb ) {
tb = NULL ;
break ;
}
tb = t ;
}
2002-03-25 23:16:26 +03:00
}
2019-01-14 23:56:55 +03:00
if ( ! tb ) {
rc = RPMERR_BADSPEC ;
2002-03-25 23:16:26 +03:00
break ;
2019-01-14 23:56:55 +03:00
}
2002-03-25 23:16:26 +03:00
bits | = tb - > bits ;
2019-01-14 23:56:55 +03:00
2002-03-25 23:16:26 +03:00
while ( ( c = * se ) & & xisspace ( c ) ) se + + ;
2019-01-14 23:56:55 +03:00
if ( c ! = ' , ' ) {
if ( c )
rc = RPMERR_BADSPEC ;
2002-03-25 23:16:26 +03:00
break ;
2019-01-14 23:56:55 +03:00
}
2002-03-25 23:16:26 +03:00
s = + + se ;
}
}
2019-01-14 23:56:55 +03:00
* bp | = bits ;
return rc ;
2002-03-25 23:16:26 +03:00
}
/**
*/
static inline char * findLastChar ( char * s )
/*@*/
{
char * res = s ;
while ( * s ! = ' \0 ' ) {
if ( ! xisspace ( * s ) )
res = s ;
s + + ;
}
/*@-temptrans -retalias@*/
return res ;
/*@=temptrans =retalias@*/
}
/**
*/
static int isMemberInEntry ( Header h , const char * name , rpmTag tag )
/*@*/
{
HGE_t hge = ( HGE_t ) headerGetEntryMinMemory ;
HFD_t hfd = headerFreeData ;
const char * * names ;
rpmTagType type ;
int count ;
if ( ! hge ( h , tag , & type , ( void * * ) & names , & count ) )
return - 1 ;
while ( count - - ) {
if ( ! xstrcasecmp ( names [ count ] , name ) )
break ;
}
names = hfd ( names , type ) ;
return ( count > = 0 ? 1 : 0 ) ;
}
/**
*/
static int checkForValidArchitectures ( Spec spec )
/*@*/
{
# ifndef DYING
const char * arch = NULL ;
const char * os = NULL ;
rpmGetArchInfo ( & arch , NULL ) ;
rpmGetOsInfo ( & os , NULL ) ;
# else
const char * arch = rpmExpand ( " %{_target_cpu} " , NULL ) ;
const char * os = rpmExpand ( " %{_target_os} " , NULL ) ;
# endif
if ( isMemberInEntry ( spec - > buildRestrictions ,
arch , RPMTAG_EXCLUDEARCH ) = = 1 ) {
rpmError ( RPMERR_BADSPEC , _ ( " Architecture is excluded: %s \n " ) , arch ) ;
return RPMERR_BADSPEC ;
}
if ( isMemberInEntry ( spec - > buildRestrictions ,
arch , RPMTAG_EXCLUSIVEARCH ) = = 0 ) {
rpmError ( RPMERR_BADSPEC , _ ( " Architecture is not included: %s \n " ) , arch ) ;
return RPMERR_BADSPEC ;
}
if ( isMemberInEntry ( spec - > buildRestrictions ,
os , RPMTAG_EXCLUDEOS ) = = 1 ) {
rpmError ( RPMERR_BADSPEC , _ ( " OS is excluded: %s \n " ) , os ) ;
return RPMERR_BADSPEC ;
}
if ( isMemberInEntry ( spec - > buildRestrictions ,
os , RPMTAG_EXCLUSIVEOS ) = = 0 ) {
rpmError ( RPMERR_BADSPEC , _ ( " OS is not included: %s \n " ) , os ) ;
return RPMERR_BADSPEC ;
}
return 0 ;
}
/**
* Check that required tags are present in header .
* @ param h header
* @ param NVR package name - version - release
* @ return 0 if OK
*/
static int checkForRequired ( Header h , const char * NVR )
/*@modifies h @*/ /* LCL: parse error here with modifies */
{
int res = 0 ;
rpmTag * p ;
for ( p = requiredTags ; * p ! = 0 ; p + + ) {
if ( ! headerIsEntry ( h , * p ) ) {
rpmError ( RPMERR_BADSPEC ,
_ ( " %s field must be present in package: %s \n " ) ,
tagName ( * p ) , NVR ) ;
res = 1 ;
}
}
return res ;
}
/**
* Check that no duplicate tags are present in header .
* @ param h header
* @ param NVR package name - version - release
* @ return 0 if OK
*/
static int checkForDuplicates ( Header h , const char * NVR )
/*@modifies h @*/
{
int res = 0 ;
int lastTag , tag ;
HeaderIterator hi ;
for ( hi = headerInitIterator ( h ) , lastTag = 0 ;
headerNextIterator ( hi , & tag , NULL , NULL , NULL ) ;
lastTag = tag )
{
if ( tag ! = lastTag )
continue ;
rpmError ( RPMERR_BADSPEC , _ ( " Duplicate %s entries in package: %s \n " ) ,
tagName ( tag ) , NVR ) ;
res = 1 ;
}
hi = headerFreeIterator ( hi ) ;
return res ;
}
/**
*/
/*@observer@*/ /*@unchecked@*/
static struct optionalTag {
rpmTag ot_tag ;
/*@observer@*/ /*@null@*/ const char * ot_mac ;
} optionalTags [ ] = {
2005-10-06 03:42:30 +04:00
{ RPMTAG_VENDOR , " %{?vendor} " } ,
{ RPMTAG_PACKAGER , " %{?packager} " } ,
{ RPMTAG_DISTRIBUTION , " %{?distribution} " } ,
{ RPMTAG_DISTURL , " %{?disturl} " } ,
{ RPMTAG_BUILDHOST , " %{?buildhost} " } ,
2014-05-16 16:45:38 +04:00
{ RPMTAG_DISTTAG , " %{?disttag} " } ,
2002-03-25 23:16:26 +03:00
{ - 1 , NULL }
} ;
/**
*/
static void fillOutMainPackage ( Header h )
/*@globals rpmGlobalMacroContext @*/
/*@modifies h, rpmGlobalMacroContext @*/
{
struct optionalTag * ot ;
for ( ot = optionalTags ; ot - > ot_mac ! = NULL ; ot + + ) {
if ( ! headerIsEntry ( h , ot - > ot_tag ) ) {
const char * val = rpmExpand ( ot - > ot_mac , NULL ) ;
2005-10-06 03:42:30 +04:00
if ( val & & * val ! = ' \0 ' )
2002-03-25 23:16:26 +03:00
( void ) headerAddEntry ( h , ot - > ot_tag , RPM_STRING_TYPE , ( void * ) val , 1 ) ;
val = _free ( val ) ;
}
}
}
2003-07-20 16:51:57 +04:00
# ifdef ENABLE_ICON_TAG
2002-03-25 23:16:26 +03:00
/**
*/
static int readIcon ( Header h , const char * file )
/*@globals rpmGlobalMacroContext,
fileSystem @ */
/*@modifies h, rpmGlobalMacroContext, fileSystem @*/
{
const char * fn = NULL ;
char * icon ;
FD_t fd ;
int rc = 0 ;
off_t size ;
size_t nb , iconsize ;
/* XXX use rpmGenPath(rootdir, "%{_sourcedir}/", file) for icon path. */
fn = rpmGetPath ( " %{_sourcedir}/ " , file , NULL ) ;
fd = Fopen ( fn , " r.ufdio " ) ;
if ( fd = = NULL | | Ferror ( fd ) ) {
rpmError ( RPMERR_BADSPEC , _ ( " Unable to open icon %s: %s \n " ) ,
fn , Fstrerror ( fd ) ) ;
rc = RPMERR_BADSPEC ;
goto exit ;
}
size = fdSize ( fd ) ;
iconsize = ( size > = 0 ? size : ( 8 * BUFSIZ ) ) ;
if ( iconsize = = 0 ) {
( void ) Fclose ( fd ) ;
rc = 0 ;
goto exit ;
}
icon = xmalloc ( iconsize + 1 ) ;
* icon = ' \0 ' ;
nb = Fread ( icon , sizeof ( icon [ 0 ] ) , iconsize , fd ) ;
if ( Ferror ( fd ) | | ( size > = 0 & & nb ! = size ) ) {
rpmError ( RPMERR_BADSPEC , _ ( " Unable to read icon %s: %s \n " ) ,
fn , Fstrerror ( fd ) ) ;
rc = RPMERR_BADSPEC ;
}
( void ) Fclose ( fd ) ;
if ( rc )
goto exit ;
if ( ! strncmp ( icon , " GIF " , sizeof ( " GIF " ) - 1 ) ) {
( void ) headerAddEntry ( h , RPMTAG_GIF , RPM_BIN_TYPE , icon , iconsize ) ;
} else if ( ! strncmp ( icon , " /* XPM " , sizeof ( " /* XPM " ) - 1 ) ) {
( void ) headerAddEntry ( h , RPMTAG_XPM , RPM_BIN_TYPE , icon , iconsize ) ;
} else {
rpmError ( RPMERR_BADSPEC , _ ( " Unknown icon type: %s \n " ) , file ) ;
rc = RPMERR_BADSPEC ;
goto exit ;
}
icon = _free ( icon ) ;
exit :
fn = _free ( fn ) ;
return rc ;
}
2003-07-20 16:51:57 +04:00
# endif /* ENABLE_ICON_TAG */
2002-03-25 23:16:26 +03:00
spectag stashSt ( Spec spec , Header h , int tag , const char * lang )
{
HGE_t hge = ( HGE_t ) headerGetEntryMinMemory ;
spectag t = NULL ;
if ( spec - > st ) {
spectags st = spec - > st ;
if ( st - > st_ntags = = st - > st_nalloc ) {
st - > st_nalloc + = 10 ;
st - > st_t = xrealloc ( st - > st_t , st - > st_nalloc * sizeof ( * ( st - > st_t ) ) ) ;
}
t = st - > st_t + st - > st_ntags + + ;
t - > t_tag = tag ;
t - > t_startx = spec - > lineNum - 1 ;
t - > t_nlines = 1 ;
t - > t_lang = xstrdup ( lang ) ;
t - > t_msgid = NULL ;
if ( ! ( t - > t_lang & & strcmp ( t - > t_lang , RPMBUILD_DEFAULT_LANG ) ) ) {
char * n ;
if ( hge ( h , RPMTAG_NAME , NULL , ( void * * ) & n , NULL ) ) {
char buf [ 1024 ] ;
sprintf ( buf , " %s(%s) " , n , tagName ( tag ) ) ;
t - > t_msgid = xstrdup ( buf ) ;
}
}
}
/*@-usereleased -compdef@*/
return t ;
/*@=usereleased =compdef@*/
}
# define SINGLE_TOKEN_ONLY \
if ( multiToken ) { \
rpmError ( RPMERR_BADSPEC , _ ( " line %d: Tag takes single token only: %s \n " ) , \
spec - > lineNum , spec - > line ) ; \
return RPMERR_BADSPEC ; \
}
2019-01-07 20:33:27 +03:00
/**
* Check for inappropriate characters .
* All alphanumerics are allowed .
*
* @ param spec spec ( or NULL )
* @ param str string to check
* @ param accept_bytes string of permitted bytes
* @ param reject_substr sequence of rejected bytes
* @ return RPMRC_OK if OK
*/
static rpmRC
rpmCharCheck ( Spec spec , const char * str ,
const char * accept_bytes , const char * reject_substr )
{
const char * err = 0 ;
for ( const char * p = str ; * p ; + + p ) {
const unsigned char c = * p ;
if ( xisalnum ( c ) )
continue ;
/* the first byte must be alphanumeric */
if ( p ! = str & & accept_bytes & & strchr ( accept_bytes , c ) )
continue ;
err = isprint ( c )
? xasprintf ( " Invalid symbol '%c' (%#x) " , c , c )
: xasprintf ( " Invalid symbol (%#x) " , c ) ;
}
if ( ! err & & reject_substr & & reject_substr [ 0 ]
& & strstr ( str , reject_substr ) )
err = xasprintf ( " Invalid sequence \" %s \" " , reject_substr ) ;
if ( ! err )
return RPMRC_OK ;
if ( spec ) {
rpmlog ( RPMLOG_ERR , " line %d: %s in: %s \n " ,
spec - > lineNum , err , spec - > line ) ;
} else {
rpmlog ( RPMLOG_ERR , " %s in: %s \n " , err , str ) ;
}
err = _free ( err ) ;
return RPMRC_FAIL ;
}
2002-03-25 23:16:26 +03:00
/*@-redecl@*/
extern int noLang ;
/*@=redecl@*/
/**
*/
static int handlePreambleTag ( Spec spec , Package pkg , int tag , const char * macro ,
const char * lang )
/*@globals rpmGlobalMacroContext,
fileSystem @ */
/*@modifies spec->macros, spec->st, spec->buildRootURL,
spec - > sources , spec - > numSources , spec - > noSource ,
spec - > buildRestrictions , spec - > BANames , spec - > BACount ,
spec - > line , spec - > gotBuildRootURL ,
pkg - > header , pkg - > autoProv , pkg - > autoReq , pkg - > icon ,
rpmGlobalMacroContext , fileSystem @ */
{
HGE_t hge = ( HGE_t ) headerGetEntryMinMemory ;
HFD_t hfd = headerFreeData ;
char * field = spec - > line ;
char * end ;
char * * array ;
int multiToken = 0 ;
2010-03-29 09:27:35 +04:00
rpmsenseFlags tagflags = RPMSENSE_ANY ;
2002-03-25 23:16:26 +03:00
rpmTagType type ;
int len ;
int num ;
int rc ;
int xx ;
if ( field = = NULL ) return RPMERR_BADSPEC ; /* XXX can't happen */
/* Find the start of the "field" and strip trailing space */
while ( ( * field ) & & ( * field ! = ' : ' ) )
field + + ;
if ( * field ! = ' : ' ) {
rpmError ( RPMERR_BADSPEC , _ ( " line %d: Malformed tag: %s \n " ) ,
spec - > lineNum , spec - > line ) ;
return RPMERR_BADSPEC ;
}
field + + ;
SKIPSPACE ( field ) ;
if ( ! * field ) {
/* Empty field */
rpmError ( RPMERR_BADSPEC , _ ( " line %d: Empty tag: %s \n " ) ,
spec - > lineNum , spec - > line ) ;
return RPMERR_BADSPEC ;
}
end = findLastChar ( field ) ;
* ( end + 1 ) = ' \0 ' ;
/* See if this is multi-token */
end = field ;
SKIPNONSPACE ( end ) ;
if ( * end ! = ' \0 ' )
multiToken = 1 ;
switch ( tag ) {
case RPMTAG_NAME :
2019-01-07 20:33:27 +03:00
SINGLE_TOKEN_ONLY ;
if ( rpmCharCheck ( spec , field , " -._+ " , " .. " ) )
return RPMERR_BADSPEC ;
( void ) headerAddEntry ( pkg - > header , tag , RPM_STRING_TYPE , field , 1 ) ;
break ;
2002-03-25 23:16:26 +03:00
case RPMTAG_VERSION :
2019-01-07 20:33:27 +03:00
SINGLE_TOKEN_ONLY ;
if ( rpmCharCheck ( spec , field , " ._+ " , " .. " ) )
return RPMERR_BADSPEC ;
/* This macro is for backward compatibility */
addMacro ( spec - > macros , " PACKAGE_VERSION " , NULL , field , RMIL_OLDSPEC ) ;
( void ) headerAddEntry ( pkg - > header , tag , RPM_STRING_TYPE , field , 1 ) ;
break ;
2002-03-25 23:16:26 +03:00
case RPMTAG_RELEASE :
2019-01-07 20:33:27 +03:00
if ( rpmCharCheck ( spec , field , " ._+ " , " .. " ) )
return RPMERR_BADSPEC ;
/* This macro is for backward compatibility */
addMacro ( spec - > macros , " PACKAGE_RELEASE " , NULL , field , RMIL_OLDSPEC - 1 ) ;
( void ) headerAddEntry ( pkg - > header , tag , RPM_STRING_TYPE , field , 1 ) ;
break ;
2014-05-16 16:45:38 +04:00
case RPMTAG_DISTTAG :
2002-03-25 23:16:26 +03:00
SINGLE_TOKEN_ONLY ;
2019-01-07 20:33:27 +03:00
if ( rpmCharCheck ( spec , field , " ._+ " , " .. " ) )
return RPMERR_BADSPEC ;
( void ) headerAddEntry ( pkg - > header , tag , RPM_STRING_TYPE , field , 1 ) ;
break ;
case RPMTAG_URL :
2010-02-23 19:02:46 +03:00
case RPMTAG_VCS :
2019-01-07 20:33:27 +03:00
SINGLE_TOKEN_ONLY ;
2002-03-25 23:16:26 +03:00
( void ) headerAddEntry ( pkg - > header , tag , RPM_STRING_TYPE , field , 1 ) ;
break ;
case RPMTAG_GROUP :
case RPMTAG_SUMMARY :
( void ) stashSt ( spec , pkg - > header , tag , lang ) ;
/*@fallthrough@*/
case RPMTAG_DISTRIBUTION :
case RPMTAG_VENDOR :
case RPMTAG_LICENSE :
case RPMTAG_PACKAGER :
2002-06-13 15:28:05 +04:00
case RPMTAG_BUILDHOST :
2002-03-25 23:16:26 +03:00
if ( ! * lang )
( void ) headerAddEntry ( pkg - > header , tag , RPM_STRING_TYPE , field , 1 ) ;
else if ( ! ( noLang & & strcmp ( lang , RPMBUILD_DEFAULT_LANG ) ) )
( void ) headerAddI18NString ( pkg - > header , tag , field , lang ) ;
break ;
case RPMTAG_BUILDROOT :
SINGLE_TOKEN_ONLY ;
2006-01-11 16:53:32 +03:00
/* Just ignore legacy tag. */
2006-04-03 20:41:43 +04:00
return 0 ;
2002-03-25 23:16:26 +03:00
case RPMTAG_PREFIXES :
addOrAppendListEntry ( pkg - > header , tag , field ) ;
xx = hge ( pkg - > header , tag , & type , ( void * * ) & array , & num ) ;
while ( num - - ) {
len = strlen ( array [ num ] ) ;
if ( array [ num ] [ len - 1 ] = = ' / ' & & len > 1 ) {
rpmError ( RPMERR_BADSPEC ,
_ ( " line %d: Prefixes must not end with \" / \" : %s \n " ) ,
spec - > lineNum , spec - > line ) ;
array = hfd ( array , type ) ;
return RPMERR_BADSPEC ;
}
}
array = hfd ( array , type ) ;
break ;
case RPMTAG_DOCDIR :
SINGLE_TOKEN_ONLY ;
if ( field [ 0 ] ! = ' / ' ) {
rpmError ( RPMERR_BADSPEC ,
_ ( " line %d: Docdir must begin with '/': %s \n " ) ,
spec - > lineNum , spec - > line ) ;
return RPMERR_BADSPEC ;
}
macro = NULL ;
delMacro ( NULL , " _docdir " ) ;
addMacro ( NULL , " _docdir " , NULL , field , RMIL_SPEC ) ;
break ;
case RPMTAG_EPOCH :
SINGLE_TOKEN_ONLY ;
if ( parseNum ( field , & num ) ) {
rpmError ( RPMERR_BADSPEC ,
_ ( " line %d: Epoch/Serial field must be a number: %s \n " ) ,
spec - > lineNum , spec - > line ) ;
return RPMERR_BADSPEC ;
}
xx = headerAddEntry ( pkg - > header , tag , RPM_INT32_TYPE , & num , 1 ) ;
break ;
case RPMTAG_AUTOREQPROV :
2002-03-26 01:57:16 +03:00
pkg - > autoReq = parseReqProv ( field ) ;
pkg - > autoProv = xstrdup ( pkg - > autoReq ) ;
2002-03-25 23:16:26 +03:00
break ;
case RPMTAG_AUTOREQ :
2002-03-26 01:57:16 +03:00
pkg - > autoReq = parseReqProv ( field ) ;
2002-03-25 23:16:26 +03:00
break ;
case RPMTAG_AUTOPROV :
2002-03-26 01:57:16 +03:00
pkg - > autoProv = parseReqProv ( field ) ;
2002-03-25 23:16:26 +03:00
break ;
case RPMTAG_SOURCE :
case RPMTAG_PATCH :
SINGLE_TOKEN_ONLY ;
macro = NULL ;
if ( ( rc = addSource ( spec , pkg , field , tag ) ) )
return rc ;
break ;
case RPMTAG_ICON :
SINGLE_TOKEN_ONLY ;
if ( ( rc = addSource ( spec , pkg , field , tag ) ) )
return rc ;
2003-07-20 16:51:57 +04:00
# ifdef ENABLE_ICON_TAG
2002-03-26 01:57:16 +03:00
if ( ! spec - > preprocess_mode ) {
if ( ( rc = readIcon ( pkg - > header , field ) ) )
return RPMERR_BADSPEC ;
}
2003-07-20 16:51:57 +04:00
# endif /* ENABLE_ICON_TAG */
2002-03-25 23:16:26 +03:00
break ;
case RPMTAG_NOSOURCE :
case RPMTAG_NOPATCH :
spec - > noSource = 1 ;
if ( ( rc = parseNoSource ( spec , field , tag ) ) )
return rc ;
break ;
case RPMTAG_BUILDREQUIRES :
if ( ( rc = parseBits ( lang , buildScriptBits , & tagflags ) ) ) {
rpmError ( RPMERR_BADSPEC ,
_ ( " line %d: Bad %s: qualifiers: %s \n " ) ,
spec - > lineNum , tagName ( tag ) , spec - > line ) ;
return rc ;
}
if ( ( rc = parseRCPOT ( spec , pkg , field , tag , 0 , tagflags ) ) )
return rc ;
break ;
case RPMTAG_REQUIREFLAGS :
case RPMTAG_PREREQ :
if ( ( rc = parseBits ( lang , installScriptBits , & tagflags ) ) ) {
rpmError ( RPMERR_BADSPEC ,
_ ( " line %d: Bad %s: qualifiers: %s \n " ) ,
spec - > lineNum , tagName ( tag ) , spec - > line ) ;
return rc ;
}
if ( ( rc = parseRCPOT ( spec , pkg , field , tag , 0 , tagflags ) ) )
return rc ;
break ;
2019-01-14 23:56:55 +03:00
case RPMTAG_BUILDPREREQ :
2002-03-25 23:16:26 +03:00
case RPMTAG_BUILDCONFLICTS :
case RPMTAG_CONFLICTFLAGS :
case RPMTAG_OBSOLETEFLAGS :
case RPMTAG_PROVIDEFLAGS :
if ( ( rc = parseRCPOT ( spec , pkg , field , tag , 0 , tagflags ) ) )
return rc ;
break ;
case RPMTAG_EXCLUDEARCH :
case RPMTAG_EXCLUSIVEARCH :
case RPMTAG_EXCLUDEOS :
case RPMTAG_EXCLUSIVEOS :
addOrAppendListEntry ( spec - > buildRestrictions , tag , field ) ;
break ;
case RPMTAG_BUILDARCHS :
2008-06-13 00:53:07 +04:00
{
const char * * BANames = NULL ;
int BACount = 0 ;
if ( ( rc = poptParseArgvString ( field , & BACount , & BANames ) ) ) {
2002-03-25 23:16:26 +03:00
rpmError ( RPMERR_BADSPEC ,
_ ( " line %d: Bad BuildArchitecture format: %s \n " ) ,
spec - > lineNum , spec - > line ) ;
return RPMERR_BADSPEC ;
}
2008-06-13 00:53:07 +04:00
if ( pkg = = spec - > packages ) {
/* toplevel */
if ( BACount > 0 & & BANames ! = NULL ) {
spec - > BACount = BACount ;
spec - > BANames = BANames ;
BANames = NULL ; /* don't free */
}
}
else {
/* subpackage */
if ( BACount ! = 1 | | strcmp ( BANames [ 0 ] , " noarch " ) ) {
rpmError ( RPMERR_BADSPEC ,
_ ( " line %d: Only \" noarch \" sub-packages are supported: %s \n " ) ,
spec - > lineNum , spec - > line ) ;
BANames = _free ( BANames ) ;
return RPMERR_BADSPEC ;
}
headerAddEntry ( pkg - > header , RPMTAG_ARCH , RPM_STRING_TYPE , " noarch " , 1 ) ;
}
BANames = _free ( BANames ) ;
2002-03-25 23:16:26 +03:00
break ;
2008-06-13 00:53:07 +04:00
}
2002-03-25 23:16:26 +03:00
default :
rpmError ( RPMERR_INTERNAL , _ ( " Internal error: Bogus tag %d \n " ) , tag ) ;
return RPMERR_INTERNAL ;
}
if ( macro )
addMacro ( spec - > macros , macro , NULL , field , RMIL_SPEC ) ;
return 0 ;
}
/* This table has to be in a peculiar order. If one tag is the */
/* same as another, plus a few letters, it must come first. */
/**
*/
2009-06-01 15:45:44 +04:00
typedef const struct PreambleRec_s {
2002-03-25 23:16:26 +03:00
rpmTag tag ;
2010-03-29 10:35:25 +04:00
unsigned type ;
2009-06-01 15:45:44 +04:00
unsigned len ;
2002-03-25 23:16:26 +03:00
/*@observer@*/ /*@null@*/ const char * token ;
} * PreambleRec ;
2009-06-01 15:45:44 +04:00
# define LEN_AND_STR(_tag) (sizeof(_tag)-1), _tag
2002-03-25 23:16:26 +03:00
/*@unchecked@*/
2009-06-01 15:45:44 +04:00
static struct PreambleRec_s const preambleList [ ] = {
{ RPMTAG_NAME , 0 , LEN_AND_STR ( " name " ) } ,
{ RPMTAG_VERSION , 0 , LEN_AND_STR ( " version " ) } ,
{ RPMTAG_RELEASE , 0 , LEN_AND_STR ( " release " ) } ,
{ RPMTAG_EPOCH , 0 , LEN_AND_STR ( " epoch " ) } ,
{ RPMTAG_EPOCH , 0 , LEN_AND_STR ( " serial " ) } ,
{ RPMTAG_SUMMARY , 1 , LEN_AND_STR ( " summary " ) } ,
{ RPMTAG_LICENSE , 0 , LEN_AND_STR ( " copyright " ) } ,
{ RPMTAG_LICENSE , 0 , LEN_AND_STR ( " license " ) } ,
{ RPMTAG_DISTRIBUTION , 0 , LEN_AND_STR ( " distribution " ) } ,
{ RPMTAG_DISTURL , 0 , LEN_AND_STR ( " disturl " ) } ,
{ RPMTAG_BUILDHOST , 0 , LEN_AND_STR ( " buildhost " ) } ,
{ RPMTAG_VENDOR , 0 , LEN_AND_STR ( " vendor " ) } ,
{ RPMTAG_GROUP , 1 , LEN_AND_STR ( " group " ) } ,
{ RPMTAG_PACKAGER , 0 , LEN_AND_STR ( " packager " ) } ,
{ RPMTAG_URL , 0 , LEN_AND_STR ( " url " ) } ,
2010-02-23 19:02:46 +03:00
{ RPMTAG_VCS , 0 , LEN_AND_STR ( " vcs " ) } ,
2009-06-01 15:45:44 +04:00
{ RPMTAG_SOURCE , 0 , LEN_AND_STR ( " source " ) } ,
{ RPMTAG_PATCH , 0 , LEN_AND_STR ( " patch " ) } ,
{ RPMTAG_NOSOURCE , 0 , LEN_AND_STR ( " nosource " ) } ,
{ RPMTAG_NOPATCH , 0 , LEN_AND_STR ( " nopatch " ) } ,
{ RPMTAG_EXCLUDEARCH , 0 , LEN_AND_STR ( " excludearch " ) } ,
{ RPMTAG_EXCLUSIVEARCH , 0 , LEN_AND_STR ( " exclusivearch " ) } ,
{ RPMTAG_EXCLUDEOS , 0 , LEN_AND_STR ( " excludeos " ) } ,
{ RPMTAG_EXCLUSIVEOS , 0 , LEN_AND_STR ( " exclusiveos " ) } ,
{ RPMTAG_ICON , 0 , LEN_AND_STR ( " icon " ) } ,
{ RPMTAG_PROVIDEFLAGS , 0 , LEN_AND_STR ( " provides " ) } ,
2010-03-29 10:35:25 +04:00
{ RPMTAG_REQUIREFLAGS , 2 , LEN_AND_STR ( " requires " ) } ,
{ RPMTAG_PREREQ , 2 , LEN_AND_STR ( " prereq " ) } ,
2009-06-01 15:45:44 +04:00
{ RPMTAG_CONFLICTFLAGS , 0 , LEN_AND_STR ( " conflicts " ) } ,
{ RPMTAG_OBSOLETEFLAGS , 0 , LEN_AND_STR ( " obsoletes " ) } ,
{ RPMTAG_PREFIXES , 0 , LEN_AND_STR ( " prefixes " ) } ,
{ RPMTAG_PREFIXES , 0 , LEN_AND_STR ( " prefix " ) } ,
{ RPMTAG_BUILDROOT , 0 , LEN_AND_STR ( " buildroot " ) } ,
{ RPMTAG_BUILDARCHS , 0 , LEN_AND_STR ( " buildarchitectures " ) } ,
{ RPMTAG_BUILDARCHS , 0 , LEN_AND_STR ( " buildarch " ) } ,
{ RPMTAG_BUILDCONFLICTS , 0 , LEN_AND_STR ( " buildconflicts " ) } ,
2019-01-14 23:56:55 +03:00
{ RPMTAG_BUILDPREREQ , 0 , LEN_AND_STR ( " buildprereq " ) } ,
2010-03-29 10:35:25 +04:00
{ RPMTAG_BUILDREQUIRES , 2 , LEN_AND_STR ( " buildrequires " ) } ,
2009-06-01 15:45:44 +04:00
{ RPMTAG_AUTOREQPROV , 0 , LEN_AND_STR ( " autoreqprov " ) } ,
{ RPMTAG_AUTOREQ , 0 , LEN_AND_STR ( " autoreq " ) } ,
{ RPMTAG_AUTOPROV , 0 , LEN_AND_STR ( " autoprov " ) } ,
{ RPMTAG_DOCDIR , 0 , LEN_AND_STR ( " docdir " ) } ,
{ RPMTAG_DISTTAG , 0 , LEN_AND_STR ( " disttag " ) } ,
2002-03-25 23:16:26 +03:00
/*@-nullassign@*/ /* LCL: can't add null annotation */
{ 0 , 0 , 0 , 0 }
/*@=nullassign@*/
} ;
/**
*/
static int findPreambleTag ( Spec spec , /*@out@*/ int * tag ,
/*@null@*/ /*@out@*/ const char * * macro , /*@out@*/ char * lang )
/*@modifies *tag, *macro, *lang @*/
{
PreambleRec p ;
char * s ;
for ( p = preambleList ; p - > token ! = NULL ; p + + ) {
if ( p - > token & & ! xstrncasecmp ( spec - > line , p - > token , p - > len ) )
break ;
}
if ( p - > token = = NULL )
return 1 ;
s = spec - > line + p - > len ;
SKIPSPACE ( s ) ;
2010-03-29 10:35:25 +04:00
switch ( p - > type ) {
2002-03-25 23:16:26 +03:00
default :
case 0 :
/* Unless this is a source or a patch, a ':' better be next */
if ( p - > tag ! = RPMTAG_SOURCE & & p - > tag ! = RPMTAG_PATCH ) {
if ( * s ! = ' : ' ) return 1 ;
}
* lang = ' \0 ' ;
break ;
case 1 : /* Parse optional ( <token> ). */
2010-03-29 10:35:25 +04:00
case 2 :
2002-03-25 23:16:26 +03:00
if ( * s = = ' : ' ) {
2010-03-29 10:35:25 +04:00
/* Type 1 is multilang, 2 is qualifiers with no defaults */
strcpy ( lang , ( p - > type = = 1 ) ? RPMBUILD_DEFAULT_LANG : " " ) ;
2002-03-25 23:16:26 +03:00
break ;
}
if ( * s ! = ' ( ' ) return 1 ;
s + + ;
SKIPSPACE ( s ) ;
while ( ! xisspace ( * s ) & & * s ! = ' ) ' )
* lang + + = * s + + ;
* lang = ' \0 ' ;
SKIPSPACE ( s ) ;
if ( * s ! = ' ) ' ) return 1 ;
s + + ;
SKIPSPACE ( s ) ;
if ( * s ! = ' : ' ) return 1 ;
break ;
}
* tag = p - > tag ;
if ( macro )
/*@-onlytrans -observertrans -dependenttrans@*/ /* FIX: double indirection. */
* macro = p - > token ;
/*@=onlytrans =observertrans =dependenttrans@*/
return 0 ;
}
int parsePreamble ( Spec spec , int initialPackage )
{
int nextPart ;
int tag , rc , xx ;
char * name , * linep ;
int flag ;
Package pkg ;
char NVR [ BUFSIZ ] ;
char lang [ BUFSIZ ] ;
strcpy ( NVR , " (main package) " ) ;
pkg = newPackage ( spec ) ;
if ( ! initialPackage ) {
/* There is one option to %package: <pkg> or -n <pkg> */
if ( parseSimplePart ( spec - > line , & name , & flag ) ) {
rpmError ( RPMERR_BADSPEC , _ ( " Bad package specification: %s \n " ) ,
spec - > line ) ;
return RPMERR_BADSPEC ;
}
if ( ! lookupPackage ( spec , name , flag , NULL ) ) {
rpmError ( RPMERR_BADSPEC , _ ( " Package already exists: %s \n " ) ,
spec - > line ) ;
return RPMERR_BADSPEC ;
}
/* Construct the package */
if ( flag = = PART_SUBNAME ) {
const char * mainName ;
2019-02-25 05:06:13 +03:00
xx = headerName ( spec - > packages - > header , & mainName ) ;
2002-03-25 23:16:26 +03:00
sprintf ( NVR , " %s-%s " , mainName , name ) ;
} else
strcpy ( NVR , name ) ;
xx = headerAddEntry ( pkg - > header , RPMTAG_NAME , RPM_STRING_TYPE , NVR , 1 ) ;
}
2005-10-06 22:21:40 +04:00
if ( ( rc = readLine ( spec , STRIP_TRAILINGSPACE | STRIP_COMMENTS ) ) = = 1 ) {
2002-03-25 23:16:26 +03:00
nextPart = PART_NONE ;
} else {
if ( rc )
return rc ;
while ( ! ( nextPart = isPart ( spec - > line ) ) ) {
const char * macro ;
/* Skip blank lines */
linep = spec - > line ;
SKIPSPACE ( linep ) ;
if ( * linep ! = ' \0 ' ) {
if ( findPreambleTag ( spec , & tag , & macro , lang ) ) {
rpmError ( RPMERR_BADSPEC , _ ( " line %d: Unknown tag: %s \n " ) ,
spec - > lineNum , spec - > line ) ;
return RPMERR_BADSPEC ;
}
if ( handlePreambleTag ( spec , pkg , tag , macro , lang ) )
return RPMERR_BADSPEC ;
if ( spec - > BANames & & ! spec - > recursing )
return PART_BUILDARCHITECTURES ;
}
if ( ( rc =
2005-10-06 22:21:40 +04:00
readLine ( spec , STRIP_TRAILINGSPACE | STRIP_COMMENTS ) ) = = 1 ) {
2002-03-25 23:16:26 +03:00
nextPart = PART_NONE ;
break ;
}
if ( rc )
return rc ;
}
}
/* Do some final processing on the header */
if ( ! spec - > gotBuildRootURL & & spec - > buildRootURL ) {
rpmError ( RPMERR_BADSPEC , _ ( " Spec file can't use BuildRoot \n " ) ) ;
return RPMERR_BADSPEC ;
}
2002-03-26 01:57:16 +03:00
if ( ! spec - > buildRootURL ) {
spec - > buildRootURL = rpmGenPath ( NULL , " %{?buildroot:%{buildroot}} " , NULL ) ;
if ( strcmp ( spec - > buildRootURL , " / " ) )
spec - > gotBuildRootURL = 1 ;
else
{
spec - > buildRootURL = NULL ;
rpmError ( RPMERR_BADSPEC , _ ( " Neither spec file nor macros define BuildRoot " ) ) ;
return RPMERR_BADSPEC ;
}
}
2002-03-25 23:16:26 +03:00
/* XXX Skip valid arch check if not building binary package */
if ( ! spec - > anyarch & & checkForValidArchitectures ( spec ) )
return RPMERR_BADSPEC ;
if ( pkg = = spec - > packages )
fillOutMainPackage ( pkg - > header ) ;
if ( checkForDuplicates ( pkg - > header , NVR ) )
return RPMERR_BADSPEC ;
if ( pkg ! = spec - > packages )
headerCopyTags ( spec - > packages - > header , pkg - > header ,
( int_32 * ) copyTagsDuringParse ) ;
if ( checkForRequired ( pkg - > header , NVR ) )
return RPMERR_BADSPEC ;
return nextPart ;
}