rpm 5.3.12
build/build.c
Go to the documentation of this file.
00001 
00006 #include "system.h"
00007 
00008 #define _RPMBC_INTERNAL
00009 #include <rpmio_internal.h>     /* XXX fdGetFp */
00010 #include <rpmcb.h>
00011 #include <rpmsq.h>
00012 
00013 #define _RPMTAG_INTERNAL
00014 #include <rpmbuild.h>
00015 #include "signature.h"          /* XXX rpmTempFile */
00016 
00017 #include "debug.h"
00018 
00021 #if defined(RPM_VENDOR_OPENPKG) /* splitted-source-directory */
00022 const char * getSourceDir(rpmfileAttrs attr, const char *filename)
00023 #else
00024 const char * getSourceDir(rpmfileAttrs attr)
00025 #endif
00026 {
00027     const char * dir = NULL;
00028 #if defined(RPM_VENDOR_OPENPKG) /* splitted-source-directory */
00029     const char *fn;
00030 
00031     /*  support splitted source directories, i.e., source files which
00032         are alternatively placed into the .spec directory and picked
00033         up from there, too. */
00034     if (attr & (RPMFILE_SOURCE|RPMFILE_PATCH|RPMFILE_ICON) && filename != NULL)
00035     {
00036         fn = rpmGetPath("%{_specdir}/", filename, NULL);
00037         if (access(fn, F_OK) == 0)
00038             dir = "%{_specdir}/";
00039         fn = _free(fn);
00040     }
00041     if (dir != NULL) {
00042     } else
00043 #endif
00044     if (attr & RPMFILE_SOURCE)
00045         dir = "%{_sourcedir}/";
00046     else if (attr & RPMFILE_PATCH)
00047         dir = "%{_patchdir}/";
00048     else if (attr & RPMFILE_ICON)
00049         dir = "%{_icondir}/";
00050 
00051     return dir;
00052 }
00053 
00054 /*@access urlinfo @*/           /* XXX compared with NULL */
00055 /*@access FD_t @*/
00056 
00059 static void doRmSource(Spec spec)
00060         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00061         /*@modifies rpmGlobalMacroContext, fileSystem, internalState  @*/
00062 {
00063     struct Source *sp;
00064     int rc;
00065 
00066 #if 0
00067     rc = Unlink(spec->specFile);
00068 #endif
00069 
00070     for (sp = spec->sources; sp != NULL; sp = sp->next) {
00071         const char *dn, *fn;
00072         if (sp->flags & RPMFILE_GHOST)
00073             continue;
00074 #if defined(RPM_VENDOR_OPENPKG) /* splitted-source-directory */
00075         if (! (dn = getSourceDir(sp->flags, sp->source)))
00076 #else
00077         if (! (dn = getSourceDir(sp->flags)))
00078 #endif
00079             continue;
00080         fn = rpmGenPath(NULL, dn, sp->source);
00081         rc = Unlink(fn);
00082         fn = _free(fn);
00083     }
00084 }
00085 
00086 /*
00087  * @todo Single use by %%doc in files.c prevents static.
00088  */
00089 rpmRC doScript(Spec spec, int what, const char *name, rpmiob iob, int test)
00090 {
00091     const char * rootURL = spec->rootURL;
00092     const char * rootDir;
00093     const char * scriptName = NULL;
00094     const char * buildDirURL = rpmGenPath(rootURL, "%{_builddir}", "");
00095     const char * buildScript;
00096     const char * buildCmd = NULL;
00097     const char * buildTemplate = NULL;
00098     const char * buildPost = NULL;
00099     const char * mTemplate = NULL;
00100     const char * mCmd = NULL;
00101     const char * mPost = NULL;
00102     int argc = 0;
00103     const char **argv = NULL;
00104     FILE * fp = NULL;
00105     urlinfo u = NULL;
00106     rpmop op = NULL;
00107     int ix = -1;
00108 
00109     FD_t fd;
00110     FD_t xfd;
00111     int status;
00112     rpmRC rc;
00113     size_t i;
00114 
00115     switch (what) {
00116     case RPMBUILD_PREP:
00117         name = "%prep";
00118         iob = spec->prep;
00119         op = memset(alloca(sizeof(*op)), 0, sizeof(*op));
00120         ix = RPMSCRIPT_PREP;
00121         mTemplate = "%{__spec_prep_template}";
00122         mPost = "%{__spec_prep_post}";
00123         mCmd = "%{__spec_prep_cmd}";
00124         break;
00125     case RPMBUILD_BUILD:
00126         name = "%build";
00127         iob = spec->build;
00128         op = memset(alloca(sizeof(*op)), 0, sizeof(*op));
00129         ix = RPMSCRIPT_BUILD;
00130         mTemplate = "%{__spec_build_template}";
00131         mPost = "%{__spec_build_post}";
00132         mCmd = "%{__spec_build_cmd}";
00133         break;
00134     case RPMBUILD_INSTALL:
00135         name = "%install";
00136         iob = spec->install;
00137         op = memset(alloca(sizeof(*op)), 0, sizeof(*op));
00138         ix = RPMSCRIPT_INSTALL;
00139         mTemplate = "%{__spec_install_template}";
00140         mPost = "%{__spec_install_post}";
00141         mCmd = "%{__spec_install_cmd}";
00142         break;
00143     case RPMBUILD_CHECK:
00144         name = "%check";
00145         iob = spec->check;
00146         op = memset(alloca(sizeof(*op)), 0, sizeof(*op));
00147         ix = RPMSCRIPT_CHECK;
00148         mTemplate = "%{__spec_check_template}";
00149         mPost = "%{__spec_check_post}";
00150         mCmd = "%{__spec_check_cmd}";
00151         break;
00152     case RPMBUILD_CLEAN:
00153         name = "%clean";
00154         iob = spec->clean;
00155         mTemplate = "%{__spec_clean_template}";
00156         mPost = "%{__spec_clean_post}";
00157         mCmd = "%{__spec_clean_cmd}";
00158         break;
00159     case RPMBUILD_RMBUILD:
00160         name = "--clean";
00161         mTemplate = "%{__spec_clean_template}";
00162         mPost = "%{__spec_clean_post}";
00163         mCmd = "%{__spec_clean_cmd}";
00164         break;
00165     /* support "%track" script/section */
00166     case RPMBUILD_TRACK:
00167         name = "%track";
00168         iob = NULL;
00169         if (spec->foo)
00170         for (i = 0; i < spec->nfoo; i++) {
00171             if (spec->foo[i].str == NULL || spec->foo[i].iob == NULL)
00172                 continue;
00173             if (xstrcasecmp(spec->foo[i].str, "track"))
00174                 continue;
00175             iob = spec->foo[i].iob;
00176             /*@loopbreak@*/ break;
00177         }
00178         mTemplate = "%{__spec_track_template}";
00179         mPost = "%{__spec_track_post}";
00180         mCmd = "%{__spec_track_cmd}";
00181         break;
00182     case RPMBUILD_STRINGBUF:
00183     default:
00184         mTemplate = "%{___build_template}";
00185         mPost = "%{___build_post}";
00186         mCmd = "%{___build_cmd}";
00187         break;
00188     }
00189 
00190 assert(name != NULL);
00191 
00192     if ((what != RPMBUILD_RMBUILD) && iob == NULL) {
00193         rc = RPMRC_OK;
00194         goto exit;
00195     }
00196 
00197     if (rpmTempFile(rootURL, &scriptName, &fd) || fd == NULL || Ferror(fd)) {
00198         rpmlog(RPMLOG_ERR, _("Unable to open temp file.\n"));
00199         rc = RPMRC_FAIL;
00200         goto exit;
00201     }
00202 
00203     if (fdGetFp(fd) == NULL)
00204         xfd = Fdopen(fd, "w.fpio");
00205     else
00206         xfd = fd;
00207 
00208     /*@-type@*/ /* FIX: cast? */
00209     if ((fp = fdGetFp(xfd)) == NULL) {
00210         rc = RPMRC_FAIL;
00211         goto exit;
00212     }
00213     /*@=type@*/
00214 
00215     (void) urlPath(rootURL, &rootDir);
00216     if (*rootDir == '\0') rootDir = "/";
00217 
00218     (void) urlPath(scriptName, &buildScript);
00219 
00220     buildTemplate = rpmExpand(mTemplate, NULL);
00221     buildPost = rpmExpand(mPost, NULL);
00222 
00223     (void) fputs(buildTemplate, fp);
00224 
00225     /* support "%track" script/section */
00226     if (what != RPMBUILD_PREP && what != RPMBUILD_RMBUILD && spec->buildSubdir && what != RPMBUILD_TRACK)
00227         fprintf(fp, "cd '%s'\n", spec->buildSubdir);
00228 
00229     if (what == RPMBUILD_RMBUILD) {
00230         if (spec->buildSubdir)
00231             fprintf(fp, "rm -rf '%s'\n", spec->buildSubdir);
00232     } else if (iob != NULL)
00233         fprintf(fp, "%s", rpmiobStr(iob));
00234 
00235     (void) fputs(buildPost, fp);
00236 
00237     (void) Fclose(xfd);
00238 
00239     if (test) {
00240         rc = RPMRC_OK;
00241         goto exit;
00242     }
00243 
00244     if (buildDirURL && buildDirURL[0] != '/' &&
00245         (urlSplit(buildDirURL, &u) != 0)) {
00246         rc = RPMRC_FAIL;
00247         goto exit;
00248     }
00249 
00250     switch (urlType(u)) {
00251     case URL_IS_HTTPS:
00252     case URL_IS_HTTP:
00253     case URL_IS_FTP:
00254         addMacro(spec->macros, "_remsh", NULL, "%{__remsh}", RMIL_SPEC);
00255         addMacro(spec->macros, "_remhost", NULL, u->host, RMIL_SPEC);
00256         if (strcmp(rootDir, "/"))
00257             addMacro(spec->macros, "_remroot", NULL, rootDir, RMIL_SPEC);
00258         break;
00259     case URL_IS_UNKNOWN:
00260     case URL_IS_DASH:
00261     case URL_IS_PATH:
00262     case URL_IS_HKP:
00263     default:
00264         break;
00265     }
00266 
00267     buildCmd = rpmExpand(mCmd, " ", buildScript, NULL);
00268     (void) poptParseArgvString(buildCmd, &argc, &argv);
00269 
00270     if (what != RPMBUILD_TRACK)         /* support "%track" script/section */
00271         rpmlog(RPMLOG_NOTICE, _("Executing(%s): %s\n"), name, buildCmd);
00272 
00273     /* Run the script with a stopwatch. */
00274     if (op != NULL)
00275         (void) rpmswEnter(op, 0);
00276 
00277     status = rpmsqExecve(argv);
00278     if (ix >= 0 && ix < RPMSCRIPT_MAX)
00279         spec->sstates[ix] =
00280             (RPMSCRIPT_STATE_EXEC | RPMSCRIPT_STATE_REAPED) | (status & 0xffff);
00281 
00282     if (!WIFEXITED(status) || WEXITSTATUS(status)) {
00283         rpmlog(RPMLOG_ERR, _("Bad exit status from %s (%s)\n"),
00284                  scriptName, name);
00285         rc = RPMRC_FAIL;
00286     } else
00287         rc = RPMRC_OK;
00288 
00289     if (op != NULL) {
00290         static unsigned int scale = 1000;
00291         (void) rpmswExit(op, 0);
00292         if (ix >= 0 && ix < RPMSCRIPT_MAX)
00293             spec->smetrics[ix] += op->usecs / scale;
00294     }
00295 
00296 exit:
00297     if (scriptName) {
00298 #if defined(RPM_VENDOR_OPENPKG) /* always-remove-tempfiles */
00299         /* Unconditionally remove temporary files ("rpm-tmp.XXXXX") which
00300            were generated for the executed scripts. In OpenPKG we run the
00301            scripts in debug mode ("set -x") anyway, so we never need to
00302            see the whole generated script -- not even if it breaks.  Instead
00303            we would just have temporary files staying around forever. */
00304 #else
00305         if (rc == RPMRC_OK)
00306 #endif
00307             (void) Unlink(scriptName);
00308         scriptName = _free(scriptName);
00309     }
00310 
00311     switch (urlType(u)) {
00312     case URL_IS_HTTPS:
00313     case URL_IS_HTTP:
00314     case URL_IS_FTP:
00315         delMacro(spec->macros, "_remsh");
00316         delMacro(spec->macros, "_remhost");
00317         if (strcmp(rootDir, "/"))
00318             delMacro(spec->macros, "_remroot");
00319         break;
00320     case URL_IS_UNKNOWN:
00321     case URL_IS_DASH:
00322     case URL_IS_PATH:
00323     case URL_IS_HKP:
00324     default:
00325         break;
00326     }
00327 
00328     argv = _free(argv);
00329     buildCmd = _free(buildCmd);
00330     buildTemplate = _free(buildTemplate);
00331     buildPost = _free(buildPost);
00332     buildDirURL = _free(buildDirURL);
00333     return rc;
00334 }
00335 
00336 rpmRC buildSpec(rpmts ts, Spec spec, int what, int test)
00337 {
00338     rpmRC rc = RPMRC_OK;
00339 
00340     /* Generate a keypair lazily. */
00341     if (spec->dig == NULL)
00342         spec->dig = pgpDigNew(RPMVSF_DEFAULT, PGPPUBKEYALGO_DSA);
00343 
00344     if (!spec->recursing && spec->BACount) {
00345         int x;
00346         /* When iterating over BANames, do the source    */
00347         /* packaging on the first run, and skip RMSOURCE altogether */
00348         if (spec->BASpecs != NULL)
00349         for (x = 0; x < spec->BACount; x++) {
00350             if ((rc = buildSpec(ts, spec->BASpecs[x],
00351                                 (what & ~RPMBUILD_RMSOURCE) |
00352                                 (x ? 0 : (what & RPMBUILD_PACKAGESOURCE)),
00353                                 test))) {
00354                 goto exit;
00355             }
00356         }
00357     } else {
00358         /* support "%track" script/section */
00359         if ((what & RPMBUILD_TRACK) &&
00360             (rc = doScript(spec, RPMBUILD_TRACK, NULL, NULL, test)))
00361                 goto exit;
00362 
00363         if ((what & RPMBUILD_PREP) &&
00364             (rc = doScript(spec, RPMBUILD_PREP, NULL, NULL, test)))
00365                 goto exit;
00366 
00367         if ((what & RPMBUILD_BUILD) &&
00368             (rc = doScript(spec, RPMBUILD_BUILD, NULL, NULL, test)))
00369                 goto exit;
00370 
00371         if ((what & RPMBUILD_INSTALL) &&
00372             (rc = doScript(spec, RPMBUILD_INSTALL, NULL, NULL, test)))
00373                 goto exit;
00374 
00375         if ((what & RPMBUILD_CHECK) &&
00376             (rc = doScript(spec, RPMBUILD_CHECK, NULL, NULL, test)))
00377                 goto exit;
00378 
00379         if ((what & RPMBUILD_PACKAGESOURCE) &&
00380             (rc = processSourceFiles(spec)))
00381                 goto exit;
00382 
00383         if (((what & RPMBUILD_INSTALL) || (what & RPMBUILD_PACKAGEBINARY) ||
00384             (what & RPMBUILD_FILECHECK)) &&
00385             (rc = processBinaryFiles(spec, what & RPMBUILD_INSTALL, test)))
00386                 goto exit;
00387 
00388         if (((what & RPMBUILD_PACKAGESOURCE) && !test) &&
00389             (rc = packageSources(spec)))
00390                 return rc;
00391 
00392         if (((what & RPMBUILD_PACKAGEBINARY) && !test) &&
00393             (rc = packageBinaries(spec)))
00394                 goto exit;
00395         
00396         if ((what & RPMBUILD_CLEAN) &&
00397             (rc = doScript(spec, RPMBUILD_CLEAN, NULL, NULL, test)))
00398                 goto exit;
00399 
00400         if ((what & RPMBUILD_RMBUILD) &&
00401             (rc = doScript(spec, RPMBUILD_RMBUILD, NULL, NULL, test)))
00402                 goto exit;
00403     }
00404 
00405     if (what & RPMBUILD_RMSOURCE)
00406         doRmSource(spec);
00407 
00408     if (what & RPMBUILD_RMSPEC)
00409         (void) Unlink(spec->specFile);
00410 
00411 #if defined(RPM_VENDOR_OPENPKG) /* auto-remove-source-directories */
00412     /* In OpenPKG we use per-package %{_sourcedir} and %{_specdir}
00413        definitions (macros have trailing ".../%{name}"). On removal of
00414        source(s) and .spec file, this per-package directory would be kept
00415        (usually <prefix>/RPM/SRC/<name>/), because RPM does not know about
00416        this OpenPKG convention. So, let RPM try(!) to remove the two
00417        directories (if they are empty) and just ignore removal failures
00418        (if they are still not empty). */
00419     if (what & RPMBUILD_RMSOURCE) {
00420         const char *pn;
00421         pn = rpmGetPath("%{_sourcedir}", NULL);
00422         Rmdir(pn); /* ignore error, it is ok if it fails (usually with ENOTEMPTY) */
00423         pn = _free(pn);
00424     }
00425     if (what & RPMBUILD_RMSPEC) {
00426         const char *pn;
00427         pn = rpmGetPath("%{_specdir}", NULL);
00428         Rmdir(pn); /* ignore error, it is ok if it fails (usually with ENOTEMPTY) */
00429         pn = _free(pn);
00430     }
00431 #endif
00432 
00433 exit:
00434     if (rc != RPMRC_OK && rpmlogGetNrecs() > 0) {
00435         rpmlog(RPMLOG_NOTICE, _("\n\nRPM build errors:\n"));
00436         rpmlogPrint(NULL);
00437     }
00438 
00439     return rc;
00440 }