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