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
00200
00201 if (!(strip & STRIP_NOEXPAND)) {
00202 if (spec->readStack->reading &&
00203 expandMacros(spec, spec->macros, spec->lbuf, sizeof(spec->lbuf))) {
00204 rpmError(RPMERR_BADSPEC, _("line %d: %s\n"),
00205 spec->lineNum, spec->lbuf);
00206 return RPMERR_BADSPEC;
00207 }
00208 }
00209 spec->nextline = spec->lbuf;
00210 }
00211
00212
00213 spec->line = last = spec->nextline;
00214 ch = ' ';
00215 while (*spec->nextline && ch != '\n') {
00216 ch = *spec->nextline++;
00217 if (!xisspace(ch))
00218 last = spec->nextline;
00219 }
00220
00221
00222 if (*spec->nextline != '\0') {
00223 spec->nextpeekc = *spec->nextline;
00224 *spec->nextline = '\0';
00225 }
00226
00227 if (strip & STRIP_COMMENTS)
00228 handleComments(spec->line);
00229
00230 if (strip & STRIP_TRAILINGSPACE)
00231 *last = '\0';
00232
00233 return 0;
00234 }
00235
00236 static const char *getAlternateArch(const char *arch)
00237 {
00238 const char *alternate_arch = NULL;
00239 if (! strncmp("x86_64", arch, sizeof("x86_64")-1))
00240 alternate_arch = "amd64";
00241 else if (! strncmp("amd64", arch, sizeof("amd64")-1))
00242 alternate_arch = "x86_64";
00243 return alternate_arch;
00244 }
00245
00246
00247 int readLine(Spec spec, int strip)
00248 {
00249 #ifdef DYING
00250 const char *arch;
00251 const char *os;
00252 #endif
00253 char *s;
00254 int match;
00255 struct ReadLevelEntry *rl;
00256 OFI_t *ofi = spec->fileStack;
00257 int rc;
00258
00259 retry:
00260
00261
00262 if (ofi->fd == NULL) {
00263 ofi->fd = Fopen(ofi->fileName, "r.fpio");
00264 if (ofi->fd == NULL || Ferror(ofi->fd)) {
00265
00266 rpmError(RPMERR_BADSPEC, _("Unable to open %s: %s\n"),
00267 ofi->fileName, Fstrerror(ofi->fd));
00268 return RPMERR_BADSPEC;
00269 }
00270 spec->lineNum = ofi->lineNum = 0;
00271 }
00272
00273
00274
00275 if (!(ofi->readPtr && *(ofi->readPtr))) {
00276
00277 FILE * f = fdGetFp(ofi->fd);
00278
00279 if (f == NULL || !fgets(ofi->readBuf, BUFSIZ, f)) {
00280
00281 if (spec->readStack->next) {
00282 rpmError(RPMERR_UNMATCHEDIF, _("Unclosed %%if\n"));
00283 return RPMERR_UNMATCHEDIF;
00284 }
00285
00286
00287 spec->fileStack = ofi->next;
00288 (void) Fclose(ofi->fd);
00289 ofi->fileName = _free(ofi->fileName);
00290 ofi = _free(ofi);
00291
00292
00293 ofi = spec->fileStack;
00294 if (ofi == NULL)
00295 return 1;
00296
00297
00298 goto retry;
00299 }
00300 ofi->readPtr = ofi->readBuf;
00301 ofi->lineNum++;
00302 spec->lineNum = ofi->lineNum;
00303 if (spec->sl) {
00304 speclines sl = spec->sl;
00305 if (sl->sl_nlines == sl->sl_nalloc) {
00306 sl->sl_nalloc += 100;
00307 sl->sl_lines = (char **) xrealloc(sl->sl_lines,
00308 sl->sl_nalloc * sizeof(*(sl->sl_lines)));
00309 }
00310 sl->sl_lines[sl->sl_nlines++] = xstrdup(ofi->readBuf);
00311 }
00312 }
00313
00314 #ifdef DYING
00315 arch = NULL;
00316 rpmGetArchInfo(&arch, NULL);
00317 os = NULL;
00318 rpmGetOsInfo(&os, NULL);
00319 #endif
00320
00321
00322 if ((rc = copyNextLine(spec, ofi, strip)) != 0) {
00323 if (rc == RPMERR_UNMATCHEDIF)
00324 goto retry;
00325 return rc;
00326 }
00327
00328 s = spec->line;
00329 SKIPSPACE(s);
00330
00331 match = -1;
00332 if (! (strip & STRIP_NOEXPAND)) {
00333 if (!spec->readStack->reading && !strncmp("%if", s, sizeof("%if")-1)) {
00334 match = 0;
00335 } else if (! strncmp("%ifarch", s, sizeof("%ifarch")-1)) {
00336 const char *arch = rpmExpand("%{_target_cpu}", NULL);
00337 const char *alternate_arch = getAlternateArch(arch);
00338 s += 7;
00339 match = matchTok(arch, s) || (alternate_arch && matchTok(alternate_arch, s));
00340 arch = _free(arch);
00341 } else if (! strncmp("%ifnarch", s, sizeof("%ifnarch")-1)) {
00342 const char *arch = rpmExpand("%{_target_cpu}", NULL);
00343 const char *alternate_arch = getAlternateArch(arch);
00344 s += 8;
00345 match = !matchTok(arch, s) && (!alternate_arch || !matchTok(alternate_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
00418 if (match != -1) {
00419 rl = xmalloc(sizeof(*rl));
00420 rl->reading = spec->readStack->reading && match;
00421 rl->next = spec->readStack;
00422 spec->readStack = rl;
00423 spec->line[0] = '\0';
00424 }
00425
00426 if (! spec->readStack->reading) {
00427 spec->line[0] = '\0';
00428 }
00429
00430
00431 return 0;
00432
00433 }
00434
00435
00436 void closeSpec(Spec spec)
00437 {
00438 OFI_t *ofi;
00439
00440 while (spec->fileStack) {
00441 ofi = spec->fileStack;
00442 spec->fileStack = spec->fileStack->next;
00443 if (ofi->fd) (void) Fclose(ofi->fd);
00444 ofi->fileName = _free(ofi->fileName);
00445 ofi = _free(ofi);
00446 }
00447 }
00448
00449
00450
00451 extern int noLang;
00452
00453
00454
00455
00456 int parseSpec(rpmts ts, const char *specFile, const char *rootURL,
00457 const char *buildRootURL, int recursing, const char *passPhrase,
00458 char *cookie, int anyarch, int force)
00459 {
00460 rpmParseState parsePart = PART_PREAMBLE;
00461 int initialPackage = 1;
00462 #ifdef DYING
00463 const char *saveArch;
00464 #endif
00465 Package pkg;
00466 Spec spec;
00467
00468
00469 spec = newSpec();
00470
00471
00472
00473
00474
00475
00476
00477
00478 spec->specFile = rpmGetPath(specFile, NULL);
00479 spec->fileStack = newOpenFileInfo();
00480 spec->fileStack->fileName = xstrdup(spec->specFile);
00481 if (buildRootURL) {
00482 const char * buildRoot;
00483 (void) urlPath(buildRootURL, &buildRoot);
00484
00485 if (*buildRoot == '\0') buildRoot = "/";
00486
00487 if (!strcmp(buildRoot, "/")) {
00488 rpmError(RPMERR_BADSPEC,
00489 _("BuildRoot can not be \"/\": %s\n"), buildRootURL);
00490 return RPMERR_BADSPEC;
00491 }
00492 spec->gotBuildRootURL = 1;
00493 spec->buildRootURL = xstrdup(buildRootURL);
00494 addMacro(spec->macros, "buildroot", NULL, buildRoot, RMIL_SPEC);
00495 }
00496 addMacro(NULL, "_docdir", NULL, "%{_defaultdocdir}", RMIL_SPEC);
00497 spec->recursing = recursing;
00498 spec->anyarch = anyarch;
00499 spec->force = force;
00500
00501 if (rootURL)
00502 spec->rootURL = xstrdup(rootURL);
00503 if (passPhrase)
00504 spec->passPhrase = xstrdup(passPhrase);
00505 if (cookie)
00506 spec->cookie = xstrdup(cookie);
00507
00508 spec->timeCheck = rpmExpandNumeric("%{_timecheck}");
00509
00510
00511
00512
00513
00514
00515 while (parsePart < PART_LAST && parsePart != PART_NONE) {
00516 switch (parsePart) {
00517 case PART_PREAMBLE:
00518 parsePart = parsePreamble(spec, initialPackage);
00519 initialPackage = 0;
00520 break;
00521 case PART_PREP:
00522 parsePart = parsePrep(spec);
00523 break;
00524 case PART_BUILD:
00525 case PART_INSTALL:
00526 case PART_CHECK:
00527 case PART_CLEAN:
00528 parsePart = parseBuildInstallClean(spec, parsePart);
00529 break;
00530 case PART_CHANGELOG:
00531 parsePart = parseChangelog(spec);
00532 break;
00533 case PART_DESCRIPTION:
00534 parsePart = parseDescription(spec);
00535 break;
00536
00537 case PART_PRE:
00538 case PART_POST:
00539 case PART_PREUN:
00540 case PART_POSTUN:
00541 case PART_PRETRANS:
00542 case PART_POSTTRANS:
00543 case PART_VERIFYSCRIPT:
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