/** * 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; }
static rpmSpec parseSpec(const char *specFile, rpmSpecFlags flags, const char *buildRoot, int recursing) { int parsePart = PART_PREAMBLE; int initialPackage = 1; rpmSpec spec; /* Set up a new Spec structure with no packages. */ spec = newSpec(); spec->specFile = rpmGetPath(specFile, NULL); pushOFI(spec, 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); addMacro(NULL, "_licensedir", NULL, "%{_defaultlicensedir}", RMIL_SPEC); spec->recursing = recursing; spec->flags = flags; /* 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) { 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: case PART_FILETRIGGERIN: case PART_FILETRIGGERUN: case PART_FILETRIGGERPOSTUN: case PART_TRANSFILETRIGGERIN: case PART_TRANSFILETRIGGERUN: case PART_TRANSFILETRIGGERPOSTUN: parsePart = parseScript(spec, parsePart); break; case PART_FILES: parsePart = parseFiles(spec); break; case PART_POLICIES: parsePart = parsePolicies(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] = parseSpec(specFile, flags, buildRoot, 1); if (spec->BASpecs[index] == 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); rpmSpecFree(spec); spec = nspec; } goto exit; } } 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 */ for (Package 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; } } /* Add arch, os and platform, self-provides etc for each package */ addTargets(spec->packages); /* Check for encoding in each package unless disabled */ if (!(spec->flags & RPMSPEC_NOUTF8)) { int badenc = 0; for (Package pkg = spec->packages; pkg != NULL; pkg = pkg->next) { if (checkForEncoding(pkg->header, 0) != RPMRC_OK) { badenc = 1; } } if (badenc) goto errxit; } closeSpec(spec); exit: /* Assemble source header from parsed components */ initSourceHeader(spec); return spec; errxit: rpmSpecFree(spec); return NULL; }
/*@-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; }