2 const char *__progname;
8 #include <rpm/rpmcli.h>
9 #include <rpm/rpmlib.h> /* RPMSIGTAG, rpmReadPackageFile .. */
10 #include <rpm/rpmbuild.h>
11 #include <rpm/rpmlog.h>
12 #include <rpm/rpmfileutil.h>
13 #include <rpm/rpmdb.h>
14 #include <rpm/rpmps.h>
15 #include <rpm/rpmts.h>
16 #include "lib/signature.h"
17 #include "build/rpmbuild_misc.h" /* XXX freeNames() */
23 MODE_BUILD = (1 << 4),
24 MODE_REBUILD = (1 << 5),
25 MODE_RECOMPILE = (1 << 8),
26 MODE_TARBUILD = (1 << 11),
31 /* the structure describing the options we take and the defaults */
32 static struct poptOption optionsTable[] = {
34 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmBuildPoptTable, 0,
35 N_("Build options with [ <specfile> | <tarball> | <source package> ]:"),
38 { "quiet", '\0', POPT_ARGFLAG_DOC_HIDDEN, &quiet, 0, NULL, NULL},
40 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmcliAllPoptTable, 0,
41 N_("Common options for all rpm modes and executables:"),
49 static int checkSpec(rpmts ts, Header h)
54 if (!headerIsEntry(h, RPMTAG_REQUIRENAME)
55 && !headerIsEntry(h, RPMTAG_CONFLICTNAME))
58 rc = rpmtsAddInstallElement(ts, h, NULL, 0, NULL);
62 ps = rpmtsProblems(ts);
63 if (rc == 0 && rpmpsNumProblems(ps) > 0) {
64 rpmlog(RPMLOG_ERR, _("Failed build dependencies:\n"));
70 /* XXX nuke the added package. */
76 static int isSpecFile(const char * specfile)
84 f = fopen(specfile, "r");
85 if (f == NULL || ferror(f)) {
86 rpmlog(RPMLOG_ERR, _("Unable to open spec file %s: %s\n"),
87 specfile, strerror(errno));
90 count = fread(buf, sizeof(buf[0]), sizeof(buf), f);
97 for (s = buf; count--; s++) {
108 if (checking && !(isprint(*s) || isspace(*s))) return 0;
111 if (checking && !(isprint(*s) || isspace(*s)) && *(unsigned char *)s < 32) return 0;
120 * Try to find a spec from a tarball pointed to by arg.
121 * Return absolute path to spec name on success, otherwise NULL.
123 static char * getTarSpec(const char *arg)
125 char *specFile = NULL;
131 int gotspec = 0, res;
132 static const char *tryspec[] = { "Specfile", "\\*.spec", NULL };
134 specDir = rpmGetPath("%{_specdir}", NULL);
135 tmpSpecFile = rpmGetPath("%{_specdir}/", "rpm-spec.XXXXXX", NULL);
137 (void) close(mkstemp(tmpSpecFile));
139 for (try = tryspec; *try != NULL; try++) {
143 cmd = rpmExpand("%{uncompress: ", arg, "} | ",
144 "%{__tar} xOvf - --wildcards ", *try,
145 " 2>&1 > ", tmpSpecFile, NULL);
147 if (!(fp = popen(cmd, "r"))) {
148 rpmlog(RPMLOG_ERR, _("Failed to open tar pipe: %m\n"));
152 fok = fgets(tarbuf, sizeof(tarbuf) - 1, fp);
153 /* tar sometimes prints "tar: Record size = 16" messages */
154 if (!fok || strncmp(fok, "tar: ", 5) != 0)
158 gotspec = (fok != NULL) && isSpecFile(tmpSpecFile);
167 rpmlog(RPMLOG_ERR, _("Failed to read spec file from %s\n"), arg);
171 specBase = basename(tarbuf);
172 /* remove trailing \n */
173 specBase[strlen(specBase)-1] = '\0';
175 rasprintf(&specFile, "%s/%s", specDir, specBase);
176 res = rename(tmpSpecFile, specFile);
179 rpmlog(RPMLOG_ERR, _("Failed to rename %s to %s: %m\n"),
180 tmpSpecFile, specFile);
184 /* mkstemp() can give unnecessarily strict permissions, fixup */
186 umask(mask = umask(0));
187 (void) chmod(specFile, 0666 & ~mask);
191 (void) unlink(tmpSpecFile);
197 static int buildForTarget(rpmts ts, const char * arg, BTA_t ba)
199 int buildAmount = ba->buildAmount;
200 char * buildRootURL = NULL;
201 char * specFile = NULL;
203 int rc = 1; /* assume failure */
204 int justRm = ((buildAmount & ~(RPMBUILD_RMSOURCE|RPMBUILD_RMSPEC)) == 0);
205 rpmSpecFlags specFlags = RPMSPEC_NONE;
208 rpmSetTables(RPM_MACHTABLE_BUILDARCH, RPM_MACHTABLE_BUILDOS);
211 if (ba->buildRootOverride)
212 buildRootURL = rpmGenPath(NULL, ba->buildRootOverride, NULL);
214 /* Create build tree if necessary */
215 const char * buildtree = "%{_topdir}:%{_specdir}:%{_sourcedir}:%{_builddir}:%{_rpmdir}:%{_srcrpmdir}:%{_buildrootdir}";
216 const char * rootdir = rpmtsRootDir(ts);
217 if (rpmMkdirs(!rstreq(rootdir, "/") ? rootdir : NULL , buildtree)) {
221 if (ba->buildMode == 't') {
222 char *srcdir = NULL, *dir;
224 specFile = getTarSpec(arg);
228 /* Make the directory of the tarball %_sourcedir for this run */
229 /* dirname() may modify contents so extra hoops needed. */
232 rstrscat(&dir, "/", arg, NULL);
236 srcdir = dirname(dir);
237 addMacro(NULL, "_sourcedir", NULL, srcdir, RMIL_TARBALL);
240 specFile = xstrdup(arg);
243 if (*specFile != '/') {
244 char *cwd = rpmGetCwd();
246 rasprintf(&s, "%s/%s", cwd, arg);
253 if (stat(specFile, &st) < 0) {
254 rpmlog(RPMLOG_ERR, _("failed to stat %s: %m\n"), specFile);
257 if (! S_ISREG(st.st_mode)) {
258 rpmlog(RPMLOG_ERR, _("File %s is not a regular file.\n"), specFile);
262 /* Try to verify that the file is actually a specfile */
263 if (!isSpecFile(specFile)) {
265 _("File %s does not appear to be a specfile.\n"), specFile);
269 /* Don't parse spec if only its removal is requested */
270 if (ba->buildAmount == RPMBUILD_RMSPEC) {
271 rc = unlink(specFile);
275 /* Parse the spec file */
276 #define _anyarch(_f) \
277 (((_f)&(RPMBUILD_PREP|RPMBUILD_BUILD|RPMBUILD_INSTALL|RPMBUILD_PACKAGEBINARY)) == 0)
278 if (_anyarch(buildAmount))
279 specFlags |= RPMSPEC_ANYARCH;
281 specFlags |= RPMSPEC_FORCE;
284 spec = rpmSpecParse(specFile, specFlags, buildRootURL);
289 /* Check build prerequisites if necessary, unless disabled */
290 if (!justRm && !ba->noDeps && checkSpec(ts, spec->sourceHeader)) {
294 if (rpmSpecBuild(ba, spec)) {
298 if (ba->buildMode == 't')
299 (void) unlink(specFile);
309 static int build(rpmts ts, const char * arg, BTA_t ba, const char * rcfile)
313 char * targets = ba->targets;
314 #define buildCleanMask (RPMBUILD_RMSOURCE|RPMBUILD_RMSPEC)
315 int cleanFlags = ba->buildAmount & buildCleanMask;
316 rpmVSFlags vsflags, ovsflags;
318 vsflags = rpmExpandNumeric("%{_vsflags_build}");
319 if (ba->qva_flags & VERIFY_DIGEST)
320 vsflags |= _RPMVSF_NODIGESTS;
321 if (ba->qva_flags & VERIFY_SIGNATURE)
322 vsflags |= _RPMVSF_NOSIGNATURES;
323 if (ba->qva_flags & VERIFY_HDRCHK)
324 vsflags |= RPMVSF_NOHDRCHK;
325 ovsflags = rpmtsSetVSFlags(ts, vsflags);
327 if (targets == NULL) {
328 rc = buildForTarget(ts, arg, ba);
332 /* parse up the build operators */
334 printf(_("Building target platforms: %s\n"), targets);
336 ba->buildAmount &= ~buildCleanMask;
337 for (t = targets; *t != '\0'; t = te) {
339 if ((te = strchr(t, ',')) == NULL)
341 target = xmalloc(te-t+1);
342 strncpy(target, t, (te-t));
346 else /* XXX Perform clean-up after last target build. */
347 ba->buildAmount |= cleanFlags;
349 printf(_("Building for target %s\n"), target);
351 /* Read in configuration for target. */
354 (void) rpmReadConfigFiles(rcfile, target);
356 rc = buildForTarget(ts, arg, ba);
362 vsflags = rpmtsSetVSFlags(ts, ovsflags);
363 /* Restore original configuration. */
366 (void) rpmReadConfigFiles(rcfile, NULL);
371 int main(int argc, char *argv[])
374 enum modes bigMode = MODE_BUILD;
375 BTA_t ba = &rpmBTArgs;
377 const char *pkg = NULL;
379 poptContext optCon = rpmcliInit(argc, argv, optionsTable);
381 if (argc <= 1 || poptPeekArg(optCon) == NULL) {
382 printUsage(optCon, stderr, 0);
386 switch (ba->buildMode) {
387 case 'b': bigMode = MODE_BUILD; break;
388 case 't': bigMode = MODE_TARBUILD; break;
389 case 'B': bigMode = MODE_REBUILD; break;
390 case 'C': bigMode = MODE_RECOMPILE; break;
393 if (rpmcliRootDir && rpmcliRootDir[0] != '/') {
394 argerror(_("arguments to --root (-r) must begin with a /"));
397 /* rpmbuild is rather chatty by default */
398 rpmSetVerbosity(quiet ? RPMLOG_WARNING : RPMLOG_INFO);
400 if (rpmcliPipeOutput && initPipe())
404 (void) rpmtsSetRootDir(ts, rpmcliRootDir);
409 RPMBUILD_PREP | RPMBUILD_BUILD | RPMBUILD_INSTALL | RPMBUILD_CHECK;
410 if (bigMode == MODE_REBUILD) {
411 ba->buildAmount |= RPMBUILD_PACKAGEBINARY;
412 ba->buildAmount |= RPMBUILD_RMSOURCE;
413 ba->buildAmount |= RPMBUILD_RMSPEC;
414 ba->buildAmount |= RPMBUILD_CLEAN;
415 ba->buildAmount |= RPMBUILD_RMBUILD;
418 while ((pkg = poptGetArg(optCon))) {
419 char * specFile = NULL;
422 ec = rpmInstallSource(ts, pkg, &specFile, &ba->cookie);
424 ba->rootdir = rpmcliRootDir;
425 ec = build(ts, specFile, ba, rpmcliRcfile);
427 ba->cookie = _free(ba->cookie);
428 specFile = _free(specFile);
436 switch (ba->buildChar) {
438 ba->buildAmount |= RPMBUILD_PACKAGESOURCE;
440 ba->buildAmount |= RPMBUILD_PACKAGEBINARY;
441 ba->buildAmount |= RPMBUILD_CLEAN;
442 if ((ba->buildChar == 'b') && ba->shortCircuit)
445 ba->buildAmount |= RPMBUILD_INSTALL;
446 ba->buildAmount |= RPMBUILD_CHECK;
447 if ((ba->buildChar == 'i') && ba->shortCircuit)
450 ba->buildAmount |= RPMBUILD_BUILD;
451 if ((ba->buildChar == 'c') && ba->shortCircuit)
454 ba->buildAmount |= RPMBUILD_PREP;
458 ba->buildAmount |= RPMBUILD_FILECHECK;
461 ba->buildAmount |= RPMBUILD_PACKAGESOURCE;
465 while ((pkg = poptGetArg(optCon))) {
466 ba->rootdir = rpmcliRootDir;
468 ec = build(ts, pkg, ba, rpmcliRcfile);
472 (void) rpmReadConfigFiles(rpmcliRcfile, NULL);
480 ba->buildRootOverride = _free(ba->buildRootOverride);
481 ba->targets = _free(ba->targets);