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

- File List
- Globals

# build/parseSpec.c

Go to the documentation of this file.

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