2 const char *__progname;
14 #include <rpm/rpmcli.h>
15 #include <rpm/rpmlib.h> /* RPMSIGTAG, rpmReadPackageFile .. */
16 #include <rpm/rpmbuild.h>
17 #include <rpm/rpmlog.h>
18 #include <rpm/rpmfileutil.h>
19 #include <rpm/rpmdb.h>
20 #include <rpm/rpmps.h>
21 #include <rpm/rpmts.h>
22 #include "lib/signature.h"
28 MODE_BUILD = (1 << 4),
29 MODE_REBUILD = (1 << 5),
30 MODE_RECOMPILE = (1 << 8),
31 MODE_TARBUILD = (1 << 11),
36 /* the structure describing the options we take and the defaults */
37 static struct poptOption optionsTable[] = {
39 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmBuildPoptTable, 0,
40 N_("Build options with [ <specfile> | <tarball> | <source package> ]:"),
43 { "quiet", '\0', 0, &quiet, 0, NULL, NULL},
45 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmcliAllPoptTable, 0,
46 N_("Common options for all rpm modes and executables:"),
54 static int checkSpec(rpmts ts, Header h)
59 if (!headerIsEntry(h, RPMTAG_REQUIRENAME)
60 && !headerIsEntry(h, RPMTAG_CONFLICTNAME))
63 rc = rpmtsAddInstallElement(ts, h, NULL, 0, NULL);
67 ps = rpmtsProblems(ts);
68 if (rc == 0 && rpmpsNumProblems(ps) > 0) {
69 rpmlog(RPMLOG_ERR, _("Failed build dependencies:\n"));
75 /* XXX nuke the added package. */
81 static int isSpecFile(const char * specfile)
89 f = fopen(specfile, "r");
90 if (f == NULL || ferror(f)) {
91 rpmlog(RPMLOG_ERR, _("Unable to open spec file %s: %s\n"),
92 specfile, strerror(errno));
95 count = fread(buf, sizeof(buf[0]), sizeof(buf), f);
102 for (s = buf; count--; s++) {
113 if (checking && !(isprint(*s) || isspace(*s))) return 0;
116 if (checking && !(isprint(*s) || isspace(*s)) && *(unsigned char *)s < 32) return 0;
125 * Try to find a spec from a tarball pointed to by arg.
126 * Return absolute path to spec name on success, otherwise NULL.
128 static char * getTarSpec(const char *arg)
130 char *specFile = NULL;
136 int gotspec = 0, res;
137 static const char *tryspec[] = { "Specfile", "\\*.spec", NULL };
139 specDir = rpmGetPath("%{_specdir}", NULL);
140 tmpSpecFile = rpmGetPath("%{_specdir}/", "rpm-spec.XXXXXX", NULL);
142 (void) close(mkstemp(tmpSpecFile));
144 for (try = tryspec; *try != NULL; try++) {
148 cmd = rpmExpand("%{uncompress: ", arg, "} | ",
149 "%{__tar} xOvf - --wildcards ", *try,
150 " 2>&1 > ", tmpSpecFile, NULL);
152 if (!(fp = popen(cmd, "r"))) {
153 rpmlog(RPMLOG_ERR, _("Failed to open tar pipe: %m\n"));
157 fok = fgets(tarbuf, sizeof(tarbuf) - 1, fp);
158 /* tar sometimes prints "tar: Record size = 16" messages */
159 if (!fok || strncmp(fok, "tar: ", 5) != 0)
163 gotspec = (fok != NULL) && isSpecFile(tmpSpecFile);
172 rpmlog(RPMLOG_ERR, _("Failed to read spec file from %s\n"), arg);
176 specBase = basename(tarbuf);
177 /* remove trailing \n */
178 specBase[strlen(specBase)-1] = '\0';
180 rasprintf(&specFile, "%s/%s", specDir, specBase);
181 res = rename(tmpSpecFile, specFile);
184 rpmlog(RPMLOG_ERR, _("Failed to rename %s to %s: %m\n"),
185 tmpSpecFile, specFile);
189 /* mkstemp() can give unnecessarily strict permissions, fixup */
191 umask(mask = umask(0));
192 (void) chmod(specFile, 0666 & ~mask);
196 (void) unlink(tmpSpecFile);
202 static int buildForTarget(rpmts ts, const char * arg, BTA_t ba)
204 const char * passPhrase = ba->passPhrase;
205 const char * cookie = ba->cookie;
206 int buildAmount = ba->buildAmount;
207 char * buildRootURL = NULL;
208 char * specFile = NULL;
210 int rc = 1; /* assume failure */
213 rpmSetTables(RPM_MACHTABLE_BUILDARCH, RPM_MACHTABLE_BUILDOS);
216 if (ba->buildRootOverride)
217 buildRootURL = rpmGenPath(NULL, ba->buildRootOverride, NULL);
219 /* Create build tree if necessary */
220 const char * buildtree = "%{_topdir}:%{_specdir}:%{_sourcedir}:%{_builddir}:%{_rpmdir}:%{_srcrpmdir}:%{_buildrootdir}";
221 const char * rootdir = rpmtsRootDir(ts);
222 if (rpmMkdirs(!rstreq(rootdir, "/") ? rootdir : NULL , buildtree)) {
226 if (ba->buildMode == 't') {
227 char *srcdir = NULL, *dir;
229 specFile = getTarSpec(arg);
233 /* Make the directory of the tarball %_sourcedir for this run */
234 /* dirname() may modify contents so extra hoops needed. */
237 rstrscat(&dir, "/", arg, NULL);
241 srcdir = dirname(dir);
242 addMacro(NULL, "_sourcedir", NULL, srcdir, RMIL_TARBALL);
245 specFile = xstrdup(arg);
248 if (*specFile != '/') {
249 char *cwd = rpmGetCwd();
251 rasprintf(&s, "%s/%s", cwd, arg);
258 if (stat(specFile, &st) < 0) {
259 rpmlog(RPMLOG_ERR, _("failed to stat %s: %m\n"), specFile);
262 if (! S_ISREG(st.st_mode)) {
263 rpmlog(RPMLOG_ERR, _("File %s is not a regular file.\n"), specFile);
267 /* Try to verify that the file is actually a specfile */
268 if (!isSpecFile(specFile)) {
270 _("File %s does not appear to be a specfile.\n"), specFile);
274 /* Don't parse spec if only its removal is requested */
275 if (ba->buildAmount == RPMBUILD_RMSPEC) {
276 rc = unlink(specFile);
280 /* Parse the spec file */
281 #define _anyarch(_f) \
282 (((_f)&(RPMBUILD_PREP|RPMBUILD_BUILD|RPMBUILD_INSTALL|RPMBUILD_PACKAGEBINARY)) == 0)
283 if (parseSpec(ts, specFile, ba->rootdir, buildRootURL, 0, passPhrase,
284 cookie, _anyarch(buildAmount), ba->force))
289 if ((spec = rpmtsSetSpec(ts, NULL)) == NULL) {
293 if ( ba->buildAmount&RPMBUILD_RMSOURCE && !(ba->buildAmount&~(RPMBUILD_RMSOURCE|RPMBUILD_RMSPEC)) ) {
294 rc = doRmSource(spec);
295 if ( rc == RPMRC_OK && ba->buildAmount&RPMBUILD_RMSPEC )
296 rc = unlink(specFile);
300 /* Assemble source header from parsed components */
301 initSourceHeader(spec);
303 /* Check build prerequisites */
304 if (!ba->noDeps && checkSpec(ts, spec->sourceHeader)) {
308 if (buildSpec(ts, spec, buildAmount, ba->noBuild)) {
312 if (ba->buildMode == 't')
313 (void) unlink(specFile);
323 static int build(rpmts ts, const char * arg, BTA_t ba, const char * rcfile)
327 char * targets = ba->targets;
328 #define buildCleanMask (RPMBUILD_RMSOURCE|RPMBUILD_RMSPEC)
329 int cleanFlags = ba->buildAmount & buildCleanMask;
330 rpmVSFlags vsflags, ovsflags;
332 vsflags = rpmExpandNumeric("%{_vsflags_build}");
333 if (ba->qva_flags & VERIFY_DIGEST)
334 vsflags |= _RPMVSF_NODIGESTS;
335 if (ba->qva_flags & VERIFY_SIGNATURE)
336 vsflags |= _RPMVSF_NOSIGNATURES;
337 if (ba->qva_flags & VERIFY_HDRCHK)
338 vsflags |= RPMVSF_NOHDRCHK;
339 ovsflags = rpmtsSetVSFlags(ts, vsflags);
341 if (targets == NULL) {
342 rc = buildForTarget(ts, arg, ba);
346 /* parse up the build operators */
348 printf(_("Building target platforms: %s\n"), targets);
350 ba->buildAmount &= ~buildCleanMask;
351 for (t = targets; *t != '\0'; t = te) {
353 if ((te = strchr(t, ',')) == NULL)
355 target = xmalloc(te-t+1);
356 strncpy(target, t, (te-t));
360 else /* XXX Perform clean-up after last target build. */
361 ba->buildAmount |= cleanFlags;
363 printf(_("Building for target %s\n"), target);
365 /* Read in configuration for target. */
368 (void) rpmReadConfigFiles(rcfile, target);
370 rc = buildForTarget(ts, arg, ba);
376 vsflags = rpmtsSetVSFlags(ts, ovsflags);
377 /* Restore original configuration. */
380 (void) rpmReadConfigFiles(rcfile, NULL);
385 int main(int argc, char *argv[])
388 enum modes bigMode = MODE_BUILD;
389 BTA_t ba = &rpmBTArgs;
390 char * passPhrase = "";
394 const char *poptCtx = "rpmbuild";
395 const char *pkg = NULL;
402 #if HAVE_MCHECK_H && HAVE_MTRACE
403 mtrace(); /* Trace malloc only if MALLOC_TRACE=mtrace-output-file. */
405 setprogname(argv[0]); /* Retrofit glibc __progname */
407 /* XXX glibc churn sanity */
408 if (__progname == NULL) {
409 if ((__progname = strrchr(argv[0], '/')) != NULL) __progname++;
410 else __progname = argv[0];
413 #if defined(ENABLE_NLS)
414 /* set up the correct locale */
415 (void) setlocale(LC_ALL, "" );
417 bindtextdomain(PACKAGE, LOCALEDIR);
421 rpmSetVerbosity(RPMLOG_NOTICE); /* XXX silly use by showrc */
423 /* Make a first pass through the arguments, looking for --rcfile */
424 /* We need to handle that before dealing with the rest of the arguments. */
425 /* XXX popt argv definition should be fixed instead of casting... */
426 optCon = poptGetContext(poptCtx, argc, (const char **)argv, optionsTable, 0);
428 char *poptfile = rpmGenPath(rpmConfigDir(), LIBRPMALIAS_FILENAME, NULL);
429 (void) poptReadConfigFile(optCon, poptfile);
432 (void) poptReadDefaultConfig(optCon, 1);
433 poptSetExecPath(optCon, rpmConfigDir(), 1);
435 while ((arg = poptGetNextOpt(optCon)) > 0) {
436 optArg = poptGetOptArg(optCon);
440 fprintf(stderr, _("Internal error in argument processing (%d) :-(\n"), arg);
446 fprintf(stderr, "%s: %s\n",
447 poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
452 if (argc <= 1 || poptPeekArg(optCon) == NULL) {
453 printUsage(optCon, stderr, 0);
459 switch (ba->buildMode) {
460 case 'b': bigMode = MODE_BUILD; break;
461 case 't': bigMode = MODE_TARBUILD; break;
462 case 'B': bigMode = MODE_REBUILD; break;
463 case 'C': bigMode = MODE_RECOMPILE; break;
466 if (rpmcliRootDir && rpmcliRootDir[0] != '/') {
467 argerror(_("arguments to --root (-r) must begin with a /"));
471 int sigTag = rpmLookupSignatureType(RPMLOOKUPSIG_QUERY);
479 passPhrase = rpmGetPassPhrase(_("Enter pass phrase: "), sigTag);
480 if (passPhrase == NULL) {
481 fprintf(stderr, _("Pass phrase check failed\n"));
485 fprintf(stderr, _("Pass phrase is good.\n"));
486 passPhrase = xstrdup(passPhrase);
489 fprintf(stderr, _("Invalid %%_signature spec in macro file.\n"));
495 /* Make rpmLookupSignatureType() return 0 ("none") from now on */
496 (void) rpmLookupSignatureType(RPMLOOKUPSIG_DISABLE);
499 /* rpmbuild is rather chatty by default */
500 rpmSetVerbosity(quiet ? RPMLOG_WARNING : RPMLOG_INFO);
502 if (rpmcliPipeOutput) {
504 fprintf(stderr, _("creating a pipe for --pipe failed: %m\n"));
508 if (!(pipeChild = fork())) {
509 (void) signal(SIGPIPE, SIG_DFL);
511 (void) dup2(p[0], STDIN_FILENO);
513 (void) execl("/bin/sh", "/bin/sh", "-c", rpmcliPipeOutput, NULL);
514 fprintf(stderr, _("exec failed\n"));
518 (void) dup2(p[1], STDOUT_FILENO);
523 (void) rpmtsSetRootDir(ts, rpmcliRootDir);
528 RPMBUILD_PREP | RPMBUILD_BUILD | RPMBUILD_INSTALL | RPMBUILD_CHECK;
529 if (bigMode == MODE_REBUILD) {
530 ba->buildAmount |= RPMBUILD_PACKAGEBINARY;
531 ba->buildAmount |= RPMBUILD_RMSOURCE;
532 ba->buildAmount |= RPMBUILD_RMSPEC;
533 ba->buildAmount |= RPMBUILD_CLEAN;
534 ba->buildAmount |= RPMBUILD_RMBUILD;
537 while ((pkg = poptGetArg(optCon))) {
538 char * specFile = NULL;
541 ec = rpmInstallSource(ts, pkg, &specFile, &ba->cookie);
543 ba->rootdir = rpmcliRootDir;
544 ba->passPhrase = passPhrase;
545 ec = build(ts, specFile, ba, rpmcliRcfile);
547 ba->cookie = _free(ba->cookie);
548 specFile = _free(specFile);
556 switch (ba->buildChar) {
558 ba->buildAmount |= RPMBUILD_PACKAGESOURCE;
560 ba->buildAmount |= RPMBUILD_PACKAGEBINARY;
561 ba->buildAmount |= RPMBUILD_CLEAN;
562 if ((ba->buildChar == 'b') && ba->shortCircuit)
565 ba->buildAmount |= RPMBUILD_INSTALL;
566 ba->buildAmount |= RPMBUILD_CHECK;
567 if ((ba->buildChar == 'i') && ba->shortCircuit)
570 ba->buildAmount |= RPMBUILD_BUILD;
571 if ((ba->buildChar == 'c') && ba->shortCircuit)
574 ba->buildAmount |= RPMBUILD_PREP;
578 ba->buildAmount |= RPMBUILD_FILECHECK;
581 ba->buildAmount |= RPMBUILD_PACKAGESOURCE;
585 while ((pkg = poptGetArg(optCon))) {
586 ba->rootdir = rpmcliRootDir;
587 ba->passPhrase = passPhrase;
589 ec = build(ts, pkg, ba, rpmcliRcfile);
593 (void) rpmReadConfigFiles(rpmcliRcfile, NULL);
602 optCon = poptFreeContext(optCon);
604 rpmFreeMacros(rpmCLIMacroContext);
608 (void) fclose(stdout);
609 (void) waitpid(pipeChild, &status, 0);
612 /* keeps memory leak checkers quiet */
616 ba->buildRootOverride = _free(ba->buildRootOverride);
617 ba->targets = _free(ba->targets);
619 #if HAVE_MCHECK_H && HAVE_MTRACE
620 muntrace(); /* Trace malloc only if MALLOC_TRACE=mtrace-output-file. */
623 /* XXX Avoid exit status overflow. Status 255 is special to xargs(1) */
624 if (ec > 254) ec = 254;