/** * Parse a spec file, and query the resultant header. * @param ts rpm transaction * @param qva query args * @param specName specfile to parse * @param target cpu-vender-os platform for query (NULL is current) * @return 0 on success */ static int _specQuery(rpmts ts, QVA_t qva, const char *specName, /*@null@*/ const char *target) /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/ { Spec spec = NULL; Package pkg; int res = 1; /* assume error */ int anyarch = (target == NULL) ? 1 : 0; char * passPhrase = ""; int recursing = 0; char *cookie = NULL; int verify = 0; int xx; /*@-mods@*/ /* FIX: make spec abstract */ if (parseSpec(ts, specName, "/", recursing, passPhrase, cookie, anyarch, 1, verify) || (spec = rpmtsSetSpec(ts, NULL)) == NULL) { rpmlog(RPMLOG_ERR, _("query of specfile %s failed, can't parse\n"), specName); goto exit; } /*@=mods@*/ res = 0; if (specedit) { printNewSpecfile(spec); goto exit; } switch (qva->qva_source) { case RPMQV_SPECSRPM: xx = initSourceHeader(spec, NULL); xx = initSourceHeaderScriptlets(spec); xx = qva->qva_showPackage(qva, ts, spec->sourceHeader); break; default: case RPMQV_SPECFILE: for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) { /* If no target was specified, display all packages. * Packages with empty file lists are not produced. */ /* XXX DIEDIEDIE: this logic looks flawed. */ if (target == NULL || pkg->fileList != NULL) xx = qva->qva_showPackage(qva, ts, pkg->header); } break; } exit: spec = freeSpec(spec); return res; }
int parseSpec(rpmts ts, const char *specFile, const char *rootDir, const char *buildRoot, int recursing, const char *passPhrase, const char *cookie, int anyarch, int force) { rpmParseState parsePart = PART_PREAMBLE; int initialPackage = 1; Package pkg; rpmSpec spec; /* Set up a new Spec structure with no packages. */ spec = newSpec(); spec->specFile = rpmGetPath(specFile, NULL); spec->fileStack = newOpenFileInfo(); spec->fileStack->fileName = xstrdup(spec->specFile); /* If buildRoot not specified, use default %{buildroot} */ if (buildRoot) { spec->buildRoot = xstrdup(buildRoot); } else { spec->buildRoot = rpmGetPath("%{?buildroot:%{buildroot}}", NULL); } addMacro(NULL, "_docdir", NULL, "%{_defaultdocdir}", RMIL_SPEC); spec->recursing = recursing; spec->anyarch = anyarch; spec->force = force; if (rootDir) spec->rootDir = xstrdup(rootDir); if (passPhrase) spec->passPhrase = xstrdup(passPhrase); if (cookie) spec->cookie = xstrdup(cookie); spec->timeCheck = rpmExpandNumeric("%{_timecheck}"); /* All the parse*() functions expect to have a line pre-read */ /* in the spec's line buffer. Except for parsePreamble(), */ /* which handles the initial entry into a spec file. */ while (parsePart != PART_NONE) { int goterror = 0; switch (parsePart) { /* XXX Trap unexpected RPMRC_FAIL returns for now */ case RPMRC_FAIL: rpmlog(RPMLOG_ERR, "FIXME: got RPMRC_FAIL from spec parse\n"); abort(); case PART_ERROR: /* fallthrough */ default: goterror = 1; break; case PART_PREAMBLE: parsePart = parsePreamble(spec, initialPackage); initialPackage = 0; break; case PART_PREP: parsePart = parsePrep(spec); break; case PART_BUILD: case PART_INSTALL: case PART_CHECK: case PART_CLEAN: parsePart = parseBuildInstallClean(spec, parsePart); break; case PART_CHANGELOG: parsePart = parseChangelog(spec); break; case PART_DESCRIPTION: parsePart = parseDescription(spec); break; case PART_PRE: case PART_POST: case PART_PREUN: case PART_POSTUN: case PART_PRETRANS: case PART_POSTTRANS: case PART_VERIFYSCRIPT: case PART_TRIGGERPREIN: case PART_TRIGGERIN: case PART_TRIGGERUN: case PART_TRIGGERPOSTUN: parsePart = parseScript(spec, parsePart); break; case PART_FILES: parsePart = parseFiles(spec); break; case PART_NONE: /* XXX avoid gcc whining */ case PART_LAST: case PART_BUILDARCHITECTURES: break; } if (goterror || parsePart >= PART_LAST) { goto errxit; } if (parsePart == PART_BUILDARCHITECTURES) { int index; int x; closeSpec(spec); spec->BASpecs = xcalloc(spec->BACount, sizeof(*spec->BASpecs)); index = 0; if (spec->BANames != NULL) for (x = 0; x < spec->BACount; x++) { /* Skip if not arch is not compatible. */ if (!rpmMachineScore(RPM_MACHTABLE_BUILDARCH, spec->BANames[x])) continue; addMacro(NULL, "_target_cpu", NULL, spec->BANames[x], RMIL_RPMRC); spec->BASpecs[index] = NULL; if (parseSpec(ts, specFile, spec->rootDir, buildRoot, 1, passPhrase, cookie, anyarch, force) || (spec->BASpecs[index] = rpmtsSetSpec(ts, NULL)) == NULL) { spec->BACount = index; goto errxit; } delMacro(NULL, "_target_cpu"); index++; } spec->BACount = index; if (! index) { rpmlog(RPMLOG_ERR, _("No compatible architectures found for build\n")); goto errxit; } /* * Return the 1st child's fully parsed Spec structure. * The restart of the parse when encountering BuildArch * causes problems for "rpm -q --specfile". This is * still a hack because there may be more than 1 arch * specified (unlikely but possible.) There's also the * further problem that the macro context, particularly * %{_target_cpu}, disagrees with the info in the header. */ if (spec->BACount >= 1) { rpmSpec nspec = spec->BASpecs[0]; spec->BASpecs = _free(spec->BASpecs); spec = freeSpec(spec); spec = nspec; } (void) rpmtsSetSpec(ts, spec); return 0; } } if (spec->clean == NULL) { char *body = rpmExpand("%{?buildroot: %{__rm} -rf %{buildroot}}", NULL); spec->clean = newStringBuf(); appendLineStringBuf(spec->clean, body); free(body); } /* Check for description in each package and add arch and os */ { char *platform = rpmExpand("%{_target_platform}", NULL); char *arch = rpmExpand("%{_target_cpu}", NULL); char *os = rpmExpand("%{_target_os}", NULL); for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) { if (!headerIsEntry(pkg->header, RPMTAG_DESCRIPTION)) { rpmlog(RPMLOG_ERR, _("Package has no %%description: %s\n"), headerGetString(pkg->header, RPMTAG_NAME)); goto errxit; } headerPutString(pkg->header, RPMTAG_OS, os); /* noarch subpackages already have arch set here, leave it alone */ if (!headerIsEntry(pkg->header, RPMTAG_ARCH)) { headerPutString(pkg->header, RPMTAG_ARCH, arch); } headerPutString(pkg->header, RPMTAG_PLATFORM, platform); pkg->ds = rpmdsThis(pkg->header, RPMTAG_REQUIRENAME, RPMSENSE_EQUAL); } platform = _free(platform); arch = _free(arch); os = _free(os); } closeSpec(spec); (void) rpmtsSetSpec(ts, spec); return 0; errxit: spec = freeSpec(spec); return PART_ERROR; }
static void spec_free(Spec rspec) { freeSpec(rspec); }
/*@-boundswrite@*/ static int buildForTarget(rpmts ts, BTA_t ba) /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ /*@modifies ts, rpmGlobalMacroContext, fileSystem, internalState @*/ { const char * passPhrase = ba->passPhrase; const char * cookie = ba->cookie; int buildAmount = ba->buildAmount; const char * specFile = NULL; const char * specURL = NULL; int specut; const char * s; char * se; const char * arg = ba->specFile; size_t nb = strlen(arg) + BUFSIZ; char * buf = alloca(nb); Spec spec = NULL; int verify = ((ba->buildAmount & RPMBUILD_TRACK) ? 0 : 1); int xx; int rc; if (ba->buildMode == 't') { static const char * sfpats[] = { "Specfile", "\\*.spec", NULL }; static const char _specfn[] = "%{mkstemp:%{_specdir}/rpm-spec.XXXXXX}"; char * tmpSpecFile = (char *) rpmGetPath(_specfn, NULL); FILE *fp; int bingo = 0; int i; for (i = 0; sfpats[i]; i++) { se = rpmExpand("%{uncompress: %{u2p:", arg, "}}", " | %{__tar} -xOvf - %{?__tar_wildcards} ", sfpats[i], " 2>&1 > '", tmpSpecFile, "'", NULL); fp = popen(se, "r"); se = _free(se); if (fp== NULL) continue; s = fgets(buf, nb - 1, fp); xx = pclose(fp); if (!s || !*s || strstr(s, ": Not found in archive")) continue; bingo = 1; break; } if (!bingo) { rpmlog(RPMLOG_ERR, _("Failed to read spec file from %s\n"), arg); xx = Unlink(tmpSpecFile); tmpSpecFile = _free(tmpSpecFile); return 1; } s = se = basename(buf); se += strlen(se); while (--se > s && strchr("\r\n", *se) != NULL) *se = '\0'; specURL = rpmGetPath("%{_specdir}/", s, NULL); specut = urlPath(specURL, &specFile); xx = Rename(tmpSpecFile, specFile); if (xx) { rpmlog(RPMLOG_ERR, _("Failed to rename %s to %s: %m\n"), tmpSpecFile, s); (void) Unlink(tmpSpecFile); } tmpSpecFile = _free(tmpSpecFile); if (xx) return 1; se = buf; *se = '\0'; se = stpcpy(se, "_sourcedir "); (void) urlPath(arg, &s); if (*s != '/') { if (getcwd(se, nb - sizeof("_sourcedir ")) != NULL) se += strlen(se); else se = stpcpy(se, "."); } else se = stpcpy(se, dirname(strcpy(se, s))); while (se > buf && se[-1] == '/') *se-- = '0'; rpmCleanPath(buf + sizeof("_sourcedir ") - 1); rpmDefineMacro(NULL, buf, RMIL_TARBALL); } else { specut = urlPath(arg, &s); se = buf; *se = '\0'; if (*s != '/') { if (getcwd(se, nb - sizeof("_sourcedir ")) != NULL) se += strlen(se); else se = stpcpy(se, "."); *se++ = '/'; se += strlen(strcpy(se,strcpy(se, s))); } else se = stpcpy(se, s); specURL = rpmGetPath(buf, NULL); specut = urlPath(specURL, &specFile); } if (specut != URL_IS_DASH) { struct stat sb; if (Stat(specURL, &sb) < 0) { rpmlog(RPMLOG_ERR, _("failed to stat %s: %m\n"), specURL); rc = 1; goto exit; } if (! S_ISREG(sb.st_mode)) { rpmlog(RPMLOG_ERR, _("File %s is not a regular file.\n"), specURL); rc = 1; goto exit; } /* Try to verify that the file is actually a specfile */ if (!isSpecFile(specURL)) { rpmlog(RPMLOG_ERR, _("File %s does not appear to be a specfile.\n"), specURL); rc = 1; goto exit; } } /* Parse the spec file */ #define _anyarch(_f) \ (((_f)&(RPMBUILD_PREP|RPMBUILD_BUILD|RPMBUILD_INSTALL|RPMBUILD_PACKAGEBINARY)) == 0) if (parseSpec(ts, specURL, ba->rootdir, 0, passPhrase, cookie, _anyarch(buildAmount), 0, verify)) { rc = 1; goto exit; } #undef _anyarch if ((spec = rpmtsSetSpec(ts, NULL)) == NULL) { rc = 1; goto exit; } /* Assemble source header from parsed components */ xx = initSourceHeader(spec, NULL); /* Check build prerequisites */ if (!ba->noDeps && checkSpec(ts, spec->sourceHeader)) { rc = 1; goto exit; } if (buildSpec(ts, spec, buildAmount, ba->noBuild)) { rc = 1; goto exit; } if (ba->buildMode == 't') (void) Unlink(specURL); rc = 0; exit: spec = freeSpec(spec); specURL = _free(specURL); return rc; }
rpmRC readRPM(const char *fileName, rpmSpec *specp, Header *sigs, CSA_t csa) { FD_t fdi; rpmSpec spec; rpmRC rc; fdi = (fileName != NULL) ? Fopen(fileName, "r.ufdio") : fdDup(STDIN_FILENO); if (fdi == NULL || Ferror(fdi)) { rpmlog(RPMLOG_ERR, _("readRPM: open %s: %s\n"), (fileName ? fileName : "<stdin>"), Fstrerror(fdi)); if (fdi) (void) Fclose(fdi); return RPMRC_FAIL; } /* XXX FIXME: EPIPE on <stdin> */ if (Fseek(fdi, 0, SEEK_SET) == -1) { rpmlog(RPMLOG_ERR, _("%s: Fseek failed: %s\n"), (fileName ? fileName : "<stdin>"), Fstrerror(fdi)); return RPMRC_FAIL; } /* Reallocate build data structures */ spec = newSpec(); spec->packages = newPackage(spec); /* XXX the header just allocated will be allocated again */ spec->packages->header = headerFree(spec->packages->header); /* Read the rpm lead, signatures, and header */ { rpmts ts = rpmtsCreate(); /* XXX W2DO? pass fileName? */ /* LCL: segfault */ rc = rpmReadPackageFile(ts, fdi, "readRPM", &spec->packages->header); ts = rpmtsFree(ts); if (sigs) *sigs = NULL; /* XXX HACK */ } switch (rc) { case RPMRC_OK: case RPMRC_NOKEY: case RPMRC_NOTTRUSTED: break; case RPMRC_NOTFOUND: rpmlog(RPMLOG_ERR, _("readRPM: %s is not an RPM package\n"), (fileName ? fileName : "<stdin>")); return RPMRC_FAIL; case RPMRC_FAIL: default: rpmlog(RPMLOG_ERR, _("readRPM: reading header from %s\n"), (fileName ? fileName : "<stdin>")); return RPMRC_FAIL; break; } if (specp) *specp = spec; else spec = freeSpec(spec); if (csa != NULL) csa->cpioFdIn = fdi; else (void) Fclose(fdi); return RPMRC_OK; }
static void specFini(void * _spec) /*@modifies _spec @*/ { Spec spec = _spec; struct ReadLevelEntry *rl; if (spec == NULL) return; /* XXX assert? */ spec->lbuf = _free(spec->lbuf); spec->sl = freeSl(spec->sl); spec->st = freeSt(spec->st); spec->prep = rpmiobFree(spec->prep); spec->build = rpmiobFree(spec->build); spec->install = rpmiobFree(spec->install); spec->check = rpmiobFree(spec->check); spec->clean = rpmiobFree(spec->clean); spec->foo = tagStoreFree(spec->foo, spec->nfoo); spec->nfoo = 0; spec->buildSubdir = _free(spec->buildSubdir); spec->rootURL = _free(spec->rootURL); spec->specFile = _free(spec->specFile); closeSpec(spec); while (spec->readStack) { rl = spec->readStack; /*@-dependenttrans@*/ spec->readStack = rl->next; /*@=dependenttrans@*/ rl->next = NULL; rl = _free(rl); } spec->sourceRpmName = _free(spec->sourceRpmName); spec->sourcePkgId = _free(spec->sourcePkgId); spec->sourceHeader = headerFree(spec->sourceHeader); if (spec->fi != NULL) { rpmfi fi = spec->fi; spec->fi = NULL; fi = rpmfiFree(fi); } if (!spec->recursing) { if (spec->BASpecs != NULL) while (spec->BACount--) { /*@-unqualifiedtrans@*/ spec->BASpecs[spec->BACount] = freeSpec(spec->BASpecs[spec->BACount]); /*@=unqualifiedtrans@*/ } /*@-compdef@*/ spec->BASpecs = _free(spec->BASpecs); /*@=compdef@*/ } spec->BANames = _free(spec->BANames); spec->passPhrase = _free(spec->passPhrase); spec->cookie = _free(spec->cookie); #ifdef WITH_LUA { rpmlua lua = NULL; /* global state */ rpmluaDelVar(lua, "patches"); rpmluaDelVar(lua, "sources"); } #endif spec->sources = freeSources(spec->sources); spec->dig = pgpDigFree(spec->dig); spec->packages = freePackages(spec->packages); }