- 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 = fgets(tarbuf, sizeof(tarbuf) - 1, fp);
    00130             pclose(fp);
    00131             gotspec = (fok != NULL) && isSpecFile(tmpSpecFile);
    00132         }
    00133
    00134         if (!gotspec)
    00135             unlink(tmpSpecFile);
    00136         free(cmd);
    00137     }
    00138
    00139     if (!gotspec) {
    00140         rpmlog(RPMLOG_ERR, _("Failed to read spec file from %s\n"), arg);
    00141         goto exit;
    00142     }
    00143
    00144     specBase = basename(tarbuf);
    00145     /* remove trailing \n */
    00146     specBase[strlen(specBase)-1] = '\0';
    00147
    00148     rasprintf(&specFile, "%s/%s", specDir, specBase);
    00149     res = rename(tmpSpecFile, specFile);
    00150
    00151     if (res) {
    00152         rpmlog(RPMLOG_ERR, _("Failed to rename %s to %s: %m\n"),
    00153                 tmpSpecFile, specFile);
    00154         free(specFile);
    00155         specFile = NULL;
    00156     } else {
    00157         /* mkstemp() can give unnecessarily strict permissions, fixup */
    00158         mode_t mask;
    00159         umask(mask = umask(0));
    00160         (void) chmod(specFile, 0666 & ~mask);
    00161     }
    00162
    00163 exit:
    00164     (void) unlink(tmpSpecFile);
    00165     free(tmpSpecFile);
    00166     free(specDir);
    00167     return specFile;
    00168 }
    00169
    00172 static int buildForTarget(rpmts ts, const char * arg, BTA_t ba)
    00173 {
    00174     const char * passPhrase = ba->passPhrase;
    00175     const char * cookie = ba->cookie;
    00176     int buildAmount = ba->buildAmount;
    00177     char * buildRootURL = NULL;
    00178     char * specFile = NULL;
    00179     rpmSpec spec = NULL;
    00180     int rc = 1; /* assume failure */
    00181
    00182 #ifndef DYING
    00183     rpmSetTables(RPM_MACHTABLE_BUILDARCH, RPM_MACHTABLE_BUILDOS);
    00184 #endif
    00185
    00186     if (ba->buildRootOverride)
    00187         buildRootURL = rpmGenPath(NULL, ba->buildRootOverride, NULL);
    00188
    00189     /* Create build tree if necessary */
    00190     const char * buildtree = "%{_topdir}:%{_specdir}:%{_sourcedir}:%{_builddir}:%{_rpmdir}:%{_srcrpmdir}:%{_buildrootdir}";
    00191     const char * rootdir = rpmtsRootDir(ts);
    00192     if (rpmMkdirs(strcmp(rootdir, "/") ? rootdir : NULL , buildtree)) {
    00193         goto exit;
    00194     }
    00195
    00196     if (ba->buildMode == 't') {
    00197         char *srcdir = NULL, *dir;
    00198
    00199         specFile = getTarSpec(arg);
    00200         if (!specFile)
    00201             goto exit;
    00202
    00203         /* Make the directory of the tarball %_sourcedir for this run */
    00204         /* dirname() may modify contents so extra hoops needed. */
    00205         if (*arg != '/') {
    00206             dir = rpmGetCwd();
    00207             rstrscat(&dir, "/", arg, NULL);
    00208         } else {
    00209             dir = xstrdup(arg);
    00210         }
    00211         srcdir = dirname(dir);
    00212         addMacro(NULL, "_sourcedir", NULL, srcdir, RMIL_TARBALL);
    00213         free(dir);
    00214     } else {
    00215         specFile = xstrdup(arg);
    00216     }
    00217
    00218     if (*specFile != '/') {
    00219         char *cwd = rpmGetCwd();
    00220         char *s = NULL;
    00221         rasprintf(&s, "%s/%s", cwd, arg);
    00222         free(cwd);
    00223         free(specFile);
    00224         specFile = s;
    00225     }
    00226
    00227     struct stat st;
    00228     if (stat(specFile, &st) < 0) {
    00229         rpmlog(RPMLOG_ERR, _("failed to stat %s: %m\n"), specFile);
    00230         goto exit;
    00231     }
    00232     if (! S_ISREG(st.st_mode)) {
    00233         rpmlog(RPMLOG_ERR, _("File %s is not a regular file.\n"), specFile);
    00234         goto exit;
    00235     }
    00236
    00237     /* Try to verify that the file is actually a specfile */
    00238     if (!isSpecFile(specFile)) {
    00239         rpmlog(RPMLOG_ERR,
    00240                 _("File %s does not appear to be a specfile.\n"), specFile);
    00241         goto exit;
    00242     }
    00243
    00244     /* Don't parse spec if only its removal is requested */
    00245     if (ba->buildAmount == RPMBUILD_RMSPEC) {
    00246         rc = unlink(specFile);
    00247         goto exit;
    00248     }
    00249
    00250     /* Parse the spec file */
    00251 #define _anyarch(_f)    \
    00252 (((_f)&(RPMBUILD_PREP|RPMBUILD_BUILD|RPMBUILD_INSTALL|RPMBUILD_PACKAGEBINARY)) == 0)
    00253     if (parseSpec(ts, specFile, ba->rootdir, buildRootURL, 0, passPhrase,
    00254                 cookie, _anyarch(buildAmount), ba->force))
    00255     {
    00256         goto exit;
    00257     }
    00258 #undef  _anyarch
    00259     if ((spec = rpmtsSetSpec(ts, NULL)) == NULL) {
    00260         goto exit;
    00261     }
    00262
    00263     if ( ba->buildAmount&RPMBUILD_RMSOURCE && !(ba->buildAmount&~(RPMBUILD_RMSOURCE|RPMBUILD_RMSPEC)) ) {
    00264         rc = doRmSource(spec);
    00265         if ( rc == RPMRC_OK && ba->buildAmount&RPMBUILD_RMSPEC )
    00266             rc = unlink(specFile);
    00267         goto exit;
    00268     }
    00269
    00270     /* Assemble source header from parsed components */
    00271     initSourceHeader(spec);
    00272
    00273     /* Check build prerequisites */
    00274     if (!ba->noDeps && checkSpec(ts, spec->sourceHeader)) {
    00275         goto exit;
    00276     }
    00277
    00278     if (buildSpec(ts, spec, buildAmount, ba->noBuild)) {
    00279         goto exit;
    00280     }
    00281
    00282     if (ba->buildMode == 't')
    00283         (void) unlink(specFile);
    00284     rc = 0;
    00285
    00286 exit:
    00287     free(specFile);
    00288     freeSpec(spec);
    00289     free(buildRootURL);
    00290     return rc;
    00291 }
    00292
    00293 int build(rpmts ts, const char * arg, BTA_t ba, const char * rcfile)
    00294 {
    00295     char *t, *te;
    00296     int rc = 0;
    00297     char * targets = ba->targets;
    00298 #define buildCleanMask  (RPMBUILD_RMSOURCE|RPMBUILD_RMSPEC)
    00299     int cleanFlags = ba->buildAmount & buildCleanMask;
    00300     rpmVSFlags vsflags, ovsflags;
    00301
    00302     vsflags = rpmExpandNumeric("%{_vsflags_build}");
    00303     if (ba->qva_flags & VERIFY_DIGEST)
    00304         vsflags |= _RPMVSF_NODIGESTS;
    00305     if (ba->qva_flags & VERIFY_SIGNATURE)
    00306         vsflags |= _RPMVSF_NOSIGNATURES;
    00307     if (ba->qva_flags & VERIFY_HDRCHK)
    00308         vsflags |= RPMVSF_NOHDRCHK;
    00309     ovsflags = rpmtsSetVSFlags(ts, vsflags);
    00310
    00311     if (targets == NULL) {
    00312         rc =  buildForTarget(ts, arg, ba);
    00313         goto exit;
    00314     }
    00315
    00316     /* parse up the build operators */
    00317
    00318     printf(_("Building target platforms: %s\n"), targets);
    00319
    00320     ba->buildAmount &= ~buildCleanMask;
    00321     for (t = targets; *t != '\0'; t = te) {
    00322         char *target;
    00323         if ((te = strchr(t, ',')) == NULL)
    00324             te = t + strlen(t);
    00325         target = xmalloc(te-t+1);
    00326         strncpy(target, t, (te-t));
    00327         target[te-t] = '\0';
    00328         if (*te != '\0')
    00329             te++;
    00330         else    /* XXX Perform clean-up after last target build. */
    00331             ba->buildAmount |= cleanFlags;
    00332
    00333         printf(_("Building for target %s\n"), target);
    00334
    00335         /* Read in configuration for target. */
    00336         rpmFreeMacros(NULL);
    00337         rpmFreeRpmrc();
    00338         (void) rpmReadConfigFiles(rcfile, target);
    00339         free(target);
    00340         rc = buildForTarget(ts, arg, ba);
    00341         if (rc)
    00342             break;
    00343     }
    00344
    00345 exit:
    00346     vsflags = rpmtsSetVSFlags(ts, ovsflags);
    00347     /* Restore original configuration. */
    00348     rpmFreeMacros(NULL);
    00349     rpmFreeRpmrc();
    00350     (void) rpmReadConfigFiles(rcfile, NULL);
    00351
    00352     return rc;
    00353 }