- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

# 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 }