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
00201
00202 if (!(strip & STRIP_NOEXPAND)) {
00203 if (spec->readStack->reading &&
00204 expandMacros(spec, spec->macros, spec->lbuf, sizeof(spec->lbuf))) {
00205 rpmError(RPMERR_BADSPEC, _("line %d: %s\n"),
00206 spec->lineNum, spec->lbuf);
00207 return RPMERR_BADSPEC;
00208 }
00209 }
00210 spec->nextline = spec->lbuf;
00211 }
00212
00213
00214 spec->line = last = spec->nextline;
00215 ch = ' ';
00216 while (*spec->nextline && ch != '\n') {
00217 ch = *spec->nextline++;
00218 if (!xisspace(ch))
00219 last = spec->nextline;
00220 }
00221
00222
00223 if (*spec->nextline != '\0') {
00224 spec->nextpeekc = *spec->nextline;
00225 *spec->nextline = '\0';
00226 }
00227
00228 if (strip & STRIP_COMMENTS)
00229 handleComments(spec->line);
00230
00231 if (strip & STRIP_TRAILINGSPACE)
00232 *last = '\0';
00233
00234 return 0;
00235 }
00236
00237
00238 static const char *getAlternateArch(const char *arch)
00239 {
00240 const char *alternate_arch = NULL;
00241 if (! strncmp("x86_64", arch, sizeof("x86_64")-1))
00242 alternate_arch = "amd64";
00243 else if (! strncmp("amd64", arch, sizeof("amd64")-1))
00244 alternate_arch = "x86_64";
00245 return alternate_arch;
00246 }
00247
00248
00249 int readLine(Spec spec, int strip)
00250 {
00251 #ifdef DYING
00252 const char *arch;
00253 const char *os;
00254 #endif
00255 char *s;
00256 int match;
00257 struct ReadLevelEntry *rl;
00258 OFI_t *ofi = spec->fileStack;
00259 int rc;
00260
00261 retry:
00262
00263
00264 if (ofi->fd == NULL) {
00265 ofi->fd = Fopen(ofi->fileName, "r.fpio");
00266 if (ofi->fd == NULL || Ferror(ofi->fd)) {
00267
00268 rpmError(RPMERR_BADSPEC, _("Unable to open %s: %s\n"),
00269 ofi->fileName, Fstrerror(ofi->fd));
00270 return RPMERR_BADSPEC;
00271 }
00272 spec->lineNum = ofi->lineNum = 0;
00273 }
00274
00275
00276
00277 if (!(ofi->readPtr && *(ofi->readPtr))) {
00278
00279 FILE * f = fdGetFp(ofi->fd);
00280
00281 if (f == NULL || !fgets(ofi->readBuf, BUFSIZ, f)) {
00282
00283 if (spec->readStack->next) {
00284 rpmError(RPMERR_UNMATCHEDIF, _("Unclosed %%if\n"));
00285 return RPMERR_UNMATCHEDIF;
00286 }
00287
00288
00289 spec->fileStack = ofi->next;
00290 (void) Fclose(ofi->fd);
00291 ofi->fileName = _free(ofi->fileName);
00292 ofi = _free(ofi);
00293
00294
00295 ofi = spec->fileStack;
00296 if (ofi == NULL)
00297 return 1;
00298
00299
00300 goto retry;
00301 }
00302 ofi->readPtr = ofi->readBuf;
00303 ofi->lineNum++;
00304 spec->lineNum = ofi->lineNum;
00305 if (spec->sl) {
00306 speclines sl = spec->sl;
00307 if (sl->sl_nlines == sl->sl_nalloc) {
00308 sl->sl_nalloc += 100;
00309 sl->sl_lines = (char **) xrealloc(sl->sl_lines,
00310 sl->sl_nalloc * sizeof(*(sl->sl_lines)));
00311 }
00312 sl->sl_lines[sl->sl_nlines++] = xstrdup(ofi->readBuf);
00313 }
00314 }
00315
00316
00317 if ((rc = copyNextLine(spec, ofi, strip)) != 0) {
00318 if (rc == RPMERR_UNMATCHEDIF)
00319 goto retry;
00320 return rc;
00321 }
00322
00323 s = spec->line;
00324 SKIPSPACE(s);
00325
00326 match = -1;
00327 if (! (strip & STRIP_NOEXPAND)) {
00328 if (!spec->readStack->reading && !strncmp("%if", s, sizeof("%if")-1)) {
00329 match = 0;
00330 } else if (! strncmp("%ifarch", s, sizeof("%ifarch")-1)) {
00331 const char *arch = rpmExpand("%{_target_cpu}", NULL);
00332 const char *alternate_arch = getAlternateArch(arch);
00333 s += 7;
00334 match = matchTok(arch, s) || (alternate_arch && matchTok(alternate_arch, s));
00335 arch = _free(arch);
00336 } else if (! strncmp("%ifnarch", s, sizeof("%ifnarch")-1)) {
00337 const char *arch = rpmExpand("%{_target_cpu}", NULL);
00338 const char *alternate_arch = getAlternateArch(arch);
00339 s += 8;
00340 match = !matchTok(arch, s) && (!alternate_arch || !matchTok(alternate_arch, s));
00341 arch = _free(arch);
00342 } else if (! strncmp("%ifos", s, sizeof("%ifos")-1)) {
00343 const char *os = rpmExpand("%{_target_os}", NULL);
00344 s += 5;
00345 match = matchTok(os, s);
00346 os = _free(os);
00347 } else if (! strncmp("%ifnos", s, sizeof("%ifnos")-1)) {
00348 const char *os = rpmExpand("%{_target_os}", NULL);
00349 s += 6;
00350 match = !matchTok(os, s);
00351 os = _free(os);
00352 } else if (! strncmp("%if", s, sizeof("%if")-1)) {
00353 s += 3;
00354 match = parseExpressionBoolean(spec, s);
00355 if (match < 0) {
00356 rpmError(RPMERR_UNMATCHEDIF,
00357 _("%s:%d: parseExpressionBoolean returns %d\n"),
00358 ofi->fileName, ofi->lineNum, match);
00359 return RPMERR_BADSPEC;
00360 }
00361 } else if (! strncmp("%else", s, sizeof("%else")-1)) {
00362 s += 5;
00363 if (! spec->readStack->next) {
00364
00365 rpmError(RPMERR_UNMATCHEDIF,
00366 _("%s:%d: Got a %%else with no %%if\n"),
00367 ofi->fileName, ofi->lineNum);
00368 return RPMERR_UNMATCHEDIF;
00369 }
00370 spec->readStack->reading =
00371 spec->readStack->next->reading && ! spec->readStack->reading;
00372 spec->line[0] = '\0';
00373 } else if (! strncmp("%endif", s, sizeof("%endif")-1)) {
00374 s += 6;
00375 if (! spec->readStack->next) {
00376
00377 rpmError(RPMERR_UNMATCHEDIF,
00378 _("%s:%d: Got a %%endif with no %%if\n"),
00379 ofi->fileName, ofi->lineNum);
00380 return RPMERR_UNMATCHEDIF;
00381 }
00382 rl = spec->readStack;
00383 spec->readStack = spec->readStack->next;
00384 free(rl);
00385 spec->line[0] = '\0';
00386 } else if (! strncmp("%include", s, sizeof("%include")-1)) {
00387 char *fileName, *endFileName, *p;
00388
00389 s += 8;
00390 fileName = s;
00391 if (! xisspace(*fileName)) {
00392 rpmError(RPMERR_BADSPEC, _("malformed %%include statement\n"));
00393 return RPMERR_BADSPEC;
00394 }
00395 SKIPSPACE(fileName);
00396 endFileName = fileName;
00397 SKIPNONSPACE(endFileName);
00398 p = endFileName;
00399 SKIPSPACE(p);
00400 if (*p != '\0') {
00401 rpmError(RPMERR_BADSPEC, _("malformed %%include statement\n"));
00402 return RPMERR_BADSPEC;
00403 }
00404 *endFileName = '\0';
00405
00406 forceIncludeFile(spec, fileName);
00407
00408 ofi = spec->fileStack;
00409 goto retry;
00410 }
00411 }
00412
00413 if (match != -1) {
00414 rl = xmalloc(sizeof(*rl));
00415 rl->reading = spec->readStack->reading && match;
00416 rl->next = spec->readStack;
00417 spec->readStack = rl;
00418 spec->line[0] = '\0';
00419 }
00420
00421 if (! spec->readStack->reading) {
00422 spec->line[0] = '\0';
00423 }
00424
00425
00426 return 0;
00427
00428 }
00429
00430
00431 void closeSpec(Spec spec)
00432 {
00433 OFI_t *ofi;
00434
00435 while (spec->fileStack) {
00436 ofi = spec->fileStack;
00437 spec->fileStack = spec->fileStack->next;
00438 if (ofi->fd) (void) Fclose(ofi->fd);
00439 ofi->fileName = _free(ofi->fileName);
00440 ofi = _free(ofi);
00441 }
00442 }
00443
00444
00445
00446 extern int noLang;
00447
00448
00449
00450
00451 int parseSpec(rpmts ts, const char *specFile, const char *rootURL,
00452 int recursing, const char *passPhrase,
00453 char *cookie, int anyarch, int force, int verify)
00454 {
00455 rpmParseState parsePart = PART_PREAMBLE;
00456 int initialPackage = 1;
00457 Package pkg;
00458 Spec spec;
00459
00460
00461 spec = newSpec();
00462
00463
00464
00465
00466
00467
00468
00469
00470 spec->specFile = rpmGetPath(specFile, NULL);
00471 spec->fileStack = newOpenFileInfo();
00472 spec->fileStack->fileName = xstrdup(spec->specFile);
00473
00474 spec->recursing = recursing;
00475 spec->anyarch = anyarch;
00476 spec->force = force;
00477
00478 if (rootURL)
00479 spec->rootURL = xstrdup(rootURL);
00480 if (passPhrase)
00481 spec->passPhrase = xstrdup(passPhrase);
00482 if (cookie)
00483 spec->cookie = xstrdup(cookie);
00484
00485 spec->timeCheck = rpmExpandNumeric("%{_timecheck}");
00486
00487
00488 addMacro(NULL, "_docdir", NULL, "%{_defaultdocdir}", RMIL_SPEC);
00489
00490
00491
00492
00493
00494
00495 while (parsePart < PART_LAST && parsePart != PART_NONE) {
00496 switch (parsePart) {
00497 case PART_PREAMBLE:
00498 parsePart = parsePreamble(spec, initialPackage);
00499 initialPackage = 0;
00500 break;
00501 case PART_PREP:
00502 parsePart = parsePrep(spec, verify);
00503 break;
00504 case PART_BUILD:
00505 case PART_INSTALL:
00506 case PART_CHECK:
00507 case PART_CLEAN:
00508 parsePart = parseBuildInstallClean(spec, parsePart);
00509 break;
00510 case PART_CHANGELOG:
00511 parsePart = parseChangelog(spec);
00512 break;
00513 case PART_DESCRIPTION:
00514 parsePart = parseDescription(spec);
00515 break;
00516
00517 case PART_PRE:
00518 case PART_POST:
00519 case PART_PREUN:
00520 case PART_POSTUN:
00521 case PART_PRETRANS:
00522 case PART_POSTTRANS:
00523 case PART_VERIFYSCRIPT:
00524 case PART_TRIGGERPREIN:
00525 case PART_TRIGGERIN:
00526 case PART_TRIGGERUN:
00527 case PART_TRIGGERPOSTUN:
00528 parsePart = parseScript(spec, parsePart);
00529 break;
00530
00531 case PART_FILES:
00532 parsePart = parseFiles(spec);
00533 break;
00534
00535 case PART_NONE:
00536 case PART_LAST:
00537 case PART_BUILDARCHITECTURES:
00538 break;
00539 }
00540
00541 if (parsePart >= PART_LAST) {
00542 spec = freeSpec(spec);
00543 return parsePart;
00544 }
00545
00546 if (parsePart == PART_BUILDARCHITECTURES) {
00547 int index;
00548 int x;
00549
00550 closeSpec(spec);
00551
00552
00553 spec->BASpecs = xcalloc(spec->BACount, sizeof(*spec->BASpecs));
00554 index = 0;
00555 if (spec->BANames != NULL)
00556 for (x = 0; x < spec->BACount; x++) {
00557
00558
00559
00560
00561 addMacro(NULL, "_target_cpu", NULL, spec->BANames[x], RMIL_RPMRC);
00562 spec->BASpecs[index] = NULL;
00563 if (parseSpec(ts, specFile, spec->rootURL, 1,
00564 passPhrase, cookie, anyarch, force, verify)
00565 || (spec->BASpecs[index] = rpmtsSetSpec(ts, NULL)) == NULL)
00566 {
00567 spec->BACount = index;
00568
00569 spec = freeSpec(spec);
00570 return RPMERR_BADSPEC;
00571
00572 }
00573
00574
00575 delMacro(NULL, "_target_cpu");
00576 index++;
00577 }
00578
00579 spec->BACount = index;
00580 if (! index) {
00581 rpmError(RPMERR_BADSPEC,
00582 _("No compatible architectures found for build\n"));
00583
00584 spec = freeSpec(spec);
00585 return RPMERR_BADSPEC;
00586
00587 }
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599 if (spec->BACount >= 1) {
00600 Spec nspec = spec->BASpecs[0];
00601 spec->BASpecs = _free(spec->BASpecs);
00602 spec = freeSpec(spec);
00603 spec = nspec;
00604 }
00605
00606
00607 (void) rpmtsSetSpec(ts, spec);
00608 return 0;
00609 }
00610 }
00611
00612
00613
00614 {
00615 const char *platform = rpmExpand("%{_target_platform}", NULL);
00616 const char *arch = rpmExpand("%{_target_cpu}", NULL);
00617 const char *os = rpmExpand("%{_target_os}", NULL);
00618
00619 for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
00620 if (!headerIsEntry(pkg->header, RPMTAG_DESCRIPTION)) {
00621 const char * name;
00622 (void) headerNVR(pkg->header, &name, NULL, NULL);
00623 rpmError(RPMERR_BADSPEC, _("Package has no %%description: %s\n"),
00624 name);
00625 spec = freeSpec(spec);
00626 return RPMERR_BADSPEC;
00627 }
00628
00629 (void) headerAddEntry(pkg->header, RPMTAG_OS, RPM_STRING_TYPE, os, 1);
00630 (void) headerAddEntry(pkg->header, RPMTAG_ARCH,
00631 RPM_STRING_TYPE, arch, 1);
00632 (void) headerAddEntry(pkg->header, RPMTAG_PLATFORM,
00633 RPM_STRING_TYPE, platform, 1);
00634
00635 pkg->ds = rpmdsThis(pkg->header, RPMTAG_REQUIRENAME, RPMSENSE_EQUAL);
00636
00637 }
00638
00639 platform = _free(platform);
00640 arch = _free(arch);
00641 os = _free(os);
00642 }
00643
00644 closeSpec(spec);
00645 (void) rpmtsSetSpec(ts, spec);
00646
00647 return 0;
00648 }
00649