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