rpm  5.4.4
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     case URL_IS_MONGO:  /* XXX FIXME */
00264     default:
00265         break;
00266     }
00267 
00268     buildCmd = rpmExpand(mCmd, " ", buildScript, NULL);
00269     (void) poptParseArgvString(buildCmd, &argc, &argv);
00270 
00271     if (what != RPMBUILD_TRACK)         /* support "%track" script/section */
00272         rpmlog(RPMLOG_NOTICE, _("Executing(%s): %s\n"), name, buildCmd);
00273 
00274     /* Run the script with a stopwatch. */
00275     if (op != NULL)
00276         (void) rpmswEnter(op, 0);
00277 
00278     status = rpmsqExecve(argv);
00279     if (ix >= 0 && ix < RPMSCRIPT_MAX)
00280         spec->sstates[ix] =
00281             (RPMSCRIPT_STATE_EXEC | RPMSCRIPT_STATE_REAPED) | (status & 0xffff);
00282 
00283     if (!WIFEXITED(status) || WEXITSTATUS(status)) {
00284         rpmlog(RPMLOG_ERR, _("Bad exit status from %s (%s)\n"),
00285                  scriptName, name);
00286         rc = RPMRC_FAIL;
00287     } else
00288         rc = RPMRC_OK;
00289 
00290     if (op != NULL) {
00291         static unsigned int scale = 1000;
00292         (void) rpmswExit(op, 0);
00293         if (ix >= 0 && ix < RPMSCRIPT_MAX)
00294             spec->smetrics[ix] += op->usecs / scale;
00295     }
00296 
00297 exit:
00298     if (scriptName) {
00299 #if defined(RPM_VENDOR_OPENPKG) /* always-remove-tempfiles */
00300         /* Unconditionally remove temporary files ("rpm-tmp.XXXXX") which
00301            were generated for the executed scripts. In OpenPKG we run the
00302            scripts in debug mode ("set -x") anyway, so we never need to
00303            see the whole generated script -- not even if it breaks.  Instead
00304            we would just have temporary files staying around forever. */
00305 #else
00306         if (rc == RPMRC_OK)
00307 #endif
00308             (void) Unlink(scriptName);
00309         scriptName = _free(scriptName);
00310     }
00311 
00312     switch (urlType(u)) {
00313     case URL_IS_HTTPS:
00314     case URL_IS_HTTP:
00315     case URL_IS_FTP:
00316         delMacro(spec->macros, "_remsh");
00317         delMacro(spec->macros, "_remhost");
00318         if (strcmp(rootDir, "/"))
00319             delMacro(spec->macros, "_remroot");
00320         break;
00321     case URL_IS_UNKNOWN:
00322     case URL_IS_DASH:
00323     case URL_IS_PATH:
00324     case URL_IS_HKP:
00325     case URL_IS_MONGO:  /* XXX FIXME */
00326     default:
00327         break;
00328     }
00329 
00330     argv = _free(argv);
00331     buildCmd = _free(buildCmd);
00332     buildTemplate = _free(buildTemplate);
00333     buildPost = _free(buildPost);
00334     buildDirURL = _free(buildDirURL);
00335     return rc;
00336 }
00337 
00338 rpmRC buildSpec(rpmts ts, Spec spec, int what, int test)
00339 {
00340     rpmRC rc = RPMRC_OK;
00341 
00342     /* Generate a keypair lazily. */
00343     if (spec->dig == NULL)
00344         spec->dig = pgpDigNew(RPMVSF_DEFAULT, PGPPUBKEYALGO_DSA);
00345 
00346     if (!spec->recursing && spec->BACount) {
00347         int x;
00348         /* When iterating over BANames, do the source    */
00349         /* packaging on the first run, and skip RMSOURCE altogether */
00350         if (spec->BASpecs != NULL)
00351         for (x = 0; x < spec->BACount; x++) {
00352             if ((rc = buildSpec(ts, spec->BASpecs[x],
00353                                 (what & ~RPMBUILD_RMSOURCE) |
00354                                 (x ? 0 : (what & RPMBUILD_PACKAGESOURCE)),
00355                                 test))) {
00356                 goto exit;
00357             }
00358         }
00359     } else {
00360         /* support "%track" script/section */
00361         if ((what & RPMBUILD_TRACK) &&
00362             (rc = doScript(spec, RPMBUILD_TRACK, NULL, NULL, test)))
00363                 goto exit;
00364 
00365         if ((what & RPMBUILD_PREP) &&
00366             (rc = doScript(spec, RPMBUILD_PREP, NULL, NULL, test)))
00367                 goto exit;
00368 
00369         if ((what & RPMBUILD_BUILD) &&
00370             (rc = doScript(spec, RPMBUILD_BUILD, NULL, NULL, test)))
00371                 goto exit;
00372 
00373         if ((what & RPMBUILD_INSTALL) &&
00374             (rc = doScript(spec, RPMBUILD_INSTALL, NULL, NULL, test)))
00375                 goto exit;
00376 
00377         if ((what & RPMBUILD_CHECK) &&
00378             (rc = doScript(spec, RPMBUILD_CHECK, NULL, NULL, test)))
00379                 goto exit;
00380 
00381         if ((what & RPMBUILD_PACKAGESOURCE) &&
00382             (rc = processSourceFiles(spec)))
00383                 goto exit;
00384 
00385         if (((what & RPMBUILD_INSTALL) || (what & RPMBUILD_PACKAGEBINARY) ||
00386             (what & RPMBUILD_FILECHECK)) &&
00387             (rc = processBinaryFiles(spec, what & RPMBUILD_INSTALL, test)))
00388                 goto exit;
00389 
00390         if (((what & RPMBUILD_PACKAGESOURCE) && !test) &&
00391             (rc = packageSources(spec)))
00392                 return rc;
00393 
00394         if (((what & RPMBUILD_PACKAGEBINARY) && !test) &&
00395             (rc = packageBinaries(spec)))
00396                 goto exit;
00397         
00398         if ((what & RPMBUILD_CLEAN) &&
00399             (rc = doScript(spec, RPMBUILD_CLEAN, NULL, NULL, test)))
00400                 goto exit;
00401 
00402         if ((what & RPMBUILD_RMBUILD) &&
00403             (rc = doScript(spec, RPMBUILD_RMBUILD, NULL, NULL, test)))
00404                 goto exit;
00405     }
00406 
00407     if (what & RPMBUILD_RMSOURCE)
00408         doRmSource(spec);
00409 
00410     if (what & RPMBUILD_RMSPEC)
00411         (void) Unlink(spec->specFile);
00412 
00413 #if defined(RPM_VENDOR_OPENPKG) /* auto-remove-source-directories */
00414     /* In OpenPKG we use per-package %{_sourcedir} and %{_specdir}
00415        definitions (macros have trailing ".../%{name}"). On removal of
00416        source(s) and .spec file, this per-package directory would be kept
00417        (usually <prefix>/RPM/SRC/<name>/), because RPM does not know about
00418        this OpenPKG convention. So, let RPM try(!) to remove the two
00419        directories (if they are empty) and just ignore removal failures
00420        (if they are still not empty). */
00421     if (what & RPMBUILD_RMSOURCE) {
00422         const char *pn;
00423         pn = rpmGetPath("%{_sourcedir}", NULL);
00424         Rmdir(pn); /* ignore error, it is ok if it fails (usually with ENOTEMPTY) */
00425         pn = _free(pn);
00426     }
00427     if (what & RPMBUILD_RMSPEC) {
00428         const char *pn;
00429         pn = rpmGetPath("%{_specdir}", NULL);
00430         Rmdir(pn); /* ignore error, it is ok if it fails (usually with ENOTEMPTY) */
00431         pn = _free(pn);
00432     }
00433 #endif
00434 
00435 exit:
00436     if (rc != RPMRC_OK && rpmlogGetNrecs() > 0) {
00437         rpmlog(RPMLOG_NOTICE, _("\n\nRPM build errors:\n"));
00438         rpmlogPrint(NULL);
00439     }
00440 
00441     return rc;
00442 }