00001
00006 #include "system.h"
00007
00008 #include <rpmio_internal.h>
00009 #define _RPMTAG_INTERNAL
00010 #include <rpmbuild.h>
00011 #include "rpmds.h"
00012 #include "rpmts.h"
00013 #include "debug.h"
00014
00015
00016
00019
00020 static struct PartRec {
00021 rpmParseState part;
00022 size_t len;
00023
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"},
00048 {0, 0, 0}
00049 };
00050
00053 static inline void initParts(struct PartRec *p)
00054
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;
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
00081 if (nextPart == PART_NONE) {
00082 ARGV_t aTags = NULL;
00083 const char * s;
00084
00085 (void) tagName(0);
00086
00087 aTags = rpmTags->aTags;
00088 if (aTags != NULL && aTags[0] != NULL) {
00089 ARGV_t av;
00090 s = tagCanonicalize(line+1);
00091 #if defined(RPM_VENDOR_OPENPKG)
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
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
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
00173
00174
00175
00176
00177 {
00178 char ch;
00179
00180
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
00190 spec->lbufPtr = to;
00191
00192 *to++ = '\0';
00193 ofi->readPtr = from;
00194
00195
00196 for (p = spec->lbuf; *p; p++) {
00197 switch (*p) {
00198 case '\\':
00199 switch (*(p+1)) {
00200 case '\n': p++, nc = 1; break;
00201 case '\0': break;
00202 default: p++; break;
00203 }
00204 break;
00205 case '\n': nc = 0; break;
00206 case '%':
00207 switch (*(p+1)) {
00208 case '{': p++, bc++; break;
00209 case '(': p++, pc++; break;
00210 case '%': p++; break;
00211 }
00212 break;
00213 case '{': if (bc > 0) bc++; break;
00214 case '}': if (bc > 0) bc--; break;
00215 case '(': if (pc > 0) pc++; break;
00216 case ')': if (pc > 0) pc--; break;
00217 }
00218 }
00219
00220
00221
00222 if (pc || bc || nc ) {
00223
00224 spec->nextline = "";
00225
00226 return RPMRC_FAIL;
00227 }
00228
00229 spec->lbufPtr = spec->lbuf;
00230
00231
00232
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
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
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
00279 {
00280 retry:
00281
00282 if (ofi->fd == NULL) {
00283 ofi->fd = Fopen(ofi->fileName, "r.fpio");
00284 if (ofi->fd == NULL || Ferror(ofi->fd)) {
00285
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
00294 if (!(ofi->readPtr && *(ofi->readPtr))) {
00295
00296 FILE * f = fdGetFp(ofi->fd);
00297
00298 if (f == NULL || !fgets(ofi->readBuf, BUFSIZ, f)) {
00299
00300 if (spec->readStack->next) {
00301 rpmlog(RPMLOG_ERR, _("Unclosed %%if\n"));
00302 return RPMRC_FAIL;
00303 }
00304
00305
00306 spec->fileStack = ofi->next;
00307 (void) Fclose(ofi->fd);
00308 ofi->fileName = _free(ofi->fileName);
00309 ofi = _free(ofi);
00310
00311
00312 ofi = spec->fileStack;
00313 if (ofi == NULL)
00314 return 1;
00315
00316
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
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
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
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
00458 return 0;
00459
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
00476
00477 extern int noLang;
00478
00479
00480
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
00493 spec = newSpec();
00494
00495
00496
00497
00498
00499
00500
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
00520 addMacro(NULL, "_docdir", NULL, "%{_defaultdocdir}", RMIL_SPEC);
00521
00522
00523
00524
00525
00526
00527 while (parsePart > PART_NONE) {
00528 int goterror = 0;
00529 switch (parsePart) {
00530 default:
00531 goterror = 1;
00532 break;
00533 case PART_PREAMBLE:
00534 parsePart = parsePreamble(spec, initialPackage);
00535 initialPackage = 0;
00536 break;
00537 case PART_PREP:
00538 parsePart = parsePrep(spec, verify);
00539 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 break;
00547 case PART_CHANGELOG:
00548 parsePart = parseChangelog(spec);
00549 break;
00550 case PART_DESCRIPTION:
00551 parsePart = parseDescription(spec);
00552 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 break;
00568
00569 case PART_FILES:
00570 parsePart = parseFiles(spec);
00571 break;
00572
00573 case PART_NONE:
00574 case PART_LAST:
00575 case PART_BUILDARCHITECTURES:
00576 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
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
00597
00598
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
00607 spec = freeSpec(spec);
00608 return RPMRC_FAIL;
00609
00610 }
00611
00612
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
00622 spec = freeSpec(spec);
00623 return RPMRC_FAIL;
00624
00625 }
00626
00627
00628
00629
00630
00631
00632
00633
00634
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
00648
00649
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 }