rpm 5.3.12
build/parseSpec.c
Go to the documentation of this file.
00001 
00006 #include "system.h"
00007 
00008 #include <rpmio_internal.h>     /* XXX fdGetFp */
00009 #include <rpmcb.h>
00010 #include <argv.h>
00011 
00012 #define _RPMTAG_INTERNAL        /* XXX rpmTags->aTags */
00013 #include <rpmbuild.h>
00014 #include "rpmds.h"
00015 #include "rpmts.h"
00016 #include "debug.h"
00017 
00018 /*@access headerTagIndices @*/
00019 /*@access FD_t @*/      /* compared with NULL */
00020 
00023 /*@unchecked@*/
00024 static struct PartRec {
00025     rpmParseState part;
00026     size_t len;
00027 /*@observer@*/ /*@null@*/
00028     const char * token;
00029 } partList[] = {
00030     { PART_PREAMBLE,      0, "%package"},
00031     { PART_PREP,          0, "%prep"},
00032     { PART_BUILD,         0, "%build"},
00033     { PART_INSTALL,       0, "%install"},
00034     { PART_CHECK,         0, "%check"},
00035     { PART_CLEAN,         0, "%clean"},
00036     { PART_PREUN,         0, "%preun"},
00037     { PART_POSTUN,        0, "%postun"},
00038     { PART_PRETRANS,      0, "%pretrans"},
00039     { PART_POSTTRANS,     0, "%posttrans"},
00040     { PART_PRE,           0, "%pre"},
00041     { PART_POST,          0, "%post"},
00042     { PART_FILES,         0, "%files"},
00043     { PART_CHANGELOG,     0, "%changelog"},
00044     { PART_DESCRIPTION,   0, "%description"},
00045     { PART_TRIGGERPOSTUN, 0, "%triggerpostun"},
00046     { PART_TRIGGERPREIN,  0, "%triggerprein"},
00047     { PART_TRIGGERUN,     0, "%triggerun"},
00048     { PART_TRIGGERIN,     0, "%triggerin"},
00049     { PART_TRIGGERIN,     0, "%trigger"},
00050     { PART_VERIFYSCRIPT,  0, "%verifyscript"},
00051     { PART_SANITYCHECK,   0, "%sanitycheck"},   /* support "%sanitycheck" scriptlet */
00052     {0, 0, NULL}
00053 };
00054 
00057 static inline void initParts(struct PartRec *p)
00058         /*@modifies p->len @*/
00059 {
00060     for (; p->token != NULL; p++)
00061         p->len = strlen(p->token);
00062 }
00063 
00064 rpmParseState isPart(Spec spec)
00065 {
00066     const char * line = spec->line;
00067     struct PartRec *p;
00068     rpmParseState nextPart = PART_NONE; /* assume plain text */
00069 
00070     if (partList[0].len == 0)
00071         initParts(partList);
00072     
00073     for (p = partList; p->token != NULL; p++) {
00074         char c;
00075         if (xstrncasecmp(line, p->token, p->len))
00076             continue;
00077         c = *(line + p->len);
00078         if (c == '\0' || xisspace(c)) {
00079             nextPart = p->part;
00080             goto exit;
00081         }
00082     }
00083 
00084     /* If %foo is not found explictly, check for an arbitrary %foo tag. */
00085     if (line[0] == '%') {
00086         ARGV_t aTags = NULL;
00087         const char * s;
00088 /*@-noeffect@*/
00089         (void) tagName(0); /* XXX force arbitrary tags to be initialized. */
00090 /*@=noeffect@*/
00091         aTags = rpmTags->aTags;
00092         if (aTags != NULL && aTags[0] != NULL) {
00093             ARGV_t av;
00094             s = tagCanonicalize(line+1);        /* XXX +1 to skip leading '%' */
00095 #if defined(RPM_VENDOR_OPENPKG) /* wildcard-matching-arbitrary-tagnames */
00096             av = argvSearchLinear(aTags, s, argvFnmatchCasefold);
00097 #else
00098             av = argvSearch(aTags, s, argvStrcasecmp);
00099 #endif
00100             if (av != NULL) {
00101                 spec->foo = xrealloc(spec->foo, (spec->nfoo + 1) * sizeof(*spec->foo));
00102                 spec->foo[spec->nfoo].str = xstrdup(s);
00103                 spec->foo[spec->nfoo].tag = tagGenerate(s);
00104                 spec->foo[spec->nfoo].iob = NULL;
00105                 spec->nfoo++;
00106                 nextPart = PART_ARBITRARY;
00107             }
00108             s = _free(s);
00109         }
00110     }
00111 
00112 exit:
00113     return nextPart;
00114 }
00115 
00118 static int matchTok(const char *token, const char *line)
00119         /*@*/
00120 {
00121     const char *b, *be = line;
00122     size_t toklen = strlen(token);
00123     int rc = 0;
00124 
00125     while ( *(b = be) != '\0' ) {
00126         SKIPSPACE(b);
00127         be = b;
00128         SKIPNONSPACE(be);
00129         if (be == b)
00130             break;
00131         if (toklen != (size_t)(be-b) || xstrncasecmp(token, b, (be-b)))
00132             continue;
00133         rc = 1;
00134         break;
00135     }
00136 
00137     return rc;
00138 }
00139 
00140 void handleComments(char *s)
00141 {
00142     SKIPSPACE(s);
00143     if (*s == '#')
00144         *s = '\0';
00145 }
00146 
00149 static void forceIncludeFile(Spec spec, const char * fileName)
00150         /*@modifies spec->fileStack @*/
00151 {
00152     OFI_t * ofi;
00153 
00154     ofi = newOpenFileInfo();
00155     ofi->fileName = xstrdup(fileName);
00156     ofi->next = spec->fileStack;
00157     spec->fileStack = ofi;
00158 }
00159 
00162 static int restoreFirstChar(Spec spec)
00163         /*@modifies spec->nextline, spec->nextpeekc @*/
00164 {
00165     /* Restore 1st char in (possible) next line */
00166     if (spec->nextline != NULL && spec->nextpeekc != '\0') {
00167         *spec->nextline = spec->nextpeekc;
00168         spec->nextpeekc = '\0';
00169         return 1;
00170     }
00171     return 0;
00172 }
00173 
00176 static int copyNextLineFromOFI(Spec spec, OFI_t * ofi, rpmStripFlags strip)
00177         /*@globals rpmGlobalMacroContext, h_errno,
00178                 fileSystem, internalState @*/
00179         /*@modifies spec->nextline, spec->lbuf, spec->lbufPtr,
00180                 ofi->readPtr,
00181                 rpmGlobalMacroContext, fileSystem, internalState @*/
00182 {
00183     char ch;
00184 
00185     /* Expand next line from file into line buffer */
00186     if (!(spec->nextline && *spec->nextline)) {
00187         int pc = 0, bc = 0, nc = 0;
00188         char *from, *to, *p;
00189         to = spec->lbufPtr ? spec->lbufPtr : spec->lbuf;
00190         from = ofi->readPtr;
00191         ch = ' ';
00192         while (from && *from && ch != '\n')
00193             ch = *to++ = *from++;
00194 /*@-mods@*/
00195         spec->lbufPtr = to;
00196 /*@=mods@*/
00197         *to++ = '\0';
00198         ofi->readPtr = from;
00199 
00200         /* Check if we need another line before expanding the buffer. */
00201         for (p = spec->lbuf; *p; p++) {
00202             switch (*p) {
00203                 case '\\':
00204                     switch (*(p+1)) {
00205                         case '\n': p++, nc = 1; /*@innerbreak@*/ break;
00206                         case '\0': /*@innerbreak@*/ break;
00207                         default: p++; /*@innerbreak@*/ break;
00208                     }
00209                     /*@switchbreak@*/ break;
00210                 case '\n': nc = 0; /*@switchbreak@*/ break;
00211                 case '%':
00212                     switch (*(p+1)) {
00213                         case '{': p++, bc++; /*@innerbreak@*/ break;
00214                         case '(': p++, pc++; /*@innerbreak@*/ break;
00215                         case '%': p++; /*@innerbreak@*/ break;
00216                     }
00217                     /*@switchbreak@*/ break;
00218                 case '{': if (bc > 0) bc++; /*@switchbreak@*/ break;
00219                 case '}': if (bc > 0) bc--; /*@switchbreak@*/ break;
00220                 case '(': if (pc > 0) pc++; /*@switchbreak@*/ break;
00221                 case ')': if (pc > 0) pc--; /*@switchbreak@*/ break;
00222             }
00223         }
00224         
00225         /* If it doesn't, ask for one more line. We need a better
00226          * error code for this. */
00227         if (pc || bc || nc ) {
00228 /*@-observertrans -readonlytrans@*/
00229             spec->nextline = "";
00230 /*@=observertrans =readonlytrans@*/
00231             return RPMRC_FAIL;
00232         }
00233 /*@-mods@*/
00234         spec->lbufPtr = spec->lbuf;
00235 /*@=mods@*/
00236 
00237         /* Don't expand macros (eg. %define) in false branch of %if clause */
00238         /* Also don't expand macros in %changelog if STRIP_NOEXPAND is set */
00239         /* (first line is omitted, so %date macro will be expanded */
00240       if (!(strip & STRIP_NOEXPAND)) {
00241         if (spec->readStack->reading &&
00242             expandMacros(spec, spec->macros, spec->lbuf, spec->lbuf_len)) {
00243                 rpmlog(RPMLOG_ERR, _("line %d: %s\n"),
00244                         spec->lineNum, spec->lbuf);
00245                 return RPMRC_FAIL;
00246         }
00247       }
00248         spec->nextline = spec->lbuf;
00249     }
00250     return 0;
00251 }
00252 
00255 static int copyNextLineFinish(Spec spec, int strip)
00256         /*@modifies spec->line, spec->nextline, spec->nextpeekc @*/
00257 {
00258     char *last;
00259     char ch;
00260 
00261     /* Find next line in expanded line buffer */
00262     spec->line = last = spec->nextline;
00263     ch = ' ';
00264     while (*spec->nextline && ch != '\n') {
00265         ch = *spec->nextline++;
00266         if (!xisspace(ch))
00267             last = spec->nextline;
00268     }
00269 
00270     /* Save 1st char of next line in order to terminate current line. */
00271     if (*spec->nextline != '\0') {
00272         spec->nextpeekc = *spec->nextline;
00273         *spec->nextline = '\0';
00274     }
00275     
00276     if (strip & STRIP_COMMENTS)
00277         handleComments(spec->line);
00278     
00279     if (strip & STRIP_TRAILINGSPACE)
00280         *last = '\0';
00281 
00282     return 0;
00283 }
00284 
00287 static int readLineFromOFI(Spec spec, OFI_t *ofi)
00288         /*@globals h_errno, fileSystem, internalState @*/
00289         /*@modifies ofi, spec->fileStack, spec->lineNum, spec->sl,
00290                 fileSystem, internalState @*/
00291 {
00292 retry:
00293     /* Make sure the current file is open */
00294     if (ofi->fd == NULL) {
00295         ofi->fd = Fopen(ofi->fileName, "r.fpio");
00296         if (ofi->fd == NULL || Ferror(ofi->fd)) {
00297             /* XXX Fstrerror */
00298             rpmlog(RPMLOG_ERR, _("Unable to open %s: %s\n"),
00299                      ofi->fileName, Fstrerror(ofi->fd));
00300             return RPMRC_FAIL;
00301         }
00302         spec->lineNum = ofi->lineNum = 0;
00303     }
00304 
00305     /* Make sure we have something in the read buffer */
00306     if (!(ofi->readPtr && *(ofi->readPtr))) {
00307         /*@-type@*/ /* FIX: cast? */
00308         FILE * f = fdGetFp(ofi->fd);
00309         /*@=type@*/
00310         if (f == NULL || !fgets(ofi->readBuf, (int)sizeof(ofi->readBuf), f)) {
00311             /* EOF */
00312             if (spec->readStack->next) {
00313                 rpmlog(RPMLOG_ERR, _("Unclosed %%if\n"));
00314                 return RPMRC_FAIL;
00315             }
00316 
00317             /* remove this file from the stack */
00318             spec->fileStack = ofi->next;
00319             (void) Fclose(ofi->fd);
00320             ofi->fileName = _free(ofi->fileName);
00321 /*@-temptrans@*/
00322             ofi = _free(ofi);
00323 /*@=temptrans@*/
00324 
00325             /* only on last file do we signal EOF to caller */
00326             ofi = spec->fileStack;
00327             if (ofi == NULL)
00328                 return 1;
00329 
00330             /* otherwise, go back and try the read again. */
00331             goto retry;
00332         }
00333         ofi->readPtr = ofi->readBuf;
00334         ofi->lineNum++;
00335         spec->lineNum = ofi->lineNum;
00336         if (spec->sl) {
00337             speclines sl = spec->sl;
00338             if (sl->sl_nlines == sl->sl_nalloc) {
00339                 sl->sl_nalloc += 100;
00340                 sl->sl_lines = (char **) xrealloc(sl->sl_lines, 
00341                         sl->sl_nalloc * sizeof(*(sl->sl_lines)));
00342             }
00343             sl->sl_lines[sl->sl_nlines++] = xstrdup(ofi->readBuf);
00344         }
00345     }
00346     return 0;
00347 }
00348 
00349 int readLine(Spec spec, rpmStripFlags strip)
00350 {
00351     char  *s;
00352     int match;
00353     struct ReadLevelEntry *rl;
00354     OFI_t *ofi = spec->fileStack;
00355     int rc;
00356 
00357     if (ofi == NULL)    /* XXX segfault avoidance */
00358         return 1;
00359     if (!restoreFirstChar(spec)) {
00360     retry:
00361       if ((rc = readLineFromOFI(spec, ofi)) != 0)
00362         return rc;
00363 
00364       /* Copy next file line into the spec line buffer */
00365 
00366       if ((rc = copyNextLineFromOFI(spec, ofi, strip)) != 0) {
00367         if (rc == RPMRC_FAIL)
00368             goto retry;
00369         return rc;
00370       }
00371     }
00372 
00373     (void) copyNextLineFinish(spec, strip);
00374 
00375     s = spec->line;
00376     SKIPSPACE(s);
00377 
00378     match = -1;
00379   if (!(strip & STRIP_NOEXPAND)) {
00380     if (!spec->readStack->reading && !strncmp("%if", s, sizeof("%if")-1)) {
00381         match = 0;
00382     } else if (! strncmp("%ifarch", s, sizeof("%ifarch")-1)) {
00383         const char *arch = rpmExpand("%{_target_cpu}", NULL);
00384         s += 7;
00385         match = matchTok(arch, s);
00386         arch = _free(arch);
00387     } else if (! strncmp("%ifnarch", s, sizeof("%ifnarch")-1)) {
00388         const char *arch = rpmExpand("%{_target_cpu}", NULL);
00389         s += 8;
00390         match = !matchTok(arch, s);
00391         arch = _free(arch);
00392     } else if (! strncmp("%ifos", s, sizeof("%ifos")-1)) {
00393         const char *os = rpmExpand("%{_target_os}", NULL);
00394         s += 5;
00395         match = matchTok(os, s);
00396         os = _free(os);
00397     } else if (! strncmp("%ifnos", s, sizeof("%ifnos")-1)) {
00398         const char *os = rpmExpand("%{_target_os}", NULL);
00399         s += 6;
00400         match = !matchTok(os, s);
00401         os = _free(os);
00402     } else if (! strncmp("%if", s, sizeof("%if")-1)) {
00403         s += 3;
00404         match = parseExpressionBoolean(spec, s);
00405         if (match < 0) {
00406             rpmlog(RPMLOG_ERR,
00407                         _("%s:%d: parseExpressionBoolean returns %d\n"),
00408                         ofi->fileName, ofi->lineNum, match);
00409             return RPMRC_FAIL;
00410         }
00411     } else if (! strncmp("%else", s, sizeof("%else")-1)) {
00412         s += 5;
00413         if (! spec->readStack->next) {
00414             /* Got an else with no %if ! */
00415             rpmlog(RPMLOG_ERR,
00416                         _("%s:%d: Got a %%else with no %%if\n"),
00417                         ofi->fileName, ofi->lineNum);
00418             return RPMRC_FAIL;
00419         }
00420         spec->readStack->reading =
00421             spec->readStack->next->reading && ! spec->readStack->reading;
00422         spec->line[0] = '\0';
00423     } else if (! strncmp("%endif", s, sizeof("%endif")-1)) {
00424         s += 6;
00425         if (! spec->readStack->next) {
00426             /* Got an end with no %if ! */
00427             rpmlog(RPMLOG_ERR,
00428                         _("%s:%d: Got a %%endif with no %%if\n"),
00429                         ofi->fileName, ofi->lineNum);
00430             return RPMRC_FAIL;
00431         }
00432         rl = spec->readStack;
00433         spec->readStack = spec->readStack->next;
00434         free(rl);
00435         spec->line[0] = '\0';
00436     } else if (! strncmp("%include", s, sizeof("%include")-1)) {
00437         char *fileName, *endFileName, *p;
00438 
00439         s += 8;
00440         fileName = s;
00441         if (! xisspace(*fileName)) {
00442             rpmlog(RPMLOG_ERR, _("malformed %%include statement\n"));
00443             return RPMRC_FAIL;
00444         }
00445         SKIPSPACE(fileName);
00446         endFileName = fileName;
00447         SKIPNONSPACE(endFileName);
00448         p = endFileName;
00449         SKIPSPACE(p);
00450         if (*p != '\0') {
00451             rpmlog(RPMLOG_ERR, _("malformed %%include statement\n"));
00452             return RPMRC_FAIL;
00453         }
00454         *endFileName = '\0';
00455 
00456         forceIncludeFile(spec, fileName);
00457 
00458         ofi = spec->fileStack;
00459         goto retry;
00460     }
00461   }
00462 
00463     if (match != -1) {
00464         rl = xmalloc(sizeof(*rl));
00465         rl->reading = spec->readStack->reading && match;
00466         rl->next = spec->readStack;
00467         spec->readStack = rl;
00468         spec->line[0] = '\0';
00469     }
00470 
00471     if (! spec->readStack->reading) {
00472         spec->line[0] = '\0';
00473     }
00474 
00475     /*@-compmempass@*/ /* FIX: spec->readStack->next should be dependent */
00476     return 0;
00477     /*@=compmempass@*/
00478 }
00479 
00480 void closeSpec(Spec spec)
00481 {
00482     OFI_t *ofi;
00483 
00484     while (spec->fileStack) {
00485         ofi = spec->fileStack;
00486         spec->fileStack = spec->fileStack->next;
00487         if (ofi->fd) (void) Fclose(ofi->fd);
00488         ofi->fileName = _free(ofi->fileName);
00489         ofi = _free(ofi);
00490     }
00491 }
00492 
00495 static inline int genSourceRpmName(Spec spec)
00496         /*@globals internalState @*/
00497         /*@modifies spec->sourceRpmName, spec->packages->header,
00498                 internalState @*/
00499 {
00500     if (spec->sourceRpmName == NULL) {
00501         const char *N, *V, *R;
00502         char fileName[BUFSIZ];
00503 
00504         (void) headerNEVRA(spec->packages->header, &N, NULL, &V, &R, NULL);
00505         (void) snprintf(fileName, sizeof(fileName), "%s-%s-%s.%ssrc.rpm",
00506                         N, V, R, spec->noSource ? "no" : "");
00507         fileName[sizeof(fileName)-1] = '\0';
00508         N = _free(N);
00509         V = _free(V);
00510         R = _free(R);
00511         spec->sourceRpmName = xstrdup(fileName);
00512     }
00513 
00514     return 0;
00515 }
00516 
00517 /*@-redecl@*/
00518 /*@unchecked@*/
00519 extern int noLang;              /* XXX FIXME: pass as arg */
00520 /*@=redecl@*/
00521 
00522 /*@todo Skip parse recursion if os is not compatible. @*/
00523 int parseSpec(rpmts ts, const char *specFile, const char *rootURL,
00524                 int recursing, const char *passPhrase,
00525                 const char *cookie, int anyarch, int force, int verify)
00526 {
00527     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
00528     rpmParseState parsePart = PART_PREAMBLE;
00529     int initialPackage = 1;
00530     Package pkg;
00531     Spec spec;
00532     int xx;
00533     
00534     /* Set up a new Spec structure with no packages. */
00535     spec = newSpec();
00536 
00537     /*
00538      * Note: rpmGetPath should guarantee a "canonical" path. That means
00539      * that the following pathologies should be weeded out:
00540      *          //bin//sh
00541      *          //usr//bin/
00542      *          /.././../usr/../bin//./sh (XXX FIXME: dots not handled yet)
00543      */
00544     spec->specFile = rpmGetPath(specFile, NULL);
00545     addMacro(spec->macros, "_specfile", NULL, spec->specFile, RMIL_SPEC);
00546     spec->fileStack = newOpenFileInfo();
00547     spec->fileStack->fileName = xstrdup(spec->specFile);
00548 
00549     spec->recursing = recursing;
00550     spec->toplevel = (!recursing ? 1 : 0);
00551     spec->anyarch = anyarch;
00552     spec->force = force;
00553 
00554     if (rootURL)
00555         spec->rootURL = xstrdup(rootURL);
00556     if (passPhrase)
00557         spec->passPhrase = xstrdup(passPhrase);
00558     if (cookie)
00559         spec->cookie = xstrdup(cookie);
00560 
00561     spec->timeCheck = rpmExpandNumeric("%{_timecheck}");
00562 
00563     /* XXX %_docdir should be set somewhere else. */
00564     addMacro(NULL, "_docdir", NULL, "%{_defaultdocdir}", RMIL_SPEC);
00565 
00566     /* All the parse*() functions expect to have a line pre-read */
00567     /* in the spec's line buffer.  Except for parsePreamble(),   */
00568     /* which handles the initial entry into a spec file.         */
00569     
00570     /*@-infloops@*/     /* LCL: parsePart is modified @*/
00571     while (parsePart > PART_NONE) {
00572         int goterror = 0;
00573 
00574         switch (parsePart) {
00575         default:
00576             goterror = 1;
00577             /*@switchbreak@*/ break;
00578         case PART_PREAMBLE:
00579             parsePart = parsePreamble(spec, initialPackage);
00580             initialPackage = 0;
00581             /*@switchbreak@*/ break;
00582         case PART_PREP:
00583             parsePart = parsePrep(spec, verify);
00584             /*@switchbreak@*/ break;
00585         case PART_BUILD:
00586         case PART_INSTALL:
00587         case PART_CHECK:
00588         case PART_CLEAN:
00589         case PART_ARBITRARY:
00590             parsePart = parseBuildInstallClean(spec, parsePart);
00591             /*@switchbreak@*/ break;
00592         case PART_CHANGELOG:
00593             parsePart = parseChangelog(spec);
00594             /*@switchbreak@*/ break;
00595         case PART_DESCRIPTION:
00596             parsePart = parseDescription(spec);
00597             /*@switchbreak@*/ break;
00598 
00599         case PART_PRE:
00600         case PART_POST:
00601         case PART_PREUN:
00602         case PART_POSTUN:
00603         case PART_PRETRANS:
00604         case PART_POSTTRANS:
00605         case PART_VERIFYSCRIPT:
00606         case PART_SANITYCHECK:
00607         case PART_TRIGGERPREIN:
00608         case PART_TRIGGERIN:
00609         case PART_TRIGGERUN:
00610         case PART_TRIGGERPOSTUN:
00611             parsePart = parseScript(spec, parsePart);
00612             /*@switchbreak@*/ break;
00613 
00614         case PART_FILES:
00615             parsePart = parseFiles(spec);
00616             /*@switchbreak@*/ break;
00617 
00618         case PART_NONE:         /* XXX avoid gcc whining */
00619         case PART_LAST:
00620         case PART_BUILDARCHITECTURES:
00621             /*@switchbreak@*/ break;
00622         }
00623 
00624         if (goterror || parsePart >= PART_LAST) {
00625             spec = freeSpec(spec);
00626             return parsePart;
00627         }
00628 
00629         /* Detect whether BuildArch: is toplevel or within %package. */
00630         if (spec->toplevel && parsePart != PART_BUILDARCHITECTURES)
00631             spec->toplevel = 0;
00632 
00633         /* Restart parse iff toplevel BuildArch: is encountered. */
00634         if (spec->toplevel && parsePart == PART_BUILDARCHITECTURES) {
00635             int index;
00636             int x;
00637 
00638             closeSpec(spec);
00639 
00640             /* LCL: sizeof(spec->BASpecs[0]) -nullderef whine here */
00641             spec->BASpecs = xcalloc(spec->BACount, sizeof(*spec->BASpecs));
00642             index = 0;
00643             if (spec->BANames != NULL)
00644             for (x = 0; x < spec->BACount; x++) {
00645 
00646                 /* XXX DIEDIEDIE: filter irrelevant platforms here. */
00647 
00648                 /* XXX there's more to do than set the macro. */
00649                 addMacro(NULL, "_target_cpu", NULL, spec->BANames[x], RMIL_RPMRC);
00650                 spec->BASpecs[index] = NULL;
00651                 if (parseSpec(ts, specFile, spec->rootURL, 1,
00652                                   passPhrase, cookie, anyarch, force, verify)
00653                  || (spec->BASpecs[index] = rpmtsSetSpec(ts, NULL)) == NULL)
00654                 {
00655                         spec->BACount = index;
00656 /*@-nullstate@*/
00657                         spec = freeSpec(spec);
00658                         return RPMRC_FAIL;
00659 /*@=nullstate@*/
00660                 }
00661 
00662                 /* XXX there's more to do than delete the macro. */
00663                 delMacro(NULL, "_target_cpu");
00664                 index++;
00665             }
00666 
00667             spec->BACount = index;
00668             if (! index) {
00669                 rpmlog(RPMLOG_ERR,
00670                         _("No compatible architectures found for build\n"));
00671 /*@-nullstate@*/
00672                 spec = freeSpec(spec);
00673                 return RPMRC_FAIL;
00674 /*@=nullstate@*/
00675             }
00676 
00677             /*
00678              * Return the 1st child's fully parsed Spec structure.
00679              * The restart of the parse when encountering BuildArch
00680              * causes problems for "rpm -q --specfile". This is
00681              * still a hack because there may be more than 1 arch
00682              * specified (unlikely but possible.) There's also the
00683              * further problem that the macro context, particularly
00684              * %{_target_cpu}, disagrees with the info in the header.
00685              */
00686             if (spec->BACount >= 1) {
00687                 Spec nspec = spec->BASpecs[0];
00688                 spec->BASpecs = _free(spec->BASpecs);
00689                 spec = freeSpec(spec);
00690                 spec = nspec;
00691             }
00692 
00693             (void) rpmtsSetSpec(ts, spec);
00694             return 0;
00695         }
00696     }
00697     /*@=infloops@*/     /* LCL: parsePart is modified @*/
00698 
00699     /* Initialize source RPM name. */
00700     (void) genSourceRpmName(spec);
00701 
00702     /* Check for description in each package and add arch and os */
00703   {
00704     const char *platform = rpmExpand("%{_target_platform}", NULL);
00705 #if defined(RPM_VENDOR_MANDRIVA)
00706     const char *platformNoarch = NULL;
00707 #endif
00708     const char *arch = rpmExpand("%{_target_cpu}", NULL);
00709     const char *os = rpmExpand("%{_target_os}", NULL);
00710 
00711     for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
00712         he->tag = RPMTAG_OS;
00713         he->t = RPM_STRING_TYPE;
00714         /* XXX todo: really need "noos" like pkg->noarch somewhen. */
00715         he->p.str = os;
00716         he->c = 1;
00717         xx = headerPut(pkg->header, he, 0);
00718 
00719         he->tag = RPMTAG_ARCH;
00720         he->t = RPM_STRING_TYPE;
00721         he->p.str = (pkg->noarch ? "noarch" : arch);
00722         he->c = 1;
00723         xx = headerPut(pkg->header, he, 0);
00724 
00725 #if defined(RPM_VENDOR_MANDRIVA)
00726         /* 
00727          * If "noarch" subpackages of different arch, we need
00728          * to use a separate platform tag for these (mdvbz#61746).
00729          */
00730         if(pkg->noarch && !platformNoarch && strcmp(arch, "noarch")) {
00731             addMacro(NULL, "_target_cpu", NULL, "noarch", RMIL_RPMRC);
00732             platformNoarch = rpmExpand("%{_target_platform}", NULL);
00733             addMacro(NULL, "_target_cpu", NULL, arch, RMIL_RPMRC);
00734         }
00735 #endif
00736         he->tag = RPMTAG_PLATFORM;
00737         he->t = RPM_STRING_TYPE;
00738 #if defined(RPM_VENDOR_MANDRIVA)
00739         he->p.str = (pkg->noarch && platformNoarch ? platformNoarch : platform);
00740 #else
00741         he->p.str = platform;
00742 #endif
00743         he->c = 1;
00744         xx = headerPut(pkg->header, he, 0);
00745 
00746         he->tag = RPMTAG_SOURCERPM;
00747         he->t = RPM_STRING_TYPE;
00748         he->p.str = spec->sourceRpmName;
00749         he->c = 1;
00750         xx = headerPut(pkg->header, he, 0);
00751 
00752         if (!headerIsEntry(pkg->header, RPMTAG_DESCRIPTION)) {
00753             he->tag = RPMTAG_NVRA;
00754             xx = headerGet(pkg->header, he, 0);
00755             rpmlog(RPMLOG_ERR, _("Package has no %%description: %s\n"),
00756                         he->p.str);
00757             he->p.ptr = _free(he->p.ptr);
00758             platform = _free(platform);
00759 #if defined(RPM_VENDOR_MANDRIVA)
00760             platformNoarch = _free(platformNoarch);
00761 #endif
00762             arch = _free(arch);
00763             os = _free(os);
00764             spec = freeSpec(spec);
00765             return RPMRC_FAIL;
00766         }
00767 
00768         pkg->ds = rpmdsThis(pkg->header, RPMTAG_REQUIRENAME, RPMSENSE_EQUAL);
00769 
00770     }
00771 
00772     platform = _free(platform);
00773 #if defined(RPM_VENDOR_MANDRIVA)
00774     platformNoarch = _free(platformNoarch);
00775 #endif
00776     arch = _free(arch);
00777     os = _free(os);
00778   }
00779 
00780     closeSpec(spec);
00781     (void) rpmtsSetSpec(ts, spec);
00782 
00783     return 0;
00784 }