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