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