2 const char *__progname;
10 #include <rpm/rpmcli.h>
11 #include <rpm/rpmlib.h> /* RPMSIGTAG, rpmReadPackageFile .. */
12 #include <rpm/rpmbuild.h>
13 #include <rpm/rpmlog.h>
14 #include <rpm/rpmfileutil.h>
15 #include <rpm/rpmdb.h>
16 #include <rpm/rpmps.h>
17 #include <rpm/rpmts.h>
18 #include "lib/signature.h"
24 MODE_BUILD = (1 << 4),
25 MODE_REBUILD = (1 << 5),
26 MODE_RECOMPILE = (1 << 8),
27 MODE_TARBUILD = (1 << 11),
32 /* the structure describing the options we take and the defaults */
33 static struct poptOption optionsTable[] = {
35 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmBuildPoptTable, 0,
36 N_("Build options with [ <specfile> | <tarball> | <source package> ]:"),
39 { "quiet", '\0', POPT_ARGFLAG_DOC_HIDDEN, &quiet, 0, NULL, NULL},
41 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmcliAllPoptTable, 0,
42 N_("Common options for all rpm modes and executables:"),
50 static int checkSpec(rpmts ts, Header h)
55 if (!headerIsEntry(h, RPMTAG_REQUIRENAME)
56 && !headerIsEntry(h, RPMTAG_CONFLICTNAME))
59 rc = rpmtsAddInstallElement(ts, h, NULL, 0, NULL);
63 ps = rpmtsProblems(ts);
64 if (rc == 0 && rpmpsNumProblems(ps) > 0) {
65 rpmlog(RPMLOG_ERR, _("Failed build dependencies:\n"));
71 /* XXX nuke the added package. */
77 static int isSpecFile(const char * specfile)
85 f = fopen(specfile, "r");
86 if (f == NULL || ferror(f)) {
87 rpmlog(RPMLOG_ERR, _("Unable to open spec file %s: %s\n"),
88 specfile, strerror(errno));
91 count = fread(buf, sizeof(buf[0]), sizeof(buf), f);
98 for (s = buf; count--; s++) {
109 if (checking && !(isprint(*s) || isspace(*s))) return 0;
112 if (checking && !(isprint(*s) || isspace(*s)) && *(unsigned char *)s < 32) return 0;
121 * Try to find a spec from a tarball pointed to by arg.
122 * Return absolute path to spec name on success, otherwise NULL.
124 static char * getTarSpec(const char *arg)
126 char *specFile = NULL;
132 int gotspec = 0, res;
133 static const char *tryspec[] = { "Specfile", "\\*.spec", NULL };
135 specDir = rpmGetPath("%{_specdir}", NULL);
136 tmpSpecFile = rpmGetPath("%{_specdir}/", "rpm-spec.XXXXXX", NULL);
138 (void) close(mkstemp(tmpSpecFile));
140 for (try = tryspec; *try != NULL; try++) {
144 cmd = rpmExpand("%{uncompress: ", arg, "} | ",
145 "%{__tar} xOvf - --wildcards ", *try,
146 " 2>&1 > ", tmpSpecFile, NULL);
148 if (!(fp = popen(cmd, "r"))) {
149 rpmlog(RPMLOG_ERR, _("Failed to open tar pipe: %m\n"));
153 fok = fgets(tarbuf, sizeof(tarbuf) - 1, fp);
154 /* tar sometimes prints "tar: Record size = 16" messages */
155 if (!fok || strncmp(fok, "tar: ", 5) != 0)
159 gotspec = (fok != NULL) && isSpecFile(tmpSpecFile);
168 rpmlog(RPMLOG_ERR, _("Failed to read spec file from %s\n"), arg);
172 specBase = basename(tarbuf);
173 /* remove trailing \n */
174 specBase[strlen(specBase)-1] = '\0';
176 rasprintf(&specFile, "%s/%s", specDir, specBase);
177 res = rename(tmpSpecFile, specFile);
180 rpmlog(RPMLOG_ERR, _("Failed to rename %s to %s: %m\n"),
181 tmpSpecFile, specFile);
185 /* mkstemp() can give unnecessarily strict permissions, fixup */
187 umask(mask = umask(0));
188 (void) chmod(specFile, 0666 & ~mask);
192 (void) unlink(tmpSpecFile);
198 static int buildForTarget(rpmts ts, const char * arg, BTA_t ba)
200 const char * passPhrase = ba->passPhrase;
201 const char * cookie = ba->cookie;
202 int buildAmount = ba->buildAmount;
203 char * buildRootURL = NULL;
204 char * specFile = NULL;
206 int rc = 1; /* assume failure */
209 rpmSetTables(RPM_MACHTABLE_BUILDARCH, RPM_MACHTABLE_BUILDOS);
212 if (ba->buildRootOverride)
213 buildRootURL = rpmGenPath(NULL, ba->buildRootOverride, NULL);
215 /* Create build tree if necessary */
216 const char * buildtree = "%{_topdir}:%{_specdir}:%{_sourcedir}:%{_builddir}:%{_rpmdir}:%{_srcrpmdir}:%{_buildrootdir}";
217 const char * rootdir = rpmtsRootDir(ts);
218 if (rpmMkdirs(!rstreq(rootdir, "/") ? rootdir : NULL , buildtree)) {
222 if (ba->buildMode == 't') {
223 char *srcdir = NULL, *dir;
225 specFile = getTarSpec(arg);
229 /* Make the directory of the tarball %_sourcedir for this run */
230 /* dirname() may modify contents so extra hoops needed. */
233 rstrscat(&dir, "/", arg, NULL);
237 srcdir = dirname(dir);
238 addMacro(NULL, "_sourcedir", NULL, srcdir, RMIL_TARBALL);
241 specFile = xstrdup(arg);
244 if (*specFile != '/') {
245 char *cwd = rpmGetCwd();
247 rasprintf(&s, "%s/%s", cwd, arg);
254 if (stat(specFile, &st) < 0) {
255 rpmlog(RPMLOG_ERR, _("failed to stat %s: %m\n"), specFile);
258 if (! S_ISREG(st.st_mode)) {
259 rpmlog(RPMLOG_ERR, _("File %s is not a regular file.\n"), specFile);
263 /* Try to verify that the file is actually a specfile */
264 if (!isSpecFile(specFile)) {
266 _("File %s does not appear to be a specfile.\n"), specFile);
270 /* Don't parse spec if only its removal is requested */
271 if (ba->buildAmount == RPMBUILD_RMSPEC) {
272 rc = unlink(specFile);
276 /* Parse the spec file */
277 #define _anyarch(_f) \
278 (((_f)&(RPMBUILD_PREP|RPMBUILD_BUILD|RPMBUILD_INSTALL|RPMBUILD_PACKAGEBINARY)) == 0)
279 if (parseSpec(ts, specFile, ba->rootdir, buildRootURL, 0, passPhrase,
280 cookie, _anyarch(buildAmount), ba->force))
285 if ((spec = rpmtsSetSpec(ts, NULL)) == NULL) {
289 if ( ba->buildAmount&RPMBUILD_RMSOURCE && !(ba->buildAmount&~(RPMBUILD_RMSOURCE|RPMBUILD_RMSPEC)) ) {
290 rc = doRmSource(spec);
291 if ( rc == RPMRC_OK && ba->buildAmount&RPMBUILD_RMSPEC )
292 rc = unlink(specFile);
296 /* Assemble source header from parsed components */
297 initSourceHeader(spec);
299 /* Check build prerequisites */
300 if (!ba->noDeps && checkSpec(ts, spec->sourceHeader)) {
304 if (buildSpec(ts, spec, buildAmount, ba->noBuild)) {
308 if (ba->buildMode == 't')
309 (void) unlink(specFile);
319 static int build(rpmts ts, const char * arg, BTA_t ba, const char * rcfile)
323 char * targets = ba->targets;
324 #define buildCleanMask (RPMBUILD_RMSOURCE|RPMBUILD_RMSPEC)
325 int cleanFlags = ba->buildAmount & buildCleanMask;
326 rpmVSFlags vsflags, ovsflags;
328 vsflags = rpmExpandNumeric("%{_vsflags_build}");
329 if (ba->qva_flags & VERIFY_DIGEST)
330 vsflags |= _RPMVSF_NODIGESTS;
331 if (ba->qva_flags & VERIFY_SIGNATURE)
332 vsflags |= _RPMVSF_NOSIGNATURES;
333 if (ba->qva_flags & VERIFY_HDRCHK)
334 vsflags |= RPMVSF_NOHDRCHK;
335 ovsflags = rpmtsSetVSFlags(ts, vsflags);
337 if (targets == NULL) {
338 rc = buildForTarget(ts, arg, ba);
342 /* parse up the build operators */
344 printf(_("Building target platforms: %s\n"), targets);
346 ba->buildAmount &= ~buildCleanMask;
347 for (t = targets; *t != '\0'; t = te) {
349 if ((te = strchr(t, ',')) == NULL)
351 target = xmalloc(te-t+1);
352 strncpy(target, t, (te-t));
356 else /* XXX Perform clean-up after last target build. */
357 ba->buildAmount |= cleanFlags;
359 printf(_("Building for target %s\n"), target);
361 /* Read in configuration for target. */
364 (void) rpmReadConfigFiles(rcfile, target);
366 rc = buildForTarget(ts, arg, ba);
372 vsflags = rpmtsSetVSFlags(ts, ovsflags);
373 /* Restore original configuration. */
376 (void) rpmReadConfigFiles(rcfile, NULL);
381 int main(int argc, char *argv[])
384 enum modes bigMode = MODE_BUILD;
385 BTA_t ba = &rpmBTArgs;
386 char * passPhrase = "";
388 const char *pkg = NULL;
390 poptContext optCon = rpmcliInit(argc, argv, optionsTable);
392 if (argc <= 1 || poptPeekArg(optCon) == NULL) {
393 printUsage(optCon, stderr, 0);
397 switch (ba->buildMode) {
398 case 'b': bigMode = MODE_BUILD; break;
399 case 't': bigMode = MODE_TARBUILD; break;
400 case 'B': bigMode = MODE_REBUILD; break;
401 case 'C': bigMode = MODE_RECOMPILE; break;
404 if (rpmcliRootDir && rpmcliRootDir[0] != '/') {
405 argerror(_("arguments to --root (-r) must begin with a /"));
409 int sigTag = rpmLookupSignatureType(RPMLOOKUPSIG_QUERY);
417 passPhrase = rpmGetPassPhrase(_("Enter pass phrase: "), sigTag);
418 if (passPhrase == NULL) {
419 fprintf(stderr, _("Pass phrase check failed\n"));
423 fprintf(stderr, _("Pass phrase is good.\n"));
424 passPhrase = xstrdup(passPhrase);
427 fprintf(stderr, _("Invalid %%_signature spec in macro file.\n"));
433 /* Make rpmLookupSignatureType() return 0 ("none") from now on */
434 (void) rpmLookupSignatureType(RPMLOOKUPSIG_DISABLE);
437 /* rpmbuild is rather chatty by default */
438 rpmSetVerbosity(quiet ? RPMLOG_WARNING : RPMLOG_INFO);
440 if (rpmcliPipeOutput && initPipe())
444 (void) rpmtsSetRootDir(ts, rpmcliRootDir);
449 RPMBUILD_PREP | RPMBUILD_BUILD | RPMBUILD_INSTALL | RPMBUILD_CHECK;
450 if (bigMode == MODE_REBUILD) {
451 ba->buildAmount |= RPMBUILD_PACKAGEBINARY;
452 ba->buildAmount |= RPMBUILD_RMSOURCE;
453 ba->buildAmount |= RPMBUILD_RMSPEC;
454 ba->buildAmount |= RPMBUILD_CLEAN;
455 ba->buildAmount |= RPMBUILD_RMBUILD;
458 while ((pkg = poptGetArg(optCon))) {
459 char * specFile = NULL;
462 ec = rpmInstallSource(ts, pkg, &specFile, &ba->cookie);
464 ba->rootdir = rpmcliRootDir;
465 ba->passPhrase = passPhrase;
466 ec = build(ts, specFile, ba, rpmcliRcfile);
468 ba->cookie = _free(ba->cookie);
469 specFile = _free(specFile);
477 switch (ba->buildChar) {
479 ba->buildAmount |= RPMBUILD_PACKAGESOURCE;
481 ba->buildAmount |= RPMBUILD_PACKAGEBINARY;
482 ba->buildAmount |= RPMBUILD_CLEAN;
483 if ((ba->buildChar == 'b') && ba->shortCircuit)
486 ba->buildAmount |= RPMBUILD_INSTALL;
487 ba->buildAmount |= RPMBUILD_CHECK;
488 if ((ba->buildChar == 'i') && ba->shortCircuit)
491 ba->buildAmount |= RPMBUILD_BUILD;
492 if ((ba->buildChar == 'c') && ba->shortCircuit)
495 ba->buildAmount |= RPMBUILD_PREP;
499 ba->buildAmount |= RPMBUILD_FILECHECK;
502 ba->buildAmount |= RPMBUILD_PACKAGESOURCE;
506 while ((pkg = poptGetArg(optCon))) {
507 ba->rootdir = rpmcliRootDir;
508 ba->passPhrase = passPhrase;
510 ec = build(ts, pkg, ba, rpmcliRcfile);
514 (void) rpmReadConfigFiles(rpmcliRcfile, NULL);
524 ba->buildRootOverride = _free(ba->buildRootOverride);
525 ba->targets = _free(ba->targets);