# build.c

Go to the documentation of this file.

    00001
    00005 #include "system.h"
    00006
    00007 #include <rpmcli.h>
    00008 #include <rpmbuild.h>
    00009
    00010 #include "build.h"
    00011 #include "debug.h"
    00012
    00013 /*@access rpmTransactionSet @*/ /* XXX compared with NULL @*/
    00014 /*@access rpmdb @*/             /* XXX compared with NULL @*/
    00015 /*@access FD_t @*/              /* XXX compared with NULL @*/
    00016
    00019 static int checkSpec(Header h)
    00020         /*@globals rpmGlobalMacroContext,
    00021                 fileSystem, internalState @*/
    00022         /*@modifies h, rpmGlobalMacroContext,
    00023                 fileSystem, internalState @*/
    00024 {
    00025     const char * rootdir = NULL;
    00026     rpmdb db = NULL;
    00027     int mode = O_RDONLY;
    00028     rpmTransactionSet ts;
    00029     rpmDependencyConflict conflicts;
    00030     int numConflicts;
    00031     int rc;
    00032
    00033     if (!headerIsEntry(h, RPMTAG_REQUIREFLAGS))
    00034         return 0;
    00035
    00036     if (rpmdbOpen(rootdir, &db, mode, 0644)) {
    00037         const char * dn;
    00038         dn = rpmGetPath( (rootdir ? rootdir : ""), "%{_dbpath}", NULL);
    00039         rpmError(RPMERR_OPEN, _("cannot open rpm database in %s\n"), dn);
    00040         dn = _free(dn);
    00041         exit(EXIT_FAILURE);
    00042     }
    00043     ts = rpmtransCreateSet(db, rootdir);
    00044
    00045     rc = rpmtransAddPackage(ts, h, NULL, NULL, 0, NULL);
    00046
    00047     rc = rpmdepCheck(ts, &conflicts, &numConflicts);
    00048     if (rc == 0 && conflicts) {
    00049         rpmMessage(RPMMESS_ERROR, _("failed build dependencies:\n"));
    00050         printDepProblems(stderr, conflicts, numConflicts);
    00051         conflicts = rpmdepFreeConflicts(conflicts, numConflicts);
    00052         rc = 1;
    00053     }
    00054
    00055     ts = rpmtransFree(ts);
    00056     if (db != NULL)
    00057         (void) rpmdbClose(db);
    00058
    00059     return rc;
    00060 }
    00061
    00062 /*
    00063  * Kurwa, durni ameryka?ce sobe zawsze my?l?, ?e ca?y ?wiat mówi po
    00064  * angielsku...
    00065  */
    00066 /* XXX this is still a dumb test but at least it's i18n aware */
    00069 static int isSpecFile(const char * specfile)
    00070         /*@globals fileSystem @*/
    00071         /*@modifies fileSystem @*/
    00072 {
    00073     char buf[256];
    00074     const char * s;
    00075     FD_t fd;
    00076     int count;
    00077     int checking;
    00078
    00079     fd = Fopen(specfile, "r.ufdio");
    00080     if (fd == NULL || Ferror(fd)) {
    00081         rpmError(RPMERR_OPEN, _("Unable to open spec file %s: %s\n"),
    00082                 specfile, Fstrerror(fd));
    00083         return 0;
    00084     }
    00085     count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd);
    00086     (void) Fclose(fd);
    00087
    00088     checking = 1;
    00089     for (s = buf; count--; s++) {
    00090         switch (*s) {
    00091         case '\r':
    00092         case '\n':
    00093             checking = 1;
    00094             /*@switchbreak@*/ break;
    00095         case ':':
    00096             checking = 0;
    00097             /*@switchbreak@*/ break;
    00098         default:
    00099             if (checking && !(isprint(*s) || isspace(*s))) return 0;
    00100             /*@switchbreak@*/ break;
    00101         }
    00102     }
    00103     return 1;
    00104 }
    00105
    00108 static int buildForTarget(const char * arg, BTA_t ba,
    00109                 const char * passPhrase, char * cookie)
    00110         /*@globals rpmGlobalMacroContext,
    00111                 fileSystem, internalState @*/
    00112         /*@modifies rpmGlobalMacroContext,
    00113                 fileSystem, internalState @*/
    00114 {
    00115     int buildAmount = ba->buildAmount;
    00116     const char * buildRootURL = NULL;
    00117     const char * specFile;
    00118     const char * specURL;
    00119     int specut;
    00120     char buf[BUFSIZ];
    00121     Spec spec = NULL;
    00122     int rc;
    00123
    00124 #ifndef DYING
    00125     rpmSetTables(RPM_MACHTABLE_BUILDARCH, RPM_MACHTABLE_BUILDOS);
    00126 #endif
    00127
    00128     /*@-branchstate@*/
    00129     if (ba->buildRootOverride)
    00130         buildRootURL = rpmGenPath(NULL, ba->buildRootOverride, NULL);
    00131     /*@=branchstate@*/
    00132
    00133     /*@-compmempass@*/ /* FIX: static zcmds heartburn */
    00134     if (ba->buildMode == 't') {
    00135         FILE *fp;
    00136         const char * specDir;
    00137         const char * tmpSpecFile;
    00138         char * cmd, * s;
    00139         rpmCompressedMagic res = COMPRESSED_OTHER;
    00140         /*@observer@*/ static const char *zcmds[] =
    00141                 { "cat", "gunzip", "bunzip2", "cat" };
    00142
    00143         specDir = rpmGetPath("%{_specdir}", NULL);
    00144
    00145         /* XXX Using mkstemp is difficult here. */
    00146         /* XXX FWIW, default %{_specdir} is root.root 0755 */
    00147         {   char tfn[64];
    00148             strcpy(tfn, "rpm-spec.XXXXXX");
    00149             /*@-unrecog@*/
    00150             tmpSpecFile = rpmGetPath("%{_specdir}/", mktemp(tfn), NULL);
    00151             /*@=unrecog@*/
    00152         }
    00153
    00154         (void) isCompressed(arg, &res);
    00155
    00156         cmd = alloca(strlen(arg) + 50 + strlen(tmpSpecFile));
    00157         sprintf(cmd, "%s < %s | tar xOvf - Specfile 2>&1 > %s",
    00158                         zcmds[res & 0x3], arg, tmpSpecFile);
    00159         if (!(fp = popen(cmd, "r"))) {
    00160             rpmError(RPMERR_POPEN, _("Failed to open tar pipe: %m\n"));
    00161             specDir = _free(specDir);
    00162             tmpSpecFile = _free(tmpSpecFile);
    00163             return 1;
    00164         }
    00165         if ((!fgets(buf, sizeof(buf) - 1, fp)) || !strchr(buf, '/')) {
    00166             /* Try again */
    00167             (void) pclose(fp);
    00168
    00169             sprintf(cmd, "%s < %s | tar xOvf - \\*.spec 2>&1 > %s",
    00170                     zcmds[res & 0x3], arg, tmpSpecFile);
    00171             if (!(fp = popen(cmd, "r"))) {
    00172                 rpmError(RPMERR_POPEN, _("Failed to open tar pipe: %m\n"));
    00173                 specDir = _free(specDir);
    00174                 tmpSpecFile = _free(tmpSpecFile);
    00175                 return 1;
    00176             }
    00177             if (!fgets(buf, sizeof(buf) - 1, fp)) {
    00178                 /* Give up */
    00179                 rpmError(RPMERR_READ, _("Failed to read spec file from %s\n"),
    00180                         arg);
    00181                 (void) unlink(tmpSpecFile);
    00182                 specDir = _free(specDir);
    00183                 tmpSpecFile = _free(tmpSpecFile);
    00184                 return 1;
    00185             }
    00186         }
    00187         (void) pclose(fp);
    00188
    00189         cmd = s = buf;
    00190         while (*cmd != '\0') {
    00191             if (*cmd == '/') s = cmd + 1;
    00192             cmd++;
    00193         }
    00194
    00195         cmd = s;
    00196
    00197         /* remove trailing \n */
    00198         s = cmd + strlen(cmd) - 1;
    00199         *s = '\0';
    00200
    00201         specURL = s = alloca(strlen(specDir) + strlen(cmd) + 5);
    00202         sprintf(s, "%s/%s", specDir, cmd);
    00203         res = rename(tmpSpecFile, s);
    00204         specDir = _free(specDir);
    00205
    00206         if (res) {
    00207             rpmError(RPMERR_RENAME, _("Failed to rename %s to %s: %m\n"),
    00208                         tmpSpecFile, s);
    00209             (void) unlink(tmpSpecFile);
    00210             tmpSpecFile = _free(tmpSpecFile);
    00211             return 1;
    00212         }
    00213         tmpSpecFile = _free(tmpSpecFile);
    00214
    00215         /* Make the directory which contains the tarball the source
    00216            directory for this run */
    00217
    00218         if (*arg != '/') {
    00219             (void)getcwd(buf, BUFSIZ);
    00220             strcat(buf, "/");
    00221             strcat(buf, arg);
    00222         } else
    00223             strcpy(buf, arg);
    00224
    00225         cmd = buf + strlen(buf) - 1;
    00226         while (*cmd != '/') cmd--;
    00227         *cmd = '\0';
    00228
    00229         addMacro(NULL, "_sourcedir", NULL, buf, RMIL_TARBALL);
    00230     } else {
    00231         specURL = arg;
    00232     }
    00233     /*@=compmempass@*/
    00234
    00235     specut = urlPath(specURL, &specFile);
    00236     if (*specFile != '/') {
    00237         char *s = alloca(BUFSIZ);
    00238         (void)getcwd(s, BUFSIZ);
    00239         strcat(s, "/");
    00240         strcat(s, arg);
    00241         specURL = s;
    00242     }
    00243
    00244     if (specut != URL_IS_DASH) {
    00245         struct stat st;
    00246         if (Stat(specURL, &st) < 0) {
    00247             rpmError(RPMERR_STAT, _("failed to stat %s: %m\n"), specURL);
    00248             rc = 1;
    00249             goto exit;
    00250         }
    00251         if (! S_ISREG(st.st_mode)) {
    00252             rpmError(RPMERR_NOTREG, _("File %s is not a regular file.\n"),
    00253                 specURL);
    00254             rc = 1;
    00255             goto exit;
    00256         }
    00257
    00258         /* Try to verify that the file is actually a specfile */
    00259         if (!isSpecFile(specURL)) {
    00260             rpmError(RPMERR_BADSPEC,
    00261                 _("File %s does not appear to be a specfile.\n"), specURL);
    00262             rc = 1;
    00263             goto exit;
    00264         }
    00265     }
    00266
    00267     /* Parse the spec file */
    00268 #define _anyarch(_f)    \
    00269 (((_f)&(RPMBUILD_PREP|RPMBUILD_BUILD|RPMBUILD_INSTALL|RPMBUILD_PACKAGEBINARY)) == 0)
    00270     if (parseSpec(&spec, specURL, ba->rootdir, buildRootURL, 0, passPhrase,
    00271                 cookie, _anyarch(buildAmount), ba->force)) {
    00272         rc = 1;
    00273         goto exit;
    00274     }
    00275 #undef  _anyarch
    00276
    00277     /* Assemble source header from parsed components */
    00278     initSourceHeader(spec);
    00279
    00280     /* Check build prerequisites */
    00281     if (!ba->noDeps && checkSpec(spec->sourceHeader)) {
    00282         rc = 1;
    00283         goto exit;
    00284     }
    00285
    00286     if (buildSpec(spec, buildAmount, ba->noBuild)) {
    00287         rc = 1;
    00288         goto exit;
    00289     }
    00290
    00291     if (ba->buildMode == 't')
    00292         (void) Unlink(specURL);
    00293     rc = 0;
    00294
    00295 exit:
    00296     spec = freeSpec(spec);
    00297     buildRootURL = _free(buildRootURL);
    00298     return rc;
    00299 }
    00300
    00301 int build(const char * arg, BTA_t ba,
    00302         const char * passPhrase, char * cookie, const char * rcfile)
    00303 {
    00304     char *t, *te;
    00305     int rc = 0;
    00306     char * targets = ba->targets;
    00307 #define buildCleanMask  (RPMBUILD_RMSOURCE|RPMBUILD_RMSPEC)
    00308     int cleanFlags = ba->buildAmount & buildCleanMask;
    00309
    00310     if (targets == NULL) {
    00311         rc =  buildForTarget(arg, ba, passPhrase, cookie);
    00312         goto exit;
    00313     }
    00314
    00315     /* parse up the build operators */
    00316
    00317     printf(_("Building target platforms: %s\n"), targets);
    00318
    00319     ba->buildAmount &= ~buildCleanMask;
    00320     for (t = targets; *t != '\0'; t = te) {
    00321         char *target;
    00322         if ((te = strchr(t, ',')) == NULL)
    00323             te = t + strlen(t);
    00324         target = alloca(te-t+1);
    00325         strncpy(target, t, (te-t));
    00326         target[te-t] = '\0';
    00327         if (*te != '\0')
    00328             te++;
    00329         else    /* XXX Perform clean-up after last target build. */
    00330             ba->buildAmount |= cleanFlags;
    00331
    00332         printf(_("Building for target %s\n"), target);
    00333
    00334         /* Read in configuration for target. */
    00335         rpmFreeMacros(NULL);
    00336         (void) rpmReadConfigFiles(rcfile, target);
    00337         rc = buildForTarget(arg, ba, passPhrase, cookie);
    00338         if (rc)
    00339             break;
    00340     }
    00341
    00342 exit:
    00343     /* Restore original configuration. */
    00344     rpmFreeMacros(NULL);
    00345     (void) rpmReadConfigFiles(rcfile, NULL);
    00346
    00347     return rc;
    00348 }