00001
00006 #include "system.h"
00007
00008 #include <rpmio_internal.h>
00009 #include <rpmcb.h>
00010 #include <argv.h>
00011
00012 #define _RPMTAG_INTERNAL
00013 #include <rpmbuild.h>
00014 #include "rpmds.h"
00015 #include "rpmts.h"
00016 #include "debug.h"
00017
00018
00019
00020
00023
00024 static struct PartRec {
00025 rpmParseState part;
00026 size_t len;
00027
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"},
00052 {0, 0, 0}
00053 };
00054
00057 static inline void initParts(struct PartRec *p)
00058
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;
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 break;
00081 }
00082 }
00083
00084
00085 if (nextPart == PART_NONE) {
00086 ARGV_t aTags = NULL;
00087 const char * s;
00088
00089 (void) tagName(0);
00090
00091 aTags = rpmTags->aTags;
00092 if (aTags != NULL && aTags[0] != NULL) {
00093 ARGV_t av;
00094 s = tagCanonicalize(line+1);
00095 #if defined(RPM_VENDOR_OPENPKG)
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 return nextPart;
00113 }
00114
00117 static int matchTok(const char *token, const char *line)
00118
00119 {
00120 const char *b, *be = line;
00121 size_t toklen = strlen(token);
00122 int rc = 0;
00123
00124 while ( *(b = be) != '\0' ) {
00125 SKIPSPACE(b);
00126 be = b;
00127 SKIPNONSPACE(be);
00128 if (be == b)
00129 break;
00130 if (toklen != (size_t)(be-b) || xstrncasecmp(token, b, (be-b)))
00131 continue;
00132 rc = 1;
00133 break;
00134 }
00135
00136 return rc;
00137 }
00138
00139 void handleComments(char *s)
00140 {
00141 SKIPSPACE(s);
00142 if (*s == '#')
00143 *s = '\0';
00144 }
00145
00148 static void forceIncludeFile(Spec spec, const char * fileName)
00149
00150 {
00151 OFI_t * ofi;
00152
00153 ofi = newOpenFileInfo();
00154 ofi->fileName = xstrdup(fileName);
00155 ofi->next = spec->fileStack;
00156 spec->fileStack = ofi;
00157 }
00158
00161 static int restoreFirstChar(Spec spec)
00162
00163 {
00164
00165 if (spec->nextline != NULL && spec->nextpeekc != '\0') {
00166 *spec->nextline = spec->nextpeekc;
00167 spec->nextpeekc = '\0';
00168 return 1;
00169 }
00170 return 0;
00171 }
00172
00175 static int copyNextLineFromOFI(Spec spec, OFI_t * ofi, rpmStripFlags strip)
00176
00177
00178
00179
00180
00181 {
00182 char ch;
00183
00184
00185 if (!(spec->nextline && *spec->nextline)) {
00186 int pc = 0, bc = 0, nc = 0;
00187 char *from, *to, *p;
00188 to = spec->lbufPtr ? spec->lbufPtr : spec->lbuf;
00189 from = ofi->readPtr;
00190 ch = ' ';
00191 while (*from && ch != '\n')
00192 ch = *to++ = *from++;
00193
00194 spec->lbufPtr = to;
00195
00196 *to++ = '\0';
00197 ofi->readPtr = from;
00198
00199
00200 for (p = spec->lbuf; *p; p++) {
00201 switch (*p) {
00202 case '\\':
00203 switch (*(p+1)) {
00204 case '\n': p++, nc = 1; break;
00205 case '\0': break;
00206 default: p++; break;
00207 }
00208 break;
00209 case '\n': nc = 0; break;
00210 case '%':
00211 switch (*(p+1)) {
00212 case '{': p++, bc++; break;
00213 case '(': p++, pc++; break;
00214 case '%': p++; break;
00215 }
00216 break;
00217 case '{': if (bc > 0) bc++; break;
00218 case '}': if (bc > 0) bc--; break;
00219 case '(': if (pc > 0) pc++; break;
00220 case ')': if (pc > 0) pc--; break;
00221 }
00222 }
00223
00224
00225
00226 if (pc || bc || nc ) {
00227
00228 spec->nextline = "";
00229
00230 return RPMRC_FAIL;
00231 }
00232
00233 spec->lbufPtr = spec->lbuf;
00234
00235
00236
00237
00238
00239 if (!(strip & STRIP_NOEXPAND)) {
00240 if (spec->readStack->reading &&
00241 expandMacros(spec, spec->macros, spec->lbuf, spec->lbuf_len)) {
00242 rpmlog(RPMLOG_ERR, _("line %d: %s\n"),
00243 spec->lineNum, spec->lbuf);
00244 return RPMRC_FAIL;
00245 }
00246 }
00247 spec->nextline = spec->lbuf;
00248 }
00249 return 0;
00250 }
00251
00254 static int copyNextLineFinish(Spec spec, int strip)
00255
00256 {
00257 char *last;
00258 char ch;
00259
00260
00261 spec->line = last = spec->nextline;
00262 ch = ' ';
00263 while (*spec->nextline && ch != '\n') {
00264 ch = *spec->nextline++;
00265 if (!xisspace(ch))
00266 last = spec->nextline;
00267 }
00268
00269
00270 if (*spec->nextline != '\0') {
00271 spec->nextpeekc = *spec->nextline;
00272 *spec->nextline = '\0';
00273 }
00274
00275 if (strip & STRIP_COMMENTS)
00276 handleComments(spec->line);
00277
00278 if (strip & STRIP_TRAILINGSPACE)
00279 *last = '\0';
00280
00281 return 0;
00282 }
00283
00286 static int readLineFromOFI(Spec spec, OFI_t *ofi)
00287
00288
00289
00290 {
00291 retry:
00292
00293 if (ofi->fd == NULL) {
00294 ofi->fd = Fopen(ofi->fileName, "r.fpio");
00295 if (ofi->fd == NULL || Ferror(ofi->fd)) {
00296
00297 rpmlog(RPMLOG_ERR, _("Unable to open %s: %s\n"),
00298 ofi->fileName, Fstrerror(ofi->fd));
00299 return RPMRC_FAIL;
00300 }
00301 spec->lineNum = ofi->lineNum = 0;
00302 }
00303
00304
00305 if (!(ofi->readPtr && *(ofi->readPtr))) {
00306
00307 FILE * f = fdGetFp(ofi->fd);
00308
00309 if (f == NULL || !fgets(ofi->readBuf, (int)sizeof(ofi->readBuf), f)) {
00310
00311 if (spec->readStack->next) {
00312 rpmlog(RPMLOG_ERR, _("Unclosed %%if\n"));
00313 return RPMRC_FAIL;
00314 }
00315
00316
00317 spec->fileStack = ofi->next;
00318 (void) Fclose(ofi->fd);
00319 ofi->fileName = _free(ofi->fileName);
00320
00321 ofi = _free(ofi);
00322
00323
00324
00325 ofi = spec->fileStack;
00326 if (ofi == NULL)
00327 return 1;
00328
00329
00330 goto retry;
00331 }
00332 ofi->readPtr = ofi->readBuf;
00333 ofi->lineNum++;
00334 spec->lineNum = ofi->lineNum;
00335 if (spec->sl) {
00336 speclines sl = spec->sl;
00337 if (sl->sl_nlines == sl->sl_nalloc) {
00338 sl->sl_nalloc += 100;
00339 sl->sl_lines = (char **) xrealloc(sl->sl_lines,
00340 sl->sl_nalloc * sizeof(*(sl->sl_lines)));
00341 }
00342 sl->sl_lines[sl->sl_nlines++] = xstrdup(ofi->readBuf);
00343 }
00344 }
00345 return 0;
00346 }
00347
00348 int readLine(Spec spec, rpmStripFlags strip)
00349 {
00350 char *s;
00351 int match;
00352 struct ReadLevelEntry *rl;
00353 OFI_t *ofi = spec->fileStack;
00354 int rc;
00355
00356 if (!restoreFirstChar(spec)) {
00357 retry:
00358 if ((rc = readLineFromOFI(spec, ofi)) != 0)
00359 return rc;
00360
00361
00362
00363 if ((rc = copyNextLineFromOFI(spec, ofi, strip)) != 0) {
00364 if (rc == RPMRC_FAIL)
00365 goto retry;
00366 return rc;
00367 }
00368 }
00369
00370 (void) copyNextLineFinish(spec, strip);
00371
00372 s = spec->line;
00373 SKIPSPACE(s);
00374
00375 match = -1;
00376 if (!(strip & STRIP_NOEXPAND)) {
00377 if (!spec->readStack->reading && !strncmp("%if", s, sizeof("%if")-1)) {
00378 match = 0;
00379 } else if (! strncmp("%ifarch", s, sizeof("%ifarch")-1)) {
00380 const char *arch = rpmExpand("%{_target_cpu}", NULL);
00381 s += 7;
00382 match = matchTok(arch, s);
00383 arch = _free(arch);
00384 } else if (! strncmp("%ifnarch", s, sizeof("%ifnarch")-1)) {
00385 const char *arch = rpmExpand("%{_target_cpu}", NULL);
00386 s += 8;
00387 match = !matchTok(arch, s);
00388 arch = _free(arch);
00389 } else if (! strncmp("%ifos", s, sizeof("%ifos")-1)) {
00390 const char *os = rpmExpand("%{_target_os}", NULL);
00391 s += 5;
00392 match = matchTok(os, s);
00393 os = _free(os);
00394 } else if (! strncmp("%ifnos", s, sizeof("%ifnos")-1)) {
00395 const char *os = rpmExpand("%{_target_os}", NULL);
00396 s += 6;
00397 match = !matchTok(os, s);
00398 os = _free(os);
00399 } else if (! strncmp("%if", s, sizeof("%if")-1)) {
00400 s += 3;
00401 match = parseExpressionBoolean(spec, s);
00402 if (match < 0) {
00403 rpmlog(RPMLOG_ERR,
00404 _("%s:%d: parseExpressionBoolean returns %d\n"),
00405 ofi->fileName, ofi->lineNum, match);
00406 return RPMRC_FAIL;
00407 }
00408 } else if (! strncmp("%else", s, sizeof("%else")-1)) {
00409 s += 5;
00410 if (! spec->readStack->next) {
00411
00412 rpmlog(RPMLOG_ERR,
00413 _("%s:%d: Got a %%else with no %%if\n"),
00414 ofi->fileName, ofi->lineNum);
00415 return RPMRC_FAIL;
00416 }
00417 spec->readStack->reading =
00418 spec->readStack->next->reading && ! spec->readStack->reading;
00419 spec->line[0] = '\0';
00420 } else if (! strncmp("%endif", s, sizeof("%endif")-1)) {
00421 s += 6;
00422 if (! spec->readStack->next) {
00423
00424 rpmlog(RPMLOG_ERR,
00425 _("%s:%d: Got a %%endif with no %%if\n"),
00426 ofi->fileName, ofi->lineNum);
00427 return RPMRC_FAIL;
00428 }
00429 rl = spec->readStack;
00430 spec->readStack = spec->readStack->next;
00431 free(rl);
00432 spec->line[0] = '\0';
00433 } else if (! strncmp("%include", s, sizeof("%include")-1)) {
00434 char *fileName, *endFileName, *p;
00435
00436 s += 8;
00437 fileName = s;
00438 if (! xisspace(*fileName)) {
00439 rpmlog(RPMLOG_ERR, _("malformed %%include statement\n"));
00440 return RPMRC_FAIL;
00441 }
00442 SKIPSPACE(fileName);
00443 endFileName = fileName;
00444 SKIPNONSPACE(endFileName);
00445 p = endFileName;
00446 SKIPSPACE(p);
00447 if (*p != '\0') {
00448 rpmlog(RPMLOG_ERR, _("malformed %%include statement\n"));
00449 return RPMRC_FAIL;
00450 }
00451 *endFileName = '\0';
00452
00453 forceIncludeFile(spec, fileName);
00454
00455 ofi = spec->fileStack;
00456 goto retry;
00457 }
00458 }
00459
00460 if (match != -1) {
00461 rl = xmalloc(sizeof(*rl));
00462 rl->reading = spec->readStack->reading && match;
00463 rl->next = spec->readStack;
00464 spec->readStack = rl;
00465 spec->line[0] = '\0';
00466 }
00467
00468 if (! spec->readStack->reading) {
00469 spec->line[0] = '\0';
00470 }
00471
00472
00473 return 0;
00474
00475 }
00476
00477 void closeSpec(Spec spec)
00478 {
00479 OFI_t *ofi;
00480
00481 while (spec->fileStack) {
00482 ofi = spec->fileStack;
00483 spec->fileStack = spec->fileStack->next;
00484 if (ofi->fd) (void) Fclose(ofi->fd);
00485 ofi->fileName = _free(ofi->fileName);
00486 ofi = _free(ofi);
00487 }
00488 }
00489
00492 static inline int genSourceRpmName(Spec spec)
00493
00494
00495
00496 {
00497 if (spec->sourceRpmName == NULL) {
00498 const char *N, *V, *R;
00499 char fileName[BUFSIZ];
00500
00501 (void) headerNEVRA(spec->packages->header, &N, NULL, &V, &R, NULL);
00502 (void) snprintf(fileName, sizeof(fileName), "%s-%s-%s.%ssrc.rpm",
00503 N, V, R, spec->noSource ? "no" : "");
00504 fileName[sizeof(fileName)-1] = '\0';
00505 N = _free(N);
00506 V = _free(V);
00507 R = _free(R);
00508 spec->sourceRpmName = xstrdup(fileName);
00509 }
00510
00511 return 0;
00512 }
00513
00514
00515
00516 extern int noLang;
00517
00518
00519
00520 int parseSpec(rpmts ts, const char *specFile, const char *rootURL,
00521 int recursing, const char *passPhrase,
00522 const char *cookie, int anyarch, int force, int verify)
00523 {
00524 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
00525 rpmParseState parsePart = PART_PREAMBLE;
00526 int initialPackage = 1;
00527 Package pkg;
00528 Spec spec;
00529 int xx;
00530
00531
00532 spec = newSpec();
00533
00534
00535
00536
00537
00538
00539
00540
00541 spec->specFile = rpmGetPath(specFile, NULL);
00542 spec->fileStack = newOpenFileInfo();
00543 spec->fileStack->fileName = xstrdup(spec->specFile);
00544
00545 spec->recursing = recursing;
00546 spec->toplevel = (!recursing ? 1 : 0);
00547 spec->anyarch = anyarch;
00548 spec->force = force;
00549
00550 if (rootURL)
00551 spec->rootURL = xstrdup(rootURL);
00552 if (passPhrase)
00553 spec->passPhrase = xstrdup(passPhrase);
00554 if (cookie)
00555 spec->cookie = xstrdup(cookie);
00556
00557 spec->timeCheck = rpmExpandNumeric("%{_timecheck}");
00558
00559
00560 addMacro(NULL, "_docdir", NULL, "%{_defaultdocdir}", RMIL_SPEC);
00561
00562
00563
00564
00565
00566
00567 while (parsePart > PART_NONE) {
00568 int goterror = 0;
00569
00570 switch (parsePart) {
00571 default:
00572 goterror = 1;
00573 break;
00574 case PART_PREAMBLE:
00575 parsePart = parsePreamble(spec, initialPackage);
00576 initialPackage = 0;
00577 break;
00578 case PART_PREP:
00579 parsePart = parsePrep(spec, verify);
00580 break;
00581 case PART_BUILD:
00582 case PART_INSTALL:
00583 case PART_CHECK:
00584 case PART_CLEAN:
00585 case PART_ARBITRARY:
00586 parsePart = parseBuildInstallClean(spec, parsePart);
00587 break;
00588 case PART_CHANGELOG:
00589 parsePart = parseChangelog(spec);
00590 break;
00591 case PART_DESCRIPTION:
00592 parsePart = parseDescription(spec);
00593 break;
00594
00595 case PART_PRE:
00596 case PART_POST:
00597 case PART_PREUN:
00598 case PART_POSTUN:
00599 case PART_PRETRANS:
00600 case PART_POSTTRANS:
00601 case PART_VERIFYSCRIPT:
00602 case PART_SANITYCHECK:
00603 case PART_TRIGGERPREIN:
00604 case PART_TRIGGERIN:
00605 case PART_TRIGGERUN:
00606 case PART_TRIGGERPOSTUN:
00607 parsePart = parseScript(spec, parsePart);
00608 break;
00609
00610 case PART_FILES:
00611 parsePart = parseFiles(spec);
00612 break;
00613
00614 case PART_NONE:
00615 case PART_LAST:
00616 case PART_BUILDARCHITECTURES:
00617 break;
00618 }
00619
00620 if (goterror || parsePart >= PART_LAST) {
00621 spec = freeSpec(spec);
00622 return parsePart;
00623 }
00624
00625
00626 if (spec->toplevel && parsePart != PART_BUILDARCHITECTURES)
00627 spec->toplevel = 0;
00628
00629
00630 if (spec->toplevel && parsePart == PART_BUILDARCHITECTURES) {
00631 int index;
00632 int x;
00633
00634 closeSpec(spec);
00635
00636
00637 spec->BASpecs = xcalloc(spec->BACount, sizeof(*spec->BASpecs));
00638 index = 0;
00639 if (spec->BANames != NULL)
00640 for (x = 0; x < spec->BACount; x++) {
00641
00642
00643
00644
00645 addMacro(NULL, "_target_cpu", NULL, spec->BANames[x], RMIL_RPMRC);
00646 spec->BASpecs[index] = NULL;
00647 if (parseSpec(ts, specFile, spec->rootURL, 1,
00648 passPhrase, cookie, anyarch, force, verify)
00649 || (spec->BASpecs[index] = rpmtsSetSpec(ts, NULL)) == NULL)
00650 {
00651 spec->BACount = index;
00652
00653 spec = freeSpec(spec);
00654 return RPMRC_FAIL;
00655
00656 }
00657
00658
00659 delMacro(NULL, "_target_cpu");
00660 index++;
00661 }
00662
00663 spec->BACount = index;
00664 if (! index) {
00665 rpmlog(RPMLOG_ERR,
00666 _("No compatible architectures found for build\n"));
00667
00668 spec = freeSpec(spec);
00669 return RPMRC_FAIL;
00670
00671 }
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682 if (spec->BACount >= 1) {
00683 Spec nspec = spec->BASpecs[0];
00684 spec->BASpecs = _free(spec->BASpecs);
00685 spec = freeSpec(spec);
00686 spec = nspec;
00687 }
00688
00689 (void) rpmtsSetSpec(ts, spec);
00690 return 0;
00691 }
00692 }
00693
00694
00695
00696 (void) genSourceRpmName(spec);
00697
00698
00699 {
00700 const char *platform = rpmExpand("%{_target_platform}", NULL);
00701 const char *arch = rpmExpand("%{_target_cpu}", NULL);
00702 const char *os = rpmExpand("%{_target_os}", NULL);
00703
00704 for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
00705 he->tag = RPMTAG_OS;
00706 he->t = RPM_STRING_TYPE;
00707
00708 he->p.str = os;
00709 he->c = 1;
00710 xx = headerPut(pkg->header, he, 0);
00711
00712 he->tag = RPMTAG_ARCH;
00713 he->t = RPM_STRING_TYPE;
00714 he->p.str = (pkg->noarch ? "noarch" : arch);
00715 he->c = 1;
00716 xx = headerPut(pkg->header, he, 0);
00717
00718 he->tag = RPMTAG_PLATFORM;
00719 he->t = RPM_STRING_TYPE;
00720 he->p.str = platform;
00721 he->c = 1;
00722 xx = headerPut(pkg->header, he, 0);
00723
00724 he->tag = RPMTAG_SOURCERPM;
00725 he->t = RPM_STRING_TYPE;
00726 he->p.str = spec->sourceRpmName;
00727 he->c = 1;
00728 xx = headerPut(pkg->header, he, 0);
00729
00730 if (!headerIsEntry(pkg->header, RPMTAG_DESCRIPTION)) {
00731 he->tag = RPMTAG_NVRA;
00732 xx = headerGet(pkg->header, he, 0);
00733 rpmlog(RPMLOG_ERR, _("Package has no %%description: %s\n"),
00734 he->p.str);
00735 he->p.ptr = _free(he->p.ptr);
00736 spec = freeSpec(spec);
00737 return RPMRC_FAIL;
00738 }
00739
00740 pkg->ds = rpmdsThis(pkg->header, RPMTAG_REQUIRENAME, RPMSENSE_EQUAL);
00741
00742 }
00743
00744 platform = _free(platform);
00745 arch = _free(arch);
00746 os = _free(os);
00747 }
00748
00749 closeSpec(spec);
00750 (void) rpmtsSetSpec(ts, spec);
00751
00752 return 0;
00753 }