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>         
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     
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 
00100 
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     
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         
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; 
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     
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         
00204         
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     
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     
00245     if (ba->buildAmount == RPMBUILD_RMSPEC) {
00246         rc = unlink(specFile);
00247         goto exit;
00248     }
00249 
00250     
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     
00271     initSourceHeader(spec);
00272 
00273     
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     
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    
00331             ba->buildAmount |= cleanFlags;
00332 
00333         printf(_("Building for target %s\n"), target);
00334 
00335         
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     
00348     rpmFreeMacros(NULL);
00349     rpmFreeRpmrc();
00350     (void) rpmReadConfigFiles(rcfile, NULL);
00351 
00352     return rc;
00353 }