2 * Parse spec file and build package.
9 #include <rpm/rpmcli.h>
10 #include <rpm/rpmtag.h>
11 #include <rpm/rpmlib.h> /* rpmrc, MACHTABLE .. */
12 #include <rpm/rpmbuild.h>
14 #include <rpm/rpmps.h>
15 #include <rpm/rpmte.h>
16 #include <rpm/rpmts.h>
17 #include <rpm/rpmfileutil.h>
18 #include <rpm/rpmlog.h>
26 static int checkSpec(rpmts ts, Header h)
31 if (!headerIsEntry(h, RPMTAG_REQUIRENAME)
32 && !headerIsEntry(h, RPMTAG_CONFLICTNAME))
35 rc = rpmtsAddInstallElement(ts, h, NULL, 0, NULL);
39 ps = rpmtsProblems(ts);
40 if (rc == 0 && rpmpsNumProblems(ps) > 0) {
41 rpmlog(RPMLOG_ERR, _("Failed build dependencies:\n"));
47 /* XXX nuke the added package. */
55 static int isSpecFile(const char * specfile)
63 f = fopen(specfile, "r");
64 if (f == NULL || ferror(f)) {
65 rpmlog(RPMLOG_ERR, _("Unable to open spec file %s: %s\n"),
66 specfile, strerror(errno));
69 count = fread(buf, sizeof(buf[0]), sizeof(buf), f);
76 for (s = buf; count--; s++) {
87 if (checking && !(isprint(*s) || isspace(*s))) return 0;
90 if (checking && !(isprint(*s) || isspace(*s)) && *(unsigned char *)s < 32) return 0;
99 * Try to find a spec from a tarball pointed to by arg.
100 * Return absolute path to spec name on success, otherwise NULL.
102 static char * getTarSpec(const char *arg)
104 char *specFile = NULL;
110 int gotspec = 0, res;
111 static const char *tryspec[] = { "Specfile", "\\*.spec", NULL };
113 specDir = rpmGetPath("%{_specdir}", NULL);
114 tmpSpecFile = rpmGetPath("%{_specdir}/", "rpm-spec.XXXXXX", NULL);
116 (void) close(mkstemp(tmpSpecFile));
118 for (try = tryspec; *try != NULL; try++) {
122 cmd = rpmExpand("%{uncompress: ", arg, "} | ",
123 "%{__tar} xOvf - --wildcards ", *try,
124 " 2>&1 > ", tmpSpecFile, NULL);
126 if (!(fp = popen(cmd, "r"))) {
127 rpmlog(RPMLOG_ERR, _("Failed to open tar pipe: %m\n"));
129 char *fok = fgets(tarbuf, sizeof(tarbuf) - 1, fp);
131 gotspec = (fok != NULL) && isSpecFile(tmpSpecFile);
140 rpmlog(RPMLOG_ERR, _("Failed to read spec file from %s\n"), arg);
144 specBase = basename(tarbuf);
145 /* remove trailing \n */
146 specBase[strlen(specBase)-1] = '\0';
148 rasprintf(&specFile, "%s/%s", specDir, specBase);
149 res = rename(tmpSpecFile, specFile);
152 rpmlog(RPMLOG_ERR, _("Failed to rename %s to %s: %m\n"),
153 tmpSpecFile, specFile);
157 /* mkstemp() can give unnecessarily strict permissions, fixup */
159 umask(mask = umask(0));
160 (void) chmod(specFile, 0666 & ~mask);
164 (void) unlink(tmpSpecFile);
172 static int buildForTarget(rpmts ts, const char * arg, BTA_t ba)
174 const char * passPhrase = ba->passPhrase;
175 const char * cookie = ba->cookie;
176 int buildAmount = ba->buildAmount;
177 char * buildRootURL = NULL;
178 char * specFile = NULL;
180 int rc = 1; /* assume failure */
183 rpmSetTables(RPM_MACHTABLE_BUILDARCH, RPM_MACHTABLE_BUILDOS);
186 if (ba->buildRootOverride)
187 buildRootURL = rpmGenPath(NULL, ba->buildRootOverride, NULL);
189 /* Create build tree if necessary */
190 const char * buildtree = "%{_topdir}:%{_specdir}:%{_sourcedir}:%{_builddir}:%{_rpmdir}:%{_srcrpmdir}:%{_buildrootdir}";
191 const char * rootdir = rpmtsRootDir(ts);
192 if (rpmMkdirs(!rstreq(rootdir, "/") ? rootdir : NULL , buildtree)) {
196 if (ba->buildMode == 't') {
197 char *srcdir = NULL, *dir;
199 specFile = getTarSpec(arg);
203 /* Make the directory of the tarball %_sourcedir for this run */
204 /* dirname() may modify contents so extra hoops needed. */
207 rstrscat(&dir, "/", arg, NULL);
211 srcdir = dirname(dir);
212 addMacro(NULL, "_sourcedir", NULL, srcdir, RMIL_TARBALL);
215 specFile = xstrdup(arg);
218 if (*specFile != '/') {
219 char *cwd = rpmGetCwd();
221 rasprintf(&s, "%s/%s", cwd, arg);
228 if (stat(specFile, &st) < 0) {
229 rpmlog(RPMLOG_ERR, _("failed to stat %s: %m\n"), specFile);
232 if (! S_ISREG(st.st_mode)) {
233 rpmlog(RPMLOG_ERR, _("File %s is not a regular file.\n"), specFile);
237 /* Try to verify that the file is actually a specfile */
238 if (!isSpecFile(specFile)) {
240 _("File %s does not appear to be a specfile.\n"), specFile);
244 /* Don't parse spec if only its removal is requested */
245 if (ba->buildAmount == RPMBUILD_RMSPEC) {
246 rc = unlink(specFile);
250 /* Parse the spec file */
251 #define _anyarch(_f) \
252 (((_f)&(RPMBUILD_PREP|RPMBUILD_BUILD|RPMBUILD_INSTALL|RPMBUILD_PACKAGEBINARY)) == 0)
253 if (parseSpec(ts, specFile, ba->rootdir, buildRootURL, 0, passPhrase,
254 cookie, _anyarch(buildAmount), ba->force))
259 if ((spec = rpmtsSetSpec(ts, NULL)) == NULL) {
263 if ( ba->buildAmount&RPMBUILD_RMSOURCE && !(ba->buildAmount&~(RPMBUILD_RMSOURCE|RPMBUILD_RMSPEC)) ) {
264 rc = doRmSource(spec);
265 if ( rc == RPMRC_OK && ba->buildAmount&RPMBUILD_RMSPEC )
266 rc = unlink(specFile);
270 /* Assemble source header from parsed components */
271 initSourceHeader(spec);
273 /* Check build prerequisites */
274 if (!ba->noDeps && checkSpec(ts, spec->sourceHeader)) {
278 if (buildSpec(ts, spec, buildAmount, ba->noBuild)) {
282 if (ba->buildMode == 't')
283 (void) unlink(specFile);
293 int build(rpmts ts, const char * arg, BTA_t ba, const char * rcfile)
297 char * targets = ba->targets;
298 #define buildCleanMask (RPMBUILD_RMSOURCE|RPMBUILD_RMSPEC)
299 int cleanFlags = ba->buildAmount & buildCleanMask;
300 rpmVSFlags vsflags, ovsflags;
302 vsflags = rpmExpandNumeric("%{_vsflags_build}");
303 if (ba->qva_flags & VERIFY_DIGEST)
304 vsflags |= _RPMVSF_NODIGESTS;
305 if (ba->qva_flags & VERIFY_SIGNATURE)
306 vsflags |= _RPMVSF_NOSIGNATURES;
307 if (ba->qva_flags & VERIFY_HDRCHK)
308 vsflags |= RPMVSF_NOHDRCHK;
309 ovsflags = rpmtsSetVSFlags(ts, vsflags);
311 if (targets == NULL) {
312 rc = buildForTarget(ts, arg, ba);
316 /* parse up the build operators */
318 printf(_("Building target platforms: %s\n"), targets);
320 ba->buildAmount &= ~buildCleanMask;
321 for (t = targets; *t != '\0'; t = te) {
323 if ((te = strchr(t, ',')) == NULL)
325 target = xmalloc(te-t+1);
326 strncpy(target, t, (te-t));
330 else /* XXX Perform clean-up after last target build. */
331 ba->buildAmount |= cleanFlags;
333 printf(_("Building for target %s\n"), target);
335 /* Read in configuration for target. */
338 (void) rpmReadConfigFiles(rcfile, target);
340 rc = buildForTarget(ts, arg, ba);
346 vsflags = rpmtsSetVSFlags(ts, ovsflags);
347 /* Restore original configuration. */
350 (void) rpmReadConfigFiles(rcfile, NULL);