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