rpm 4.8.1
build.c
Go to the documentation of this file.
00001 
00005 #include "system.h"
00006 
00007 #include <libgen.h>
00008 
00009 #include <rpm/rpmcli.h>
00010 #include <rpm/rpmtag.h>
00011 #include <rpm/rpmlib.h>         /* rpmrc, MACHTABLE .. */
00012 #include <rpm/rpmbuild.h>
00013 
00014 #include <rpm/rpmps.h>
00015 #include <rpm/rpmte.h>
00016 #include <rpm/rpmts.h>
00017 #include <rpm/rpmfileutil.h>
00018 #include <rpm/rpmlog.h>
00019 #include <lib/misc.h>
00020 
00021 #include "build.h"
00022 #include "debug.h"
00023 
00026 static int checkSpec(rpmts ts, Header h)
00027 {
00028     rpmps ps;
00029     int rc;
00030 
00031     if (!headerIsEntry(h, RPMTAG_REQUIRENAME)
00032      && !headerIsEntry(h, RPMTAG_CONFLICTNAME))
00033         return 0;
00034 
00035     rc = rpmtsAddInstallElement(ts, h, NULL, 0, NULL);
00036 
00037     rc = rpmtsCheck(ts);
00038 
00039     ps = rpmtsProblems(ts);
00040     if (rc == 0 && rpmpsNumProblems(ps) > 0) {
00041         rpmlog(RPMLOG_ERR, _("Failed build dependencies:\n"));
00042         rpmpsPrint(NULL, ps);
00043         rc = 1;
00044     }
00045     ps = rpmpsFree(ps);
00046 
00047     /* XXX nuke the added package. */
00048     rpmtsClean(ts);
00049 
00050     return rc;
00051 }
00052 
00055 static int isSpecFile(const char * specfile)
00056 {
00057     char buf[256];
00058     const char * s;
00059     FILE * f;
00060     int count;
00061     int checking;
00062 
00063     f = fopen(specfile, "r");
00064     if (f == NULL || ferror(f)) {
00065         rpmlog(RPMLOG_ERR, _("Unable to open spec file %s: %s\n"),
00066                 specfile, strerror(errno));
00067         return 0;
00068     }
00069     count = fread(buf, sizeof(buf[0]), sizeof(buf), f);
00070     (void) fclose(f);
00071 
00072     if (count == 0)
00073         return 0;
00074 
00075     checking = 1;
00076     for (s = buf; count--; s++) {
00077         switch (*s) {
00078         case '\r':
00079         case '\n':
00080             checking = 1;
00081             break;
00082         case ':':
00083             checking = 0;
00084             break;
00085         default:
00086 #if 0
00087             if (checking && !(isprint(*s) || isspace(*s))) return 0;
00088             break;
00089 #else
00090             if (checking && !(isprint(*s) || isspace(*s)) && *(unsigned char *)s < 32) return 0;
00091             break;
00092 #endif
00093         }
00094     }
00095     return 1;
00096 }
00097 
00098 /* 
00099  * Try to find a spec from a tarball pointed to by arg. 
00100  * Return absolute path to spec name on success, otherwise NULL.
00101  */
00102 static char * getTarSpec(const char *arg)
00103 {
00104     char *specFile = NULL;
00105     char *specDir;
00106     char *specBase;
00107     char *tmpSpecFile;
00108     const char **try;
00109     char tarbuf[BUFSIZ];
00110     int gotspec = 0, res;
00111     static const char *tryspec[] = { "Specfile", "\\*.spec", NULL };
00112 
00113     specDir = rpmGetPath("%{_specdir}", NULL);
00114     tmpSpecFile = rpmGetPath("%{_specdir}/", "rpm-spec.XXXXXX", NULL);
00115 
00116     (void) close(mkstemp(tmpSpecFile));
00117 
00118     for (try = tryspec; *try != NULL; try++) {
00119         FILE *fp;
00120         char *cmd;
00121 
00122         cmd = rpmExpand("%{uncompress: ", arg, "} | ",
00123                         "%{__tar} xOvf - --wildcards ", *try,
00124                         " 2>&1 > ", tmpSpecFile, NULL);
00125 
00126         if (!(fp = popen(cmd, "r"))) {
00127             rpmlog(RPMLOG_ERR, _("Failed to open tar pipe: %m\n"));
00128         } else {
00129             char *fok;
00130             for (;;) {
00131                 fok = fgets(tarbuf, sizeof(tarbuf) - 1, fp);
00132                 /* tar sometimes prints "tar: Record size = 16" messages */
00133                 if (!fok || strncmp(fok, "tar: ", 5) != 0)
00134                     break;
00135             }
00136             pclose(fp);
00137             gotspec = (fok != NULL) && isSpecFile(tmpSpecFile);
00138         }
00139 
00140         if (!gotspec) 
00141             unlink(tmpSpecFile);
00142         free(cmd);
00143     }
00144 
00145     if (!gotspec) {
00146         rpmlog(RPMLOG_ERR, _("Failed to read spec file from %s\n"), arg);
00147         goto exit;
00148     }
00149 
00150     specBase = basename(tarbuf);
00151     /* remove trailing \n */
00152     specBase[strlen(specBase)-1] = '\0';
00153 
00154     rasprintf(&specFile, "%s/%s", specDir, specBase);
00155     res = rename(tmpSpecFile, specFile);
00156 
00157     if (res) {
00158         rpmlog(RPMLOG_ERR, _("Failed to rename %s to %s: %m\n"),
00159                 tmpSpecFile, specFile);
00160         free(specFile);
00161         specFile = NULL;
00162     } else {
00163         /* mkstemp() can give unnecessarily strict permissions, fixup */
00164         mode_t mask;
00165         umask(mask = umask(0));
00166         (void) chmod(specFile, 0666 & ~mask);
00167     }
00168 
00169 exit:
00170     (void) unlink(tmpSpecFile);
00171     free(tmpSpecFile);
00172     free(specDir);
00173     return specFile;
00174 }
00175 
00178 static int buildForTarget(rpmts ts, const char * arg, BTA_t ba)
00179 {
00180     const char * passPhrase = ba->passPhrase;
00181     const char * cookie = ba->cookie;
00182     int buildAmount = ba->buildAmount;
00183     char * buildRootURL = NULL;
00184     char * specFile = NULL;
00185     rpmSpec spec = NULL;
00186     int rc = 1; /* assume failure */
00187 
00188 #ifndef DYING
00189     rpmSetTables(RPM_MACHTABLE_BUILDARCH, RPM_MACHTABLE_BUILDOS);
00190 #endif
00191 
00192     if (ba->buildRootOverride)
00193         buildRootURL = rpmGenPath(NULL, ba->buildRootOverride, NULL);
00194 
00195     /* Create build tree if necessary */
00196     const char * buildtree = "%{_topdir}:%{_specdir}:%{_sourcedir}:%{_builddir}:%{_rpmdir}:%{_srcrpmdir}:%{_buildrootdir}";
00197     const char * rootdir = rpmtsRootDir(ts);
00198     if (rpmMkdirs(!rstreq(rootdir, "/") ? rootdir : NULL , buildtree)) {
00199         goto exit;
00200     }
00201 
00202     if (ba->buildMode == 't') {
00203         char *srcdir = NULL, *dir;
00204 
00205         specFile = getTarSpec(arg);
00206         if (!specFile)
00207             goto exit;
00208 
00209         /* Make the directory of the tarball %_sourcedir for this run */
00210         /* dirname() may modify contents so extra hoops needed. */
00211         if (*arg != '/') {
00212             dir = rpmGetCwd();
00213             rstrscat(&dir, "/", arg, NULL);
00214         } else {
00215             dir = xstrdup(arg);
00216         }
00217         srcdir = dirname(dir);
00218         addMacro(NULL, "_sourcedir", NULL, srcdir, RMIL_TARBALL);
00219         free(dir);
00220     } else {
00221         specFile = xstrdup(arg);
00222     }
00223 
00224     if (*specFile != '/') {
00225         char *cwd = rpmGetCwd();
00226         char *s = NULL;
00227         rasprintf(&s, "%s/%s", cwd, arg);
00228         free(cwd);
00229         free(specFile);
00230         specFile = s;
00231     }
00232 
00233     struct stat st;
00234     if (stat(specFile, &st) < 0) {
00235         rpmlog(RPMLOG_ERR, _("failed to stat %s: %m\n"), specFile);
00236         goto exit;
00237     }
00238     if (! S_ISREG(st.st_mode)) {
00239         rpmlog(RPMLOG_ERR, _("File %s is not a regular file.\n"), specFile);
00240         goto exit;
00241     }
00242 
00243     /* Try to verify that the file is actually a specfile */
00244     if (!isSpecFile(specFile)) {
00245         rpmlog(RPMLOG_ERR,
00246                 _("File %s does not appear to be a specfile.\n"), specFile);
00247         goto exit;
00248     }
00249     
00250     /* Don't parse spec if only its removal is requested */
00251     if (ba->buildAmount == RPMBUILD_RMSPEC) {
00252         rc = unlink(specFile);
00253         goto exit;
00254     }
00255 
00256     /* Parse the spec file */
00257 #define _anyarch(_f)    \
00258 (((_f)&(RPMBUILD_PREP|RPMBUILD_BUILD|RPMBUILD_INSTALL|RPMBUILD_PACKAGEBINARY)) == 0)
00259     if (parseSpec(ts, specFile, ba->rootdir, buildRootURL, 0, passPhrase,
00260                 cookie, _anyarch(buildAmount), ba->force))
00261     {
00262         goto exit;
00263     }
00264 #undef  _anyarch
00265     if ((spec = rpmtsSetSpec(ts, NULL)) == NULL) {
00266         goto exit;
00267     }
00268 
00269     if ( ba->buildAmount&RPMBUILD_RMSOURCE && !(ba->buildAmount&~(RPMBUILD_RMSOURCE|RPMBUILD_RMSPEC)) ) {
00270         rc = doRmSource(spec);
00271         if ( rc == RPMRC_OK && ba->buildAmount&RPMBUILD_RMSPEC )
00272             rc = unlink(specFile);
00273         goto exit;
00274     }
00275 
00276     /* Assemble source header from parsed components */
00277     initSourceHeader(spec);
00278 
00279     /* Check build prerequisites */
00280     if (!ba->noDeps && checkSpec(ts, spec->sourceHeader)) {
00281         goto exit;
00282     }
00283 
00284     if (buildSpec(ts, spec, buildAmount, ba->noBuild)) {
00285         goto exit;
00286     }
00287     
00288     if (ba->buildMode == 't')
00289         (void) unlink(specFile);
00290     rc = 0;
00291 
00292 exit:
00293     free(specFile);
00294     freeSpec(spec);
00295     free(buildRootURL);
00296     return rc;
00297 }
00298 
00299 int build(rpmts ts, const char * arg, BTA_t ba, const char * rcfile)
00300 {
00301     char *t, *te;
00302     int rc = 0;
00303     char * targets = ba->targets;
00304 #define buildCleanMask  (RPMBUILD_RMSOURCE|RPMBUILD_RMSPEC)
00305     int cleanFlags = ba->buildAmount & buildCleanMask;
00306     rpmVSFlags vsflags, ovsflags;
00307 
00308     vsflags = rpmExpandNumeric("%{_vsflags_build}");
00309     if (ba->qva_flags & VERIFY_DIGEST)
00310         vsflags |= _RPMVSF_NODIGESTS;
00311     if (ba->qva_flags & VERIFY_SIGNATURE)
00312         vsflags |= _RPMVSF_NOSIGNATURES;
00313     if (ba->qva_flags & VERIFY_HDRCHK)
00314         vsflags |= RPMVSF_NOHDRCHK;
00315     ovsflags = rpmtsSetVSFlags(ts, vsflags);
00316 
00317     if (targets == NULL) {
00318         rc =  buildForTarget(ts, arg, ba);
00319         goto exit;
00320     }
00321 
00322     /* parse up the build operators */
00323 
00324     printf(_("Building target platforms: %s\n"), targets);
00325 
00326     ba->buildAmount &= ~buildCleanMask;
00327     for (t = targets; *t != '\0'; t = te) {
00328         char *target;
00329         if ((te = strchr(t, ',')) == NULL)
00330             te = t + strlen(t);
00331         target = xmalloc(te-t+1);
00332         strncpy(target, t, (te-t));
00333         target[te-t] = '\0';
00334         if (*te != '\0')
00335             te++;
00336         else    /* XXX Perform clean-up after last target build. */
00337             ba->buildAmount |= cleanFlags;
00338 
00339         printf(_("Building for target %s\n"), target);
00340 
00341         /* Read in configuration for target. */
00342         rpmFreeMacros(NULL);
00343         rpmFreeRpmrc();
00344         (void) rpmReadConfigFiles(rcfile, target);
00345         free(target);
00346         rc = buildForTarget(ts, arg, ba);
00347         if (rc)
00348             break;
00349     }
00350 
00351 exit:
00352     vsflags = rpmtsSetVSFlags(ts, ovsflags);
00353     /* Restore original configuration. */
00354     rpmFreeMacros(NULL);
00355     rpmFreeRpmrc();
00356     (void) rpmReadConfigFiles(rcfile, NULL);
00357 
00358     return rc;
00359 }