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