- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

# build/parsePreamble.c

Go to the documentation of this file.

    00001
    00006 #include "system.h"
    00007
    00008 #include <rpmio.h>
    00009
    00010 #define _RPMEVR_INTERNAL
    00011 #define _RPMTAG_INTERNAL        /* XXX rpmTags->aTags */
    00012 #include <rpmbuild.h>
    00013 #include "debug.h"
    00014
    00015 /*@access FD_t @*/      /* compared with NULL */
    00016 /*@access headerTagIndices @*/  /* rpmTags->aTags */
    00017
    00020 /*@observer@*/ /*@unchecked@*/
    00021 static rpmTag copyTagsDuringParse[] = {
    00022     RPMTAG_EPOCH,
    00023     RPMTAG_VERSION,
    00024     RPMTAG_RELEASE,
    00025     RPMTAG_LICENSE,
    00026     RPMTAG_PACKAGER,
    00027     RPMTAG_DISTRIBUTION,
    00028     RPMTAG_DISTURL,
    00029     RPMTAG_VENDOR,
    00030     RPMTAG_ICON,
    00031     RPMTAG_GIF,
    00032     RPMTAG_XPM,
    00033     RPMTAG_URL,
    00034     RPMTAG_CHANGELOGTIME,
    00035     RPMTAG_CHANGELOGNAME,
    00036     RPMTAG_CHANGELOGTEXT,
    00037     RPMTAG_PREFIXES,
    00038     RPMTAG_DISTTAG,
    00039     RPMTAG_CVSID,
    00040     RPMTAG_VARIANTS,
    00041     RPMTAG_XMAJOR,
    00042     RPMTAG_XMINOR,
    00043     RPMTAG_REPOTAG,
    00044     RPMTAG_KEYWORDS,
    00045     0
    00046 };
    00047
    00050 /*@observer@*/ /*@unchecked@*/
    00051 static rpmTag requiredTags[] = {
    00052     RPMTAG_NAME,
    00053     RPMTAG_VERSION,
    00054     RPMTAG_RELEASE,
    00055     RPMTAG_SUMMARY,
    00056     RPMTAG_GROUP,
    00057     RPMTAG_LICENSE,
    00058     0
    00059 };
    00060
    00063 static void addOrAppendListEntry(Header h, rpmTag tag, char * line)
    00064         /*@modifies h @*/
    00065 {
    00066     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
    00067     int xx;
    00068     int argc;
    00069     const char **argv;
    00070
    00071     xx = poptParseArgvString(line, &argc, &argv);
    00072     if (argc) {
    00073         he->tag = tag;
    00074         he->t = RPM_STRING_ARRAY_TYPE;
    00075         he->p.argv = argv;
    00076         he->c = argc;
    00077         he->append = 1;
    00078         xx = headerPut(h, he, 0);
    00079         he->append = 0;
    00080     }
    00081     argv = _free(argv);
    00082 }
    00083
    00084 /* Parse a simple part line that only take -n <pkg> or <pkg> */
    00085 /* <pkg> is return in name as a pointer into a static buffer */
    00086
    00089 static int parseSimplePart(char *line, /*@out@*/char **name,
    00090                 /*@out@*/rpmParseState *flag)
    00091         /*@globals internalState@*/
    00092         /*@modifies *name, *flag, internalState @*/
    00093 {
    00094     char *tok;
    00095     char linebuf[BUFSIZ];
    00096     static char buf[BUFSIZ];
    00097
    00098     strcpy(linebuf, line);
    00099
    00100     /* Throw away the first token (the %xxxx) */
    00101     (void)strtok(linebuf, " \t\n");
    00102
    00103     if (!(tok = strtok(NULL, " \t\n"))) {
    00104         *name = NULL;
    00105         return 0;
    00106     }
    00107
    00108     if (!strcmp(tok, "-n")) {
    00109         if (!(tok = strtok(NULL, " \t\n")))
    00110             return 1;
    00111         *flag = PART_NAME;
    00112     } else {
    00113         *flag = PART_SUBNAME;
    00114     }
    00115     strcpy(buf, tok);
    00116     *name = buf;
    00117
    00118     return (strtok(NULL, " \t\n")) ? 1 : 0;
    00119 }
    00120
    00123 static inline int parseYesNo(const char * s)
    00124         /*@*/
    00125 {
    00126     return ((!s || (s[0] == 'n' || s[0] == 'N' || s[0] == '0') ||
    00127         !xstrcasecmp(s, "false") || !xstrcasecmp(s, "off"))
    00128             ? 0 : 1);
    00129 }
    00130
    00131 typedef struct tokenBits_s {
    00132 /*@observer@*/ /*@null@*/
    00133     const char * name;
    00134     rpmsenseFlags bits;
    00135 } * tokenBits;
    00136
    00139 /*@observer@*/ /*@unchecked@*/
    00140 static struct tokenBits_s installScriptBits[] = {
    00141     { "interp",         RPMSENSE_INTERP },
    00142     { "preun",          RPMSENSE_SCRIPT_PREUN },
    00143     { "pre",            RPMSENSE_SCRIPT_PRE },
    00144     { "postun",         RPMSENSE_SCRIPT_POSTUN },
    00145     { "post",           RPMSENSE_SCRIPT_POST },
    00146     { "rpmlib",         RPMSENSE_RPMLIB },
    00147     { "verify",         RPMSENSE_SCRIPT_VERIFY },
    00148     { "hint",           RPMSENSE_MISSINGOK },
    00149     { NULL, 0 }
    00150 };
    00151
    00154 /*@observer@*/ /*@unchecked@*/
    00155 static struct tokenBits_s buildScriptBits[] = {
    00156     { "prep",           RPMSENSE_SCRIPT_PREP },
    00157     { "build",          RPMSENSE_SCRIPT_BUILD },
    00158     { "install",        RPMSENSE_SCRIPT_INSTALL },
    00159     { "clean",          RPMSENSE_SCRIPT_CLEAN },
    00160     { "hint",           RPMSENSE_MISSINGOK },
    00161     { NULL, 0 }
    00162 };
    00163
    00166 static int parseBits(const char * s, const tokenBits tokbits,
    00167                 /*@out@*/ rpmsenseFlags * bp)
    00168         /*@modifies *bp @*/
    00169 {
    00170     tokenBits tb;
    00171     const char * se;
    00172     rpmsenseFlags bits = RPMSENSE_ANY;
    00173     int c = 0;
    00174
    00175     if (s) {
    00176         while (*s != '\0') {
    00177             while ((c = *s) && xisspace(c)) s++;
    00178             se = s;
    00179             while ((c = *se) && xisalpha(c)) se++;
    00180             if (s == se)
    00181                 break;
    00182             for (tb = tokbits; tb->name; tb++) {
    00183                 if (tb->name != NULL &&
    00184                     strlen(tb->name) == (se-s) && !strncmp(tb->name, s, (se-s)))
    00185                     /*@innerbreak@*/ break;
    00186             }
    00187             if (tb->name == NULL)
    00188                 break;
    00189             bits |= tb->bits;
    00190             while ((c = *se) && xisspace(c)) se++;
    00191             if (c != ',')
    00192                 break;
    00193             s = ++se;
    00194         }
    00195     }
    00196     if (c == 0 && bp) *bp = bits;
    00197     return (c ? RPMRC_FAIL : RPMRC_OK);
    00198 }
    00199
    00202 static inline char * findLastChar(char * s)
    00203         /*@modifies *s @*/
    00204 {
    00205     char *se = s + strlen(s);
    00206
    00207     while (--se > s && strchr(" \t\n\r", *se) != NULL)
    00208         *se = '\0';
    00209 /*@-temptrans -retalias @*/
    00210     return se;
    00211 /*@=temptrans =retalias @*/
    00212 }
    00213
    00216 static int isMemberInEntry(Header h, const char *name, rpmTag tag)
    00217         /*@*/
    00218 {
    00219     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
    00220     int rc = -1;
    00221     int xx;
    00222
    00223     he->tag = tag;
    00224     xx = headerGet(h, he, 0);
    00225     if (!xx)
    00226         return rc;
    00227     rc = 0;
    00228     while (he->c) {
    00229         he->c--;
    00230         if (xstrcasecmp(he->p.argv[he->c], name))
    00231             continue;
    00232         rc = 1;
    00233         break;
    00234     }
    00235     he->p.ptr = _free(he->p.ptr);
    00236     return rc;
    00237 }
    00238
    00241 static int checkForValidArchitectures(Spec spec)
    00242         /*@globals rpmGlobalMacroContext, h_errno @*/
    00243         /*@modifies rpmGlobalMacroContext @*/
    00244 {
    00245     const char *arch = rpmExpand("%{_target_cpu}", NULL);
    00246     const char *os = rpmExpand("%{_target_os}", NULL);
    00247     int rc = RPMRC_FAIL;        /* assume failure. */
    00248
    00249     if (isMemberInEntry(spec->sourceHeader, arch, RPMTAG_EXCLUDEARCH) == 1) {
    00250         rpmlog(RPMLOG_ERR, _("Architecture is excluded: %s\n"), arch);
    00251         goto exit;
    00252     }
    00253     if (isMemberInEntry(spec->sourceHeader, arch, RPMTAG_EXCLUSIVEARCH) == 0) {
    00254         rpmlog(RPMLOG_ERR, _("Architecture is not included: %s\n"), arch);
    00255         goto exit;
    00256     }
    00257     if (isMemberInEntry(spec->sourceHeader, os, RPMTAG_EXCLUDEOS) == 1) {
    00258         rpmlog(RPMLOG_ERR, _("OS is excluded: %s\n"), os);
    00259         goto exit;
    00260     }
    00261     if (isMemberInEntry(spec->sourceHeader, os, RPMTAG_EXCLUSIVEOS) == 0) {
    00262         rpmlog(RPMLOG_ERR, _("OS is not included: %s\n"), os);
    00263         goto exit;
    00264     }
    00265     rc = 0;
    00266 exit:
    00267     arch = _free(arch);
    00268     os = _free(os);
    00269     return rc;
    00270 }
    00271
    00278 static rpmRC checkForRequired(Header h, const char * NVR)
    00279         /*@modifies h @*/
    00280 {
    00281     rpmTag * p;
    00282     rpmRC rc = RPMRC_OK;
    00283
    00284     for (p = requiredTags; *p != 0; p++) {
    00285         if (!headerIsEntry(h, *p)) {
    00286             rpmlog(RPMLOG_ERR,
    00287                         _("%s field must be present in package: %s\n"),
    00288                         tagName(*p), NVR);
    00289             rc = RPMRC_FAIL;
    00290         }
    00291     }
    00292
    00293     return rc;
    00294 }
    00295
    00302 static rpmRC checkForDuplicates(Header h, const char * NVR)
    00303         /*@modifies h @*/
    00304 {
    00305     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
    00306     HeaderIterator hi;
    00307     rpmTag lastTag = 0;
    00308     rpmRC rc = RPMRC_OK;
    00309
    00310     for (hi = headerInit(h);
    00311         headerNext(hi, he, 0);
    00312         he->p.ptr = _free(he->p.ptr))
    00313     {
    00314         if (he->tag != lastTag) {
    00315             lastTag = he->tag;
    00316             continue;
    00317         }
    00318         rpmlog(RPMLOG_ERR, _("Duplicate %s entries in package: %s\n"),
    00319                      tagName(he->tag), NVR);
    00320         rc = RPMRC_FAIL;
    00321     }
    00322     hi = headerFini(hi);
    00323
    00324     return rc;
    00325 }
    00326
    00329 /*@observer@*/ /*@unchecked@*/
    00330 static struct optionalTag {
    00331     rpmTag      ot_tag;
    00332 /*@observer@*/ /*@null@*/
    00333     const char * ot_mac;
    00334 } optionalTags[] = {
    00335     { RPMTAG_VENDOR,            "%{vendor}" },
    00336     { RPMTAG_PACKAGER,          "%{packager}" },
    00337     { RPMTAG_DISTRIBUTION,      "%{distribution}" },
    00338     { RPMTAG_DISTURL,           "%{disturl}" },
    00339     { 0xffffffff,               "%{class}" },
    00340     { -1, NULL }
    00341 };
    00342
    00345 static void fillOutMainPackage(Header h)
    00346         /*@globals rpmGlobalMacroContext, h_errno @*/
    00347         /*@modifies h, rpmGlobalMacroContext @*/
    00348 {
    00349     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
    00350     struct optionalTag *ot;
    00351     int xx;
    00352
    00353     for (ot = optionalTags; ot->ot_mac != NULL; ot++) {
    00354         const char * val;
    00355         rpmTag tag;
    00356
    00357         tag = ot->ot_tag;
    00358
    00359         /* Generate arbitrary tag (if necessary). */
    00360         if (tag == 0xffffffff) {
    00361             val = tagCanonicalize(ot->ot_mac + (sizeof("%{")-1));
    00362             tag = tagGenerate(val);
    00363             val = _free(val);
    00364         }
    00365
    00366         if (headerIsEntry(h, tag))
    00367             continue;
    00368         val = rpmExpand(ot->ot_mac, NULL);
    00369         if (val && *val != '%') {
    00370                 he->tag = tag;
    00371                 he->t = RPM_STRING_TYPE;
    00372                 he->p.str = val;
    00373                 he->c = 1;
    00374                 xx = headerPut(h, he, 0);
    00375         }
    00376         val = _free(val);
    00377     }
    00378 }
    00379
    00382 static int doIcon(Spec spec, Header h)
    00383         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
    00384         /*@modifies h, rpmGlobalMacroContext, fileSystem, internalState  @*/
    00385 {
    00386     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
    00387     const char *fn, *Lurlfn = NULL;
    00388     struct Source *sp;
    00389     size_t iconsize = 2048;     /* XXX big enuf */
    00390     size_t nb;
    00391     uint8_t * icon = alloca(iconsize+1);
    00392     FD_t fd = NULL;
    00393     int rc = RPMRC_FAIL;        /* assume error */
    00394     int urltype;
    00395     int xx;
    00396
    00397     for (sp = spec->sources; sp != NULL; sp = sp->next) {
    00398         if (sp->flags & RPMFILE_ICON)
    00399             break;
    00400     }
    00401     if (sp == NULL) {
    00402         rpmlog(RPMLOG_ERR, _("No icon file in sources\n"));
    00403         goto exit;
    00404     }
    00405
    00406 #if defined(RPM_VENDOR_OPENPKG) /* splitted-source-directory */
    00407     /* support splitted source directories, i.e., source files which
    00408        are alternatively placed into the .spec directory and picked
    00409        up from there, too. */
    00410     Lurlfn = rpmGenPath(NULL, "%{_specdir}/", sp->source);
    00411     if (access(Lurlfn, F_OK) == -1) {
    00412         Lurlfn = _free(Lurlfn);
    00413         Lurlfn = rpmGenPath(NULL, "%{_icondir}/", sp->source);
    00414     }
    00415 #else
    00416     Lurlfn = rpmGenPath(NULL, "%{_icondir}/", sp->source);
    00417 #endif
    00418
    00419     fn = NULL;
    00420     urltype = urlPath(Lurlfn, &fn);
    00421     switch (urltype) {
    00422     case URL_IS_HTTPS:
    00423     case URL_IS_HTTP:
    00424     case URL_IS_FTP:
    00425     case URL_IS_PATH:
    00426     case URL_IS_UNKNOWN:
    00427         break;
    00428     case URL_IS_DASH:
    00429     case URL_IS_HKP:
    00430         rpmlog(RPMLOG_ERR, _("Invalid icon URL: %s\n"), Lurlfn);
    00431         goto exit;
    00432         /*@notreached@*/ break;
    00433     }
    00434
    00435     fd = Fopen(fn, "r.fdio");
    00436     if (fd == NULL || Ferror(fd)) {
    00437         rpmlog(RPMLOG_ERR, _("Unable to open icon %s: %s\n"),
    00438                 fn, Fstrerror(fd));
    00439         rc = RPMRC_FAIL;
    00440         goto exit;
    00441     }
    00442
    00443     *icon = '\0';
    00444     nb = Fread(icon, sizeof(icon[0]), iconsize, fd);
    00445     if (Ferror(fd) || nb == 0) {
    00446         rpmlog(RPMLOG_ERR, _("Unable to read icon %s: %s\n"),
    00447                 fn, Fstrerror(fd));
    00448         goto exit;
    00449     }
    00450     if (nb >= iconsize) {
    00451         rpmlog(RPMLOG_ERR, _("Icon %s is too big (max. %d bytes)\n"),
    00452                 fn, iconsize);
    00453         goto exit;
    00454     }
    00455
    00456     if (icon[0] == 'G' && icon[1] == 'I' && icon[2] == 'F') {
    00457         he->tag = RPMTAG_GIF;
    00458         he->t = RPM_BIN_TYPE;
    00459         he->p.ui8p = icon;
    00460         he->c = nb;
    00461         xx = headerPut(h, he, 0);
    00462     } else
    00463     if (icon[0] == '/' && icon[1] == '*' && icon[2] == ' '
    00464      && icon[3] == 'X' && icon[4] == 'P' && icon[5] == 'M')
    00465     {
    00466         he->tag = RPMTAG_XPM;
    00467         he->t = RPM_BIN_TYPE;
    00468         he->p.ui8p = icon;
    00469         he->c = nb;
    00470         xx = headerPut(h, he, 0);
    00471     } else {
    00472         rpmlog(RPMLOG_ERR, _("Unknown icon type: %s\n"), fn);
    00473         goto exit;
    00474     }
    00475     rc = 0;
    00476
    00477 exit:
    00478     if (fd) {
    00479         (void) Fclose(fd);
    00480         fd = NULL;
    00481     }
    00482     Lurlfn = _free(Lurlfn);
    00483     return rc;
    00484 }
    00485
    00486 spectag stashSt(Spec spec, Header h, int tag, const char * lang)
    00487 {
    00488     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
    00489     spectag t = NULL;
    00490     int xx;
    00491
    00492     if (spec->st) {
    00493         spectags st = spec->st;
    00494         if (st->st_ntags == st->st_nalloc) {
    00495             st->st_nalloc += 10;
    00496             st->st_t = xrealloc(st->st_t, st->st_nalloc * sizeof(*(st->st_t)));
    00497         }
    00498         t = st->st_t + st->st_ntags++;
    00499         t->t_tag = tag;
    00500         t->t_startx = spec->lineNum - 1;
    00501         t->t_nlines = 1;
    00502         t->t_lang = xstrdup(lang);
    00503         t->t_msgid = NULL;
    00504         if (!(t->t_lang && strcmp(t->t_lang, RPMBUILD_DEFAULT_LANG))) {
    00505             he->tag = RPMTAG_NAME;
    00506             xx = headerGet(h, he, 0);
    00507             if (xx) {
    00508                 char buf[1024];
    00509                 sprintf(buf, "%s(%s)", he->p.str, tagName(tag));
    00510                 t->t_msgid = xstrdup(buf);
    00511             }
    00512             he->p.ptr = _free(he->p.ptr);
    00513         }
    00514     }
    00515     /*@-usereleased -compdef@*/
    00516     return t;
    00517     /*@=usereleased =compdef@*/
    00518 }
    00519
    00520 #define SINGLE_TOKEN_ONLY \
    00521 if (multiToken) { \
    00522     rpmlog(RPMLOG_ERR, _("line %d: Tag takes single token only: %s\n"), \
    00523              spec->lineNum, spec->line); \
    00524     return RPMRC_FAIL; \
    00525 }
    00526
    00527 /*@-redecl@*/
    00528 extern int noLang;
    00529 /*@=redecl@*/
    00530
    00533 static rpmRC handlePreambleTag(Spec spec, Package pkg, rpmTag tag,
    00534                 const char *macro, const char *lang)
    00535         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
    00536         /*@modifies spec->macros, spec->st,
    00537                 spec->sources, spec->numSources, spec->noSource,
    00538                 spec->sourceHeader, spec->BANames, spec->BACount,
    00539                 spec->line,
    00540                 pkg->header, pkg->autoProv, pkg->autoReq,
    00541                 rpmGlobalMacroContext, fileSystem, internalState @*/
    00542 {
    00543     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
    00544     char * field = spec->line;
    00545     char * end;
    00546     int multiToken = 0;
    00547     rpmsenseFlags tagflags;
    00548     int len;
    00549     uint32_t num;
    00550     int rc;
    00551     int xx;
    00552
    00553     if (field == NULL) return RPMRC_FAIL;       /* XXX can't happen */
    00554     /* Find the start of the "field" and strip trailing space */
    00555     while ((*field) && (*field != ':'))
    00556         field++;
    00557     if (*field != ':') {
    00558         rpmlog(RPMLOG_ERR, _("line %d: Malformed tag: %s\n"),
    00559                  spec->lineNum, spec->line);
    00560         return RPMRC_FAIL;
    00561     }
    00562     field++;
    00563     SKIPSPACE(field);
    00564     if (!*field) {
    00565         /* Empty field */
    00566         rpmlog(RPMLOG_ERR, _("line %d: Empty tag: %s\n"),
    00567                  spec->lineNum, spec->line);
    00568         return RPMRC_FAIL;
    00569     }
    00570     end = findLastChar(field);
    00571
    00572     /* See if this is multi-token */
    00573     end = field;
    00574     SKIPNONSPACE(end);
    00575     if (*end != '\0')
    00576         multiToken = 1;
    00577
    00578     switch (tag) {
    00579     case RPMTAG_NAME:
    00580     case RPMTAG_VERSION:
    00581     case RPMTAG_RELEASE:
    00582     case RPMTAG_URL:
    00583     case RPMTAG_DISTTAG:
    00584     case RPMTAG_REPOTAG:
    00585     case RPMTAG_CVSID:
    00586         SINGLE_TOKEN_ONLY;
    00587         /* These macros are for backward compatibility */
    00588         if (tag == RPMTAG_VERSION) {
    00589             if (strchr(field, '-') != NULL) {
    00590                 rpmlog(RPMLOG_ERR, _("line %d: Illegal char '-' in %s: %s\n"),
    00591                     spec->lineNum, "version", spec->line);
    00592                 return RPMRC_FAIL;
    00593             }
    00594             addMacro(spec->macros, "PACKAGE_VERSION", NULL, field, RMIL_OLDSPEC);
    00595         } else if (tag == RPMTAG_RELEASE) {
    00596             if (strchr(field, '-') != NULL) {
    00597                 rpmlog(RPMLOG_ERR, _("line %d: Illegal char '-' in %s: %s\n"),
    00598                     spec->lineNum, "release", spec->line);
    00599                 return RPMRC_FAIL;
    00600             }
    00601             addMacro(spec->macros, "PACKAGE_RELEASE", NULL, field, RMIL_OLDSPEC-1);
    00602         }
    00603         he->tag = tag;
    00604         he->t = RPM_STRING_TYPE;
    00605         he->p.str = field;
    00606         he->c = 1;
    00607         xx = headerPut(pkg->header, he, 0);
    00608         break;
    00609     case RPMTAG_GROUP:
    00610     case RPMTAG_SUMMARY:
    00611 #if defined(RPM_VENDOR_OPENPKG) /* make-class-available-as-macro */
    00612     case RPMTAG_CLASS:
    00613 #endif
    00614         (void) stashSt(spec, pkg->header, tag, lang);
    00615         /*@fallthrough@*/
    00616     case RPMTAG_DISTRIBUTION:
    00617     case RPMTAG_VENDOR:
    00618     case RPMTAG_LICENSE:
    00619     case RPMTAG_PACKAGER:
    00620         if (!*lang) {
    00621             he->tag = tag;
    00622             he->t = RPM_STRING_TYPE;
    00623             he->p.str = field;
    00624             he->c = 1;
    00625             xx = headerPut(pkg->header, he, 0);
    00626         } else if (!(noLang && strcmp(lang, RPMBUILD_DEFAULT_LANG))) {
    00627             (void) headerAddI18NString(pkg->header, tag, field, lang);
    00628         }
    00629         break;
    00630     /* XXX silently ignore BuildRoot: */
    00631     case RPMTAG_BUILDROOT:
    00632         SINGLE_TOKEN_ONLY;
    00633         macro = NULL;
    00634 #ifdef  DYING
    00635         buildRootURL = rpmGenPath(spec->rootURL, "%{?buildroot}", NULL);
    00636         (void) urlPath(buildRootURL, &buildRoot);
    00637         if (*buildRoot == '\0') buildRoot = "/";
    00638         if (!strcmp(buildRoot, "/")) {
    00639             rpmlog(RPMLOG_ERR,
    00640                      _("BuildRoot can not be \"/\": %s\n"), spec->buildRootURL);
    00641             buildRootURL = _free(buildRootURL);
    00642             return RPMRC_FAIL;
    00643         }
    00644         buildRootURL = _free(buildRootURL);
    00645 #endif
    00646         break;
    00647     case RPMTAG_KEYWORDS:
    00648     case RPMTAG_VARIANTS:
    00649     case RPMTAG_PREFIXES:
    00650         addOrAppendListEntry(pkg->header, tag, field);
    00651         he->tag = tag;
    00652         xx = headerGet(pkg->header, he, 0);
    00653         if (tag == RPMTAG_PREFIXES)
    00654         while (he->c--) {
    00655             if (he->p.argv[he->c][0] != '/') {
    00656                 rpmlog(RPMLOG_ERR,
    00657                          _("line %d: Prefixes must begin with \"/\": %s\n"),
    00658                          spec->lineNum, spec->line);
    00659                 he->p.ptr = _free(he->p.ptr);
    00660                 return RPMRC_FAIL;
    00661             }
    00662             len = strlen(he->p.argv[he->c]);
    00663             if (he->p.argv[he->c][len - 1] == '/' && len > 1) {
    00664                 rpmlog(RPMLOG_ERR,
    00665                          _("line %d: Prefixes must not end with \"/\": %s\n"),
    00666                          spec->lineNum, spec->line);
    00667                 he->p.ptr = _free(he->p.ptr);
    00668                 return RPMRC_FAIL;
    00669             }
    00670         }
    00671         he->p.ptr = _free(he->p.ptr);
    00672         break;
    00673     case RPMTAG_DOCDIR:
    00674         SINGLE_TOKEN_ONLY;
    00675         if (field[0] != '/') {
    00676             rpmlog(RPMLOG_ERR,
    00677                      _("line %d: Docdir must begin with '/': %s\n"),
    00678                      spec->lineNum, spec->line);
    00679             return RPMRC_FAIL;
    00680         }
    00681         macro = NULL;
    00682         delMacro(NULL, "_docdir");
    00683         addMacro(NULL, "_docdir", NULL, field, RMIL_SPEC);
    00684         break;
    00685     case RPMTAG_XMAJOR:
    00686     case RPMTAG_XMINOR:
    00687     case RPMTAG_EPOCH:
    00688         SINGLE_TOKEN_ONLY;
    00689         if (parseNum(field, &num)) {
    00690             rpmlog(RPMLOG_ERR,
    00691                      _("line %d: %s takes an integer value: %s\n"),
    00692                      spec->lineNum, tagName(tag), spec->line);
    00693             return RPMRC_FAIL;
    00694         }
    00695         he->tag = tag;
    00696         he->t = RPM_UINT32_TYPE;
    00697         he->p.ui32p = &num;
    00698         he->c = 1;
    00699         xx = headerPut(pkg->header, he, 0);
    00700         break;
    00701     case RPMTAG_AUTOREQPROV:
    00702         pkg->autoReq = parseYesNo(field);
    00703         pkg->autoProv = pkg->autoReq;
    00704         break;
    00705     case RPMTAG_AUTOREQ:
    00706         pkg->autoReq = parseYesNo(field);
    00707         break;
    00708     case RPMTAG_AUTOPROV:
    00709         pkg->autoProv = parseYesNo(field);
    00710         break;
    00711     case RPMTAG_SOURCE:
    00712     case RPMTAG_PATCH:
    00713         SINGLE_TOKEN_ONLY;
    00714         macro = NULL;
    00715         if ((rc = addSource(spec, pkg, field, tag)))
    00716             return rc;
    00717         break;
    00718     case RPMTAG_ICON:
    00719         SINGLE_TOKEN_ONLY;
    00720         macro = NULL;
    00721         if ((rc = addSource(spec, pkg, field, tag)))
    00722             return rc;
    00723         /* XXX the fetch/load of icon needs to be elsewhere. */
    00724         if ((rc = doIcon(spec, pkg->header)))
    00725             return rc;
    00726         break;
    00727     case RPMTAG_NOSOURCE:
    00728     case RPMTAG_NOPATCH:
    00729         spec->noSource = 1;
    00730         if ((rc = parseNoSource(spec, field, tag)))
    00731             return rc;
    00732         break;
    00733     case RPMTAG_BUILDPREREQ:
    00734     case RPMTAG_BUILDREQUIRES:
    00735         if ((rc = parseBits(lang, buildScriptBits, &tagflags))) {
    00736             rpmlog(RPMLOG_ERR,
    00737                      _("line %d: Bad %s: qualifiers: %s\n"),
    00738                      spec->lineNum, tagName(tag), spec->line);
    00739             return rc;
    00740         }
    00741         if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags)))
    00742             return rc;
    00743         break;
    00744     case RPMTAG_PREREQ:
    00745     case RPMTAG_REQUIREFLAGS:
    00746         if ((rc = parseBits(lang, installScriptBits, &tagflags))) {
    00747             rpmlog(RPMLOG_ERR,
    00748                      _("line %d: Bad %s: qualifiers: %s\n"),
    00749                      spec->lineNum, tagName(tag), spec->line);
    00750             return rc;
    00751         }
    00752         if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags)))
    00753             return rc;
    00754         break;
    00755     /* Aliases for BuildRequires(hint): */
    00756     case RPMTAG_BUILDSUGGESTS:
    00757     case RPMTAG_BUILDENHANCES:
    00758         tagflags = RPMSENSE_MISSINGOK;
    00759         if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags)))
    00760             return rc;
    00761         break;
    00762     /* Aliases for Requires(hint): */
    00763     case RPMTAG_SUGGESTSFLAGS:
    00764     case RPMTAG_ENHANCESFLAGS:
    00765         tag = RPMTAG_REQUIREFLAGS;
    00766         tagflags = RPMSENSE_MISSINGOK;
    00767         if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags)))
    00768             return rc;
    00769         break;
    00770     case RPMTAG_BUILDOBSOLETES:
    00771     case RPMTAG_BUILDPROVIDES:
    00772     case RPMTAG_BUILDCONFLICTS:
    00773     case RPMTAG_CONFLICTFLAGS:
    00774     case RPMTAG_OBSOLETEFLAGS:
    00775     case RPMTAG_PROVIDEFLAGS:
    00776         tagflags = RPMSENSE_ANY;
    00777         if ((rc = parseRCPOT(spec, pkg, field, tag, 0, tagflags)))
    00778             return rc;
    00779         break;
    00780     case RPMTAG_BUILDPLATFORMS:         /* XXX needs pattern parsing */
    00781     case RPMTAG_EXCLUDEARCH:
    00782     case RPMTAG_EXCLUSIVEARCH:
    00783     case RPMTAG_EXCLUDEOS:
    00784     case RPMTAG_EXCLUSIVEOS:
    00785         addOrAppendListEntry(spec->sourceHeader, tag, field);
    00786         break;
    00787     case RPMTAG_BUILDARCHS:
    00788         if ((rc = poptParseArgvString(field,
    00789                                       &(spec->BACount),
    00790                                       &(spec->BANames)))) {
    00791             rpmlog(RPMLOG_ERR,
    00792                      _("line %d: Bad BuildArchitecture format: %s\n"),
    00793                      spec->lineNum, spec->line);
    00794             return RPMRC_FAIL;
    00795         }
    00796         if (!spec->BACount)
    00797             spec->BANames = _free(spec->BANames);
    00798         break;
    00799
    00800     default:
    00801         macro = NULL;
    00802         he->tag = tag;
    00803         he->t = RPM_STRING_ARRAY_TYPE;
    00804         he->p.argv= (const char **) &field;     /* XXX NOCAST */
    00805         he->c = 1;
    00806         he->append = 1;
    00807         xx = headerPut(pkg->header, he, 0);
    00808         he->append = 0;
    00809         break;
    00810     }
    00811
    00812     if (macro)
    00813         addMacro(spec->macros, macro, NULL, field, RMIL_SPEC);
    00814
    00815     return RPMRC_OK;
    00816 }
    00817
    00818 /* This table has to be in a peculiar order.  If one tag is the */
    00819 /* same as another, plus a few letters, it must come first.     */
    00820
    00823 typedef struct PreambleRec_s {
    00824     rpmTag tag;
    00825     int multiLang;
    00826     int obsolete;
    00827 /*@observer@*/ /*@null@*/
    00828     const char * token;
    00829 } * PreambleRec;
    00830
    00831 /*@unchecked@*/
    00832 static struct PreambleRec_s preambleList[] = {
    00833     {RPMTAG_NAME,               0, 0, "name"},
    00834     {RPMTAG_VERSION,            0, 0, "version"},
    00835     {RPMTAG_RELEASE,            0, 0, "release"},
    00836     {RPMTAG_EPOCH,              0, 0, "epoch"},
    00837     {RPMTAG_EPOCH,              0, 1, "serial"},
    00838     {RPMTAG_SUMMARY,            1, 0, "summary"},
    00839     {RPMTAG_LICENSE,            0, 0, "copyright"},
    00840     {RPMTAG_LICENSE,            0, 0, "license"},
    00841     {RPMTAG_DISTRIBUTION,       0, 0, "distribution"},
    00842     {RPMTAG_DISTURL,            0, 0, "disturl"},
    00843     {RPMTAG_VENDOR,             0, 0, "vendor"},
    00844     {RPMTAG_GROUP,              1, 0, "group"},
    00845     {RPMTAG_PACKAGER,           0, 0, "packager"},
    00846     {RPMTAG_URL,                0, 0, "url"},
    00847     {RPMTAG_SOURCE,             0, 0, "source"},
    00848     {RPMTAG_PATCH,              0, 0, "patch"},
    00849     {RPMTAG_NOSOURCE,           0, 0, "nosource"},
    00850     {RPMTAG_NOPATCH,            0, 0, "nopatch"},
    00851     {RPMTAG_EXCLUDEARCH,        0, 0, "excludearch"},
    00852     {RPMTAG_EXCLUSIVEARCH,      0, 0, "exclusivearch"},
    00853     {RPMTAG_EXCLUDEOS,          0, 0, "excludeos"},
    00854     {RPMTAG_EXCLUSIVEOS,        0, 0, "exclusiveos"},
    00855     {RPMTAG_ICON,               0, 0, "icon"},
    00856     {RPMTAG_PROVIDEFLAGS,       0, 0, "provides"},
    00857     {RPMTAG_REQUIREFLAGS,       1, 0, "requires"},
    00858     {RPMTAG_PREREQ,             1, 0, "prereq"},
    00859     {RPMTAG_CONFLICTFLAGS,      0, 0, "conflicts"},
    00860     {RPMTAG_OBSOLETEFLAGS,      0, 0, "obsoletes"},
    00861     {RPMTAG_PREFIXES,           0, 0, "prefixes"},
    00862     {RPMTAG_PREFIXES,           0, 0, "prefix"},
    00863     {RPMTAG_BUILDROOT,          0, 0, "buildroot"},
    00864     {RPMTAG_BUILDARCHS,         0, 0, "buildarchitectures"},
    00865     {RPMTAG_BUILDARCHS,         0, 0, "buildarch"},
    00866     {RPMTAG_BUILDCONFLICTS,     0, 0, "buildconflicts"},
    00867     {RPMTAG_BUILDOBSOLETES,     0, 0, "buildobsoletes"},
    00868     {RPMTAG_BUILDPREREQ,        1, 0, "buildprereq"},
    00869     {RPMTAG_BUILDPROVIDES,      0, 0, "buildprovides"},
    00870     {RPMTAG_BUILDREQUIRES,      1, 0, "buildrequires"},
    00871     {RPMTAG_AUTOREQPROV,        0, 0, "autoreqprov"},
    00872     {RPMTAG_AUTOREQ,            0, 0, "autoreq"},
    00873     {RPMTAG_AUTOPROV,           0, 0, "autoprov"},
    00874     {RPMTAG_DOCDIR,             0, 0, "docdir"},
    00875     {RPMTAG_DISTTAG,            0, 0, "disttag"},
    00876     {RPMTAG_CVSID,              0, 0, "cvsid"},
    00877     {RPMTAG_SVNID,              0, 0, "svnid"},
    00878     {RPMTAG_SUGGESTSFLAGS,      0, 0, "suggests"},
    00879     {RPMTAG_ENHANCESFLAGS,      0, 0, "enhances"},
    00880     {RPMTAG_BUILDSUGGESTS,      0, 0, "buildsuggests"},
    00881     {RPMTAG_BUILDENHANCES,      0, 0, "buildenhances"},
    00882     {RPMTAG_VARIANTS,           0, 0, "variants"},
    00883     {RPMTAG_VARIANTS,           0, 0, "variant"},
    00884     {RPMTAG_XMAJOR,             0, 0, "xmajor"},
    00885     {RPMTAG_XMINOR,             0, 0, "xminor"},
    00886     {RPMTAG_REPOTAG,            0, 0, "repotag"},
    00887     {RPMTAG_KEYWORDS,           0, 0, "keywords"},
    00888     {RPMTAG_KEYWORDS,           0, 0, "keyword"},
    00889     {RPMTAG_BUILDPLATFORMS,     0, 0, "buildplatforms"},
    00890 #if defined(RPM_VENDOR_OPENPKG) /* make-class-available-as-macro */
    00891     {RPMTAG_CLASS,              0, 0, "class"},
    00892 #endif
    00893     /*@-nullassign@*/   /* LCL: can't add null annotation */
    00894     {0, 0, 0, 0}
    00895     /*@=nullassign@*/
    00896 };
    00897
    00900 static int findPreambleTag(Spec spec, /*@out@*/rpmTag * tagp,
    00901                 /*@null@*/ /*@out@*/ const char ** macro, /*@out@*/ char * lang)
    00902         /*@modifies *tagp, *macro, *lang @*/
    00903 {
    00904     PreambleRec p;
    00905     char *s;
    00906     size_t len = 0;
    00907
    00908     /* Search for defined tags. */
    00909     for (p = preambleList; p->token != NULL; p++) {
    00910         len = strlen(p->token);
    00911         if (!(p->token && !xstrncasecmp(spec->line, p->token, len)))
    00912             continue;
    00913         if (p->obsolete) {
    00914             rpmlog(RPMLOG_ERR, _("Legacy syntax is unsupported: %s\n"),
    00915                         p->token);
    00916             p = NULL;
    00917         }
    00918         break;
    00919     }
    00920     if (p == NULL)
    00921         return 1;
    00922
    00923     /* Search for arbitrary tags. */
    00924     if (tagp && p->token == NULL) {
    00925         ARGV_t aTags = NULL;
    00926         int rc = 1;     /* assume failure */
    00927
    00928 /*@-noeffect@*/
    00929         (void) tagName(0); /* XXX force arbitrary tags to be initialized. */
    00930 /*@=noeffect@*/
    00931         aTags = rpmTags->aTags;
    00932         if (aTags != NULL && aTags[0] != NULL) {
    00933             ARGV_t av;
    00934             s = tagCanonicalize(spec->line);
    00935 #if defined(RPM_VENDOR_OPENPKG) /* wildcard-matching-arbitrary-tagnames */
    00936             av = argvSearchLinear(aTags, s, argvFnmatchCasefold);
    00937 #else
    00938             av = argvSearch(aTags, s, argvStrcasecmp);
    00939 #endif
    00940             if (av != NULL) {
    00941                 *tagp = tagGenerate(s);
    00942                 rc = 0;
    00943             }
    00944             s = _free(s);
    00945         }
    00946         return rc;
    00947     }
    00948
    00949     s = spec->line + len;
    00950     SKIPSPACE(s);
    00951
    00952     switch (p->multiLang) {
    00953     default:
    00954     case 0:
    00955         /* Unless this is a source or a patch, a ':' better be next */
    00956         if (p->tag != RPMTAG_SOURCE && p->tag != RPMTAG_PATCH) {
    00957             if (*s != ':') return 1;
    00958         }
    00959         *lang = '\0';
    00960         break;
    00961     case 1:     /* Parse optional ( <token> ). */
    00962         if (*s == ':') {
    00963             strcpy(lang, RPMBUILD_DEFAULT_LANG);
    00964             break;
    00965         }
    00966         if (*s != '(') return 1;
    00967         s++;
    00968         SKIPSPACE(s);
    00969         while (!xisspace(*s) && *s != ')')
    00970             *lang++ = *s++;
    00971         *lang = '\0';
    00972         SKIPSPACE(s);
    00973         if (*s != ')') return 1;
    00974         s++;
    00975         SKIPSPACE(s);
    00976         if (*s != ':') return 1;
    00977         break;
    00978     }
    00979
    00980     if (tagp)
    00981         *tagp = p->tag;
    00982     if (macro)
    00983         /*@-onlytrans -observertrans -dependenttrans@*/ /* FIX: double indirection. */
    00984         *macro = p->token;
    00985         /*@=onlytrans =observertrans =dependenttrans@*/
    00986     return 0;
    00987 }
    00988
    00989 /* XXX should return rpmParseState, but RPMRC_FAIL forces int return. */
    00990 int parsePreamble(Spec spec, int initialPackage)
    00991 {
    00992     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
    00993     rpmParseState nextPart;
    00994     int xx;
    00995     char *name, *linep;
    00996     Package pkg;
    00997     char NVR[BUFSIZ];
    00998     char lang[BUFSIZ];
    00999     rpmRC rc;
    01000
    01001     strcpy(NVR, "(main package)");
    01002
    01003     pkg = newPackage(spec);
    01004
    01005     if (! initialPackage) {
    01006         rpmParseState flag;
    01007         /* There is one option to %package: <pkg> or -n <pkg> */
    01008         flag = PART_NONE;
    01009         if (parseSimplePart(spec->line, &name, &flag)) {
    01010             rpmlog(RPMLOG_ERR, _("Bad package specification: %s\n"),
    01011                         spec->line);
    01012             return RPMRC_FAIL;
    01013         }
    01014
    01015         if (lookupPackage(spec, name, flag, NULL) == RPMRC_OK) {
    01016             rpmlog(RPMLOG_ERR, _("Package already exists: %s\n"),
    01017                         spec->line);
    01018             return RPMRC_FAIL;
    01019         }
    01020
    01021         /* Construct the package */
    01022         if (flag == PART_SUBNAME) {
    01023             he->tag = RPMTAG_NAME;
    01024             xx = headerGet(spec->packages->header, he, 0);
    01025             sprintf(NVR, "%s-%s", he->p.str, name);
    01026             he->p.ptr = _free(he->p.ptr);
    01027         } else
    01028             strcpy(NVR, name);
    01029         he->tag = RPMTAG_NAME;
    01030         he->t = RPM_STRING_TYPE;
    01031         he->p.str = NVR;
    01032         he->c = 1;
    01033         xx = headerPut(pkg->header, he, 0);
    01034     }
    01035
    01036     if ((rc = readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) {
    01037         nextPart = PART_NONE;
    01038     } else {
    01039         if (rc)
    01040             return rc;
    01041         while ((nextPart = isPart(spec)) == PART_NONE) {
    01042             const char * macro = NULL;
    01043             rpmTag tag;
    01044
    01045             /* Skip blank lines */
    01046             linep = spec->line;
    01047             SKIPSPACE(linep);
    01048             if (*linep != '\0') {
    01049                 if (findPreambleTag(spec, &tag, &macro, lang)) {
    01050                     rpmlog(RPMLOG_ERR, _("line %d: Unknown tag: %s\n"),
    01051                                 spec->lineNum, spec->line);
    01052                     return RPMRC_FAIL;
    01053                 }
    01054                 if (handlePreambleTag(spec, pkg, tag, macro, lang))
    01055                     return RPMRC_FAIL;
    01056                 if (spec->BANames && !spec->recursing)
    01057                     return PART_BUILDARCHITECTURES;
    01058             }
    01059             if ((rc =
    01060                  readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) {
    01061                 nextPart = PART_NONE;
    01062                 break;
    01063             }
    01064             if (rc)
    01065                 return rc;
    01066         }
    01067     }
    01068
    01069     /* Do some final processing on the header */
    01070
    01071     /* XXX Skip valid arch check if not building binary package */
    01072     if (!spec->anyarch && checkForValidArchitectures(spec))
    01073         return RPMRC_FAIL;
    01074
    01075     if (pkg == spec->packages)
    01076         fillOutMainPackage(pkg->header);
    01077
    01078     if (checkForDuplicates(pkg->header, NVR) != RPMRC_OK)
    01079         return RPMRC_FAIL;
    01080
    01081     if (pkg != spec->packages)
    01082         headerCopyTags(spec->packages->header, pkg->header,
    01083                         (uint32_t *)copyTagsDuringParse);
    01084
    01085     if (checkForRequired(pkg->header, NVR) != RPMRC_OK)
    01086         return RPMRC_FAIL;
    01087
    01088     return nextPart;
    01089 }