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