00001
00006 #include "system.h"
00007
00008 #include <rpmio_internal.h>
00009 #include <rpmbuild.h>
00010 #include "rpmds.h"
00011 #include "rpmts.h"
00012 #include "debug.h"
00013
00014
00015
00018
00019 static struct PartRec {
00020 int part;
00021 int len;
00022
00023 const char * token;
00024 } partList[] = {
00025 { PART_PREAMBLE, 0, "%package"},
00026 { PART_PREP, 0, "%prep"},
00027 { PART_BUILD, 0, "%build"},
00028 { PART_INSTALL, 0, "%install"},
00029 { PART_CHECK, 0, "%check"},
00030 { PART_CLEAN, 0, "%clean"},
00031 { PART_PREUN, 0, "%preun"},
00032 { PART_POSTUN, 0, "%postun"},
00033 { PART_PRETRANS, 0, "%pretrans"},
00034 { PART_POSTTRANS, 0, "%posttrans"},
00035 { PART_PRE, 0, "%pre"},
00036 { PART_POST, 0, "%post"},
00037 { PART_FILES, 0, "%files"},
00038 { PART_CHANGELOG, 0, "%changelog"},
00039 { PART_DESCRIPTION, 0, "%description"},
00040 { PART_TRIGGERPOSTUN, 0, "%triggerpostun"},
00041 { PART_TRIGGERPREIN, 0, "%triggerprein"},
00042 { PART_TRIGGERUN, 0, "%triggerun"},
00043 { PART_TRIGGERIN, 0, "%triggerin"},
00044 { PART_TRIGGERIN, 0, "%trigger"},
00045 { PART_VERIFYSCRIPT, 0, "%verifyscript"},
00046 {0, 0, 0}
00047 };
00048
00051 static inline void initParts(struct PartRec *p)
00052
00053 {
00054 for (; p->token != NULL; p++)
00055 p->len = strlen(p->token);
00056 }
00057
00058 rpmParseState isPart(const char *line)
00059 {
00060 struct PartRec *p;
00061
00062
00063 if (partList[0].len == 0)
00064 initParts(partList);
00065
00066
00067 for (p = partList; p->token != NULL; p++) {
00068 char c;
00069 if (xstrncasecmp(line, p->token, p->len))
00070 continue;
00071
00072 c = *(line + p->len);
00073
00074 if (c == '\0' || xisspace(c))
00075 break;
00076 }
00077
00078 return (p->token ? p->part : PART_NONE);
00079 }
00080
00083 static int matchTok(const char *token, const char *line)
00084
00085 {
00086 const char *b, *be = line;
00087 size_t toklen = strlen(token);
00088 int rc = 0;
00089
00090
00091 while ( *(b = be) != '\0' ) {
00092 SKIPSPACE(b);
00093 be = b;
00094 SKIPNONSPACE(be);
00095 if (be == b)
00096 break;
00097 if (toklen != (be-b) || xstrncasecmp(token, b, (be-b)))
00098 continue;
00099 rc = 1;
00100 break;
00101 }
00102
00103
00104 return rc;
00105 }
00106
00107
00108 void handleComments(char *s)
00109 {
00110 SKIPSPACE(s);
00111 if (*s == '#')
00112 *s = '\0';
00113 }
00114
00115
00118 static void forceIncludeFile(Spec spec, const char * fileName)
00119
00120 {
00121 OFI_t * ofi;
00122
00123 ofi = newOpenFileInfo();
00124 ofi->fileName = xstrdup(fileName);
00125 ofi->next = spec->fileStack;
00126 spec->fileStack = ofi;
00127 }
00128
00131
00132 static int copyNextLineFromOFI(Spec spec, OFI_t *ofi)
00133 {
00134 char ch;
00135
00136
00137 if (!(spec->nextline && *spec->nextline)) {
00138 int pc = 0, bc = 0, nc = 0;
00139 char *from, *to, *p;
00140 to = spec->lbufPtr ? spec->lbufPtr : spec->lbuf;
00141 from = ofi->readPtr;
00142 ch = ' ';
00143 while (*from && ch != '\n')
00144 ch = *to++ = *from++;
00145
00146 spec->lbufPtr = to;
00147
00148 *to++ = '\0';
00149 ofi->readPtr = from;
00150
00151
00152 for (p = spec->lbuf; *p; p++) {
00153 switch (*p) {
00154 case '\\':
00155 switch (*(p+1)) {
00156 case '\n': p++, nc = 1; break;
00157 case '\0': break;
00158 default: p++; break;
00159 }
00160 break;
00161 case '\n': nc = 0; break;
00162 case '%':
00163 switch (*(p+1)) {
00164 case '{': p++, bc++; break;
00165 case '(': p++, pc++; break;
00166 case '%': p++; break;
00167 }
00168 break;
00169 case '{': if (bc > 0) bc++; break;
00170 case '}': if (bc > 0) bc--; break;
00171 case '(': if (pc > 0) pc++; break;
00172 case ')': if (pc > 0) pc--; break;
00173 }
00174 }
00175
00176
00177
00178 if (pc || bc || nc ) {
00179
00180 spec->nextline = "";
00181
00182 return RPMERR_UNMATCHEDIF;
00183 }
00184
00185 spec->lbufPtr = spec->lbuf;
00186
00187
00188
00189 if (spec->readStack->reading &&
00190 expandMacros(spec, spec->macros, spec->lbuf, sizeof(spec->lbuf))) {
00191 rpmError(RPMERR_BADSPEC, _("line %d: %s\n"),
00192 spec->lineNum, spec->lbuf);
00193 return RPMERR_BADSPEC;
00194 }
00195 spec->nextline = spec->lbuf;
00196 }
00197
00198 return 0;
00199 }
00200
00203 static void copyNextLineFinish(Spec spec, int strip)
00204 {
00205 char *last;
00206 char ch;
00207
00208
00209 spec->line = last = spec->nextline;
00210 ch = ' ';
00211 while (*spec->nextline && ch != '\n') {
00212 ch = *spec->nextline++;
00213 if (!xisspace(ch))
00214 last = spec->nextline;
00215 }
00216
00217
00218 if (*spec->nextline != '\0') {
00219 spec->nextpeekc = *spec->nextline;
00220 *spec->nextline = '\0';
00221 }
00222
00223 if (strip & STRIP_COMMENTS)
00224 handleComments(spec->line);
00225
00226 if (strip & STRIP_TRAILINGSPACE)
00227 *last = '\0';
00228 }
00229
00230
00231 static int readLineFromOFI(Spec spec, OFI_t *ofi)
00232 {
00233
00234 retry:
00235
00236
00237 if (ofi->fd == NULL) {
00238 ofi->fd = Fopen(ofi->fileName, "r.fpio");
00239 if (ofi->fd == NULL || Ferror(ofi->fd)) {
00240
00241 rpmError(RPMERR_BADSPEC, _("Unable to open %s: %s\n"),
00242 ofi->fileName, Fstrerror(ofi->fd));
00243 return RPMERR_BADSPEC;
00244 }
00245 spec->lineNum = ofi->lineNum = 0;
00246 }
00247
00248
00249 if (!(ofi->readPtr && *(ofi->readPtr))) {
00250
00251 FILE * f = fdGetFp(ofi->fd);
00252
00253 if (f == NULL || !fgets(ofi->readBuf, BUFSIZ, f)) {
00254
00255 if (spec->readStack->next) {
00256 rpmError(RPMERR_UNMATCHEDIF, _("Unclosed %%if\n"));
00257 return RPMERR_UNMATCHEDIF;
00258 }
00259
00260
00261 spec->fileStack = ofi->next;
00262 (void) Fclose(ofi->fd);
00263 ofi->fileName = _free(ofi->fileName);
00264 ofi = _free(ofi);
00265
00266
00267 ofi = spec->fileStack;
00268 if (ofi == NULL)
00269 return 1;
00270
00271
00272 goto retry;
00273 }
00274 ofi->readPtr = ofi->readBuf;
00275 ofi->lineNum++;
00276 spec->lineNum = ofi->lineNum;
00277 if (spec->sl) {
00278 speclines sl = spec->sl;
00279 if (sl->sl_nlines == sl->sl_nalloc) {
00280 sl->sl_nalloc += 100;
00281 sl->sl_lines = (char **) xrealloc(sl->sl_lines,
00282 sl->sl_nalloc * sizeof(*(sl->sl_lines)));
00283 }
00284 sl->sl_lines[sl->sl_nlines++] = xstrdup(ofi->readBuf);
00285 }
00286 }
00287 return 0;
00288 }
00289
00290
00291 int readLine(Spec spec, int strip)
00292 {
00293 #ifdef DYING
00294 const char *arch;
00295 const char *os;
00296 #endif
00297 char *s;
00298 int match;
00299 struct ReadLevelEntry *rl;
00300 OFI_t *ofi = spec->fileStack;
00301 int rc;
00302
00303 #ifdef DYING
00304 arch = NULL;
00305 rpmGetArchInfo(&arch, NULL);
00306 os = NULL;
00307 rpmGetOsInfo(&os, NULL);
00308 #endif
00309
00310
00311 if (spec->nextline != NULL && spec->nextpeekc != '\0') {
00312 *spec->nextline = spec->nextpeekc;
00313 spec->nextpeekc = '\0';
00314 } else {
00315 retry:
00316
00317 if ((rc = readLineFromOFI(spec, ofi)) != 0) {
00318 return rc;
00319 }
00320
00321 if ((rc = copyNextLineFromOFI(spec, ofi)) != 0) {
00322 if (rc == RPMERR_UNMATCHEDIF)
00323 goto retry;
00324 return rc;
00325 }
00326 }
00327
00328
00329 copyNextLineFinish(spec, strip);
00330
00331 s = spec->line;
00332 SKIPSPACE(s);
00333
00334 match = -1;
00335 if (!spec->readStack->reading && !strncmp("%if", s, sizeof("%if")-1)) {
00336 match = 0;
00337 } else if (! strncmp("%ifarch", s, sizeof("%ifarch")-1)) {
00338 const char *arch = rpmExpand("%{_target_cpu}", NULL);
00339 s += 7;
00340 match = matchTok(arch, s);
00341 arch = _free(arch);
00342 } else if (! strncmp("%ifnarch", s, sizeof("%ifnarch")-1)) {
00343 const char *arch = rpmExpand("%{_target_cpu}", NULL);
00344 s += 8;
00345 match = !matchTok(arch, s);
00346 arch = _free(arch);
00347 } else if (! strncmp("%ifos", s, sizeof("%ifos")-1)) {
00348 const char *os = rpmExpand("%{_target_os}", NULL);
00349 s += 5;
00350 match = matchTok(os, s);
00351 os = _free(os);
00352 } else if (! strncmp("%ifnos", s, sizeof("%ifnos")-1)) {
00353 const char *os = rpmExpand("%{_target_os}", NULL);
00354 s += 6;
00355 match = !matchTok(os, s);
00356 os = _free(os);
00357 } else if (! strncmp("%if", s, sizeof("%if")-1)) {
00358 s += 3;
00359 match = parseExpressionBoolean(spec, s);
00360 if (match < 0) {
00361 rpmError(RPMERR_UNMATCHEDIF,
00362 _("%s:%d: parseExpressionBoolean returns %d\n"),
00363 ofi->fileName, ofi->lineNum, match);
00364 return RPMERR_BADSPEC;
00365 }
00366 } else if (! strncmp("%else", s, sizeof("%else")-1)) {
00367 s += 5;
00368 if (! spec->readStack->next) {
00369
00370 rpmError(RPMERR_UNMATCHEDIF,
00371 _("%s:%d: Got a %%else with no %%if\n"),
00372 ofi->fileName, ofi->lineNum);
00373 return RPMERR_UNMATCHEDIF;
00374 }
00375 spec->readStack->reading =
00376 spec->readStack->next->reading && ! spec->readStack->reading;
00377 spec->line[0] = '\0';
00378 } else if (! strncmp("%endif", s, sizeof("%endif")-1)) {
00379 s += 6;
00380 if (! spec->readStack->next) {
00381
00382 rpmError(RPMERR_UNMATCHEDIF,
00383 _("%s:%d: Got a %%endif with no %%if\n"),
00384 ofi->fileName, ofi->lineNum);
00385 return RPMERR_UNMATCHEDIF;
00386 }
00387 rl = spec->readStack;
00388 spec->readStack = spec->readStack->next;
00389 free(rl);
00390 spec->line[0] = '\0';
00391 } else if (! strncmp("%include", s, sizeof("%include")-1)) {
00392 char *fileName, *endFileName, *p;
00393
00394 s += 8;
00395 fileName = s;
00396 if (! xisspace(*fileName)) {
00397 rpmError(RPMERR_BADSPEC, _("malformed %%include statement\n"));
00398 return RPMERR_BADSPEC;
00399 }
00400 SKIPSPACE(fileName);
00401 endFileName = fileName;
00402 SKIPNONSPACE(endFileName);
00403 p = endFileName;
00404 SKIPSPACE(p);
00405 if (*p != '\0') {
00406 rpmError(RPMERR_BADSPEC, _("malformed %%include statement\n"));
00407 return RPMERR_BADSPEC;
00408 }
00409 *endFileName = '\0';
00410
00411 forceIncludeFile(spec, fileName);
00412
00413 ofi = spec->fileStack;
00414 goto retry;
00415 }
00416
00417 if (match != -1) {
00418 rl = xmalloc(sizeof(*rl));
00419 rl->reading = spec->readStack->reading && match;
00420 rl->next = spec->readStack;
00421 spec->readStack = rl;
00422 spec->line[0] = '\0';
00423 }
00424
00425 if (! spec->readStack->reading) {
00426 spec->line[0] = '\0';
00427 }
00428
00429
00430 return 0;
00431
00432 }
00433
00434
00435 void closeSpec(Spec spec)
00436 {
00437 OFI_t *ofi;
00438
00439 while (spec->fileStack) {
00440 ofi = spec->fileStack;
00441 spec->fileStack = spec->fileStack->next;
00442 if (ofi->fd) (void) Fclose(ofi->fd);
00443 ofi->fileName = _free(ofi->fileName);
00444 ofi = _free(ofi);
00445 }
00446 }
00447
00448
00449
00450 extern int noLang;
00451
00452
00453
00454
00455 int parseSpec(rpmts ts, const char *specFile, const char *rootURL,
00456 const char *buildRootURL, int recursing, const char *passPhrase,
00457 char *cookie, int anyarch, int force)
00458 {
00459 rpmParseState parsePart = PART_PREAMBLE;
00460 int initialPackage = 1;
00461 #ifdef DYING
00462 const char *saveArch;
00463 #endif
00464 Package pkg;
00465 Spec spec;
00466
00467
00468 spec = newSpec();
00469
00470
00471
00472
00473
00474
00475
00476
00477 spec->specFile = rpmGetPath(specFile, NULL);
00478 spec->fileStack = newOpenFileInfo();
00479 spec->fileStack->fileName = xstrdup(spec->specFile);
00480 if (buildRootURL) {
00481 const char * buildRoot;
00482 (void) urlPath(buildRootURL, &buildRoot);
00483
00484 if (*buildRoot == '\0') buildRoot = "/";
00485
00486 if (!strcmp(buildRoot, "/")) {
00487 rpmError(RPMERR_BADSPEC,
00488 _("BuildRoot can not be \"/\": %s\n"), buildRootURL);
00489 return RPMERR_BADSPEC;
00490 }
00491 spec->gotBuildRootURL = 1;
00492 spec->buildRootURL = xstrdup(buildRootURL);
00493 addMacro(spec->macros, "buildroot", NULL, buildRoot, RMIL_SPEC);
00494 }
00495 addMacro(NULL, "_docdir", NULL, "%{_defaultdocdir}", RMIL_SPEC);
00496 spec->recursing = recursing;
00497 spec->anyarch = anyarch;
00498 spec->force = force;
00499
00500 if (rootURL)
00501 spec->rootURL = xstrdup(rootURL);
00502 if (passPhrase)
00503 spec->passPhrase = xstrdup(passPhrase);
00504 if (cookie)
00505 spec->cookie = xstrdup(cookie);
00506
00507 spec->timeCheck = rpmExpandNumeric("%{_timecheck}");
00508
00509
00510
00511
00512
00513
00514 while (parsePart < PART_LAST && parsePart != PART_NONE) {
00515 switch (parsePart) {
00516 case PART_PREAMBLE:
00517 parsePart = parsePreamble(spec, initialPackage);
00518 initialPackage = 0;
00519 break;
00520 case PART_PREP:
00521 parsePart = parsePrep(spec);
00522 break;
00523 case PART_BUILD:
00524 case PART_INSTALL:
00525 case PART_CHECK:
00526 case PART_CLEAN:
00527 parsePart = parseBuildInstallClean(spec, parsePart);
00528 break;
00529 case PART_CHANGELOG:
00530 parsePart = parseChangelog(spec);
00531 break;
00532 case PART_DESCRIPTION:
00533 parsePart = parseDescription(spec);
00534 break;
00535
00536 case PART_PRE:
00537 case PART_POST:
00538 case PART_PREUN:
00539 case PART_POSTUN:
00540 case PART_PRETRANS:
00541 case PART_POSTTRANS:
00542 case PART_VERIFYSCRIPT:
00543 case PART_TRIGGERPREIN:
00544 case PART_TRIGGERIN:
00545 case PART_TRIGGERUN:
00546 case PART_TRIGGERPOSTUN:
00547 parsePart = parseScript(spec, parsePart);
00548 break;
00549
00550 case PART_FILES:
00551 parsePart = parseFiles(spec);
00552 break;
00553
00554 case PART_NONE:
00555 case PART_LAST:
00556 case PART_BUILDARCHITECTURES:
00557 break;
00558 }
00559
00560 if (parsePart >= PART_LAST) {
00561 spec = freeSpec(spec);
00562 return parsePart;
00563 }
00564
00565 if (parsePart == PART_BUILDARCHITECTURES) {
00566 int index;
00567 int x;
00568
00569 closeSpec(spec);
00570
00571
00572 spec->BASpecs = xcalloc(spec->BACount, sizeof(*spec->BASpecs));
00573 index = 0;
00574 if (spec->BANames != NULL)
00575 for (x = 0; x < spec->BACount; x++) {
00576
00577
00578 if (!rpmMachineScore(RPM_MACHTABLE_BUILDARCH, spec->BANames[x]))
00579 continue;
00580 #ifdef DYING
00581 rpmGetMachine(&saveArch, NULL);
00582 saveArch = xstrdup(saveArch);
00583 rpmSetMachine(spec->BANames[x], NULL);
00584 #else
00585 addMacro(NULL, "_target_cpu", NULL, spec->BANames[x], RMIL_RPMRC);
00586 #endif
00587 spec->BASpecs[index] = NULL;
00588 if (parseSpec(ts, specFile, spec->rootURL, buildRootURL, 1,
00589 passPhrase, cookie, anyarch, force)
00590 || (spec->BASpecs[index] = rpmtsSetSpec(ts, NULL)) == NULL)
00591 {
00592 spec->BACount = index;
00593
00594 spec = freeSpec(spec);
00595 return RPMERR_BADSPEC;
00596
00597 }
00598 #ifdef DYING
00599 rpmSetMachine(saveArch, NULL);
00600 saveArch = _free(saveArch);
00601 #else
00602 delMacro(NULL, "_target_cpu");
00603 #endif
00604 index++;
00605 }
00606
00607 spec->BACount = index;
00608 if (! index) {
00609 rpmError(RPMERR_BADSPEC,
00610 _("No compatible architectures found for build\n"));
00611
00612 spec = freeSpec(spec);
00613 return RPMERR_BADSPEC;
00614
00615 }
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627 if (spec->BACount >= 1) {
00628 Spec nspec = spec->BASpecs[0];
00629 spec->BASpecs = _free(spec->BASpecs);
00630 spec = freeSpec(spec);
00631 spec = nspec;
00632 }
00633
00634
00635 (void) rpmtsSetSpec(ts, spec);
00636 return 0;
00637 }
00638 }
00639
00640
00641
00642 {
00643 #ifdef DYING
00644 const char *arch = NULL;
00645 const char *os = NULL;
00646 char *myos = NULL;
00647
00648 rpmGetArchInfo(&arch, NULL);
00649 rpmGetOsInfo(&os, NULL);
00650
00651
00652
00653
00654
00655
00656 if (!strcmp(os, "linux")) {
00657 myos = xstrdup(os);
00658 *myos = 'L';
00659 os = myos;
00660 }
00661 #else
00662 const char *platform = rpmExpand("%{_target_platform}", NULL);
00663 const char *arch = rpmExpand("%{_target_cpu}", NULL);
00664 const char *os = rpmExpand("%{_target_os}", NULL);
00665 #endif
00666
00667 for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
00668 if (!headerIsEntry(pkg->header, RPMTAG_DESCRIPTION)) {
00669 const char * name;
00670 (void) headerNVR(pkg->header, &name, NULL, NULL);
00671 rpmError(RPMERR_BADSPEC, _("Package has no %%description: %s\n"),
00672 name);
00673 spec = freeSpec(spec);
00674 return RPMERR_BADSPEC;
00675 }
00676
00677 (void) headerAddEntry(pkg->header, RPMTAG_OS, RPM_STRING_TYPE, os, 1);
00678 (void) headerAddEntry(pkg->header, RPMTAG_ARCH,
00679 RPM_STRING_TYPE, arch, 1);
00680 if (!headerIsEntry(pkg->header, RPMTAG_RHNPLATFORM))
00681 (void) headerAddEntry(pkg->header, RPMTAG_RHNPLATFORM,
00682 RPM_STRING_TYPE, arch, 1);
00683 (void) headerAddEntry(pkg->header, RPMTAG_PLATFORM,
00684 RPM_STRING_TYPE, platform, 1);
00685
00686 pkg->ds = rpmdsThis(pkg->header, RPMTAG_REQUIRENAME, RPMSENSE_EQUAL);
00687
00688 }
00689
00690 #ifdef DYING
00691 myos = _free(myos);
00692 #else
00693 platform = _free(platform);
00694 arch = _free(arch);
00695 os = _free(os);
00696 #endif
00697 }
00698
00699 closeSpec(spec);
00700 (void) rpmtsSetSpec(ts, spec);
00701
00702 return 0;
00703 }
00704