Permit file objects in python header constructor
[platform/upstream/rpm.git] / build / build.c
index f1b9d42..a4a271a 100644 (file)
+/** \ingroup rpmbuild
+ * \file build/build.c
+ *  Top-level build dispatcher.
+ */
+
 #include "system.h"
 
-#include <rpmbuild.h>
-#include <rpmurl.h>
+#include <rpm/rpmbuild.h>
+#include <rpm/rpmlog.h>
+#include <rpm/rpmfileutil.h>
+
+#include "debug.h"
 
-static void doRmSource(Spec spec)
+static int _build_debug = 0;
+
+/**
+ */
+rpmRC doRmSource(rpmSpec spec)
 {
     struct Source *p;
     Package pkg;
+    int rc = 0;
     
-#if 0
-    unlink(spec->specFile);
-#endif
-
     for (p = spec->sources; p != NULL; p = p->next) {
        if (! (p->flags & RPMBUILD_ISNO)) {
-           const char *fn = rpmGetPath("%{_sourcedir}/", p->source, NULL);
-           unlink(fn);
-           xfree(fn);
+           char *fn = rpmGetPath("%{_sourcedir}/", p->source, NULL);
+           rc = unlink(fn);
+           fn = _free(fn);
+           if (rc) goto exit;
        }
     }
 
     for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
        for (p = pkg->icon; p != NULL; p = p->next) {
            if (! (p->flags & RPMBUILD_ISNO)) {
-               const char *fn = rpmGetPath("%{_sourcedir}/", p->source, NULL);
-               unlink(fn);
-               xfree(fn);
+               char *fn = rpmGetPath("%{_sourcedir}/", p->source, NULL);
+               rc = unlink(fn);
+               fn = _free(fn);
+               if (rc) goto exit;
            }
        }
     }
+exit:
+    return !rc ? RPMRC_OK : RPMRC_FAIL;
 }
 
 /*
- * The _preScript string is expanded to export values to a script environment.
+ * @todo Single use by %%doc in files.c prevents static.
  */
-
-static char *_preScriptEnvironment = "%{_preScriptEnvironment}";
-
-static char *_preScriptChdir = 
-       "umask 022\n"
-       "cd %{_builddir}\n"
-;
-
-int doScript(Spec spec, int what, const char *name, StringBuf sb, int test)
+rpmRC doScript(rpmSpec spec, rpmBuildFlags what, const char *name, StringBuf sb, int test)
 {
+    const char * rootDir = spec->rootDir;
+    char *scriptName = NULL;
+    char * buildDir = rpmGenPath(rootDir, "%{_builddir}", "");
+    char * buildCmd = NULL;
+    char * buildTemplate = NULL;
+    char * buildPost = NULL;
+    const char * mTemplate = NULL;
+    const char * mCmd = NULL;
+    const char * mPost = NULL;
+    int argc = 0;
+    const char **argv = NULL;
+    FILE * fp = NULL;
+
     FD_t fd;
     FD_t xfd;
-    const char *scriptName;
-    int pid;
+    pid_t pid;
+    pid_t child;
     int status;
-    char buf[BUFSIZ];
+    rpmRC rc;
     
     switch (what) {
-      case RPMBUILD_PREP:
+    case RPMBUILD_PREP:
        name = "%prep";
        sb = spec->prep;
+       mTemplate = "%{__spec_prep_template}";
+       mPost = "%{__spec_prep_post}";
+       mCmd = "%{__spec_prep_cmd}";
        break;
-      case RPMBUILD_BUILD:
+    case RPMBUILD_BUILD:
        name = "%build";
        sb = spec->build;
+       mTemplate = "%{__spec_build_template}";
+       mPost = "%{__spec_build_post}";
+       mCmd = "%{__spec_build_cmd}";
        break;
-      case RPMBUILD_INSTALL:
+    case RPMBUILD_INSTALL:
        name = "%install";
        sb = spec->install;
+       mTemplate = "%{__spec_install_template}";
+       mPost = "%{__spec_install_post}";
+       mCmd = "%{__spec_install_cmd}";
+       break;
+    case RPMBUILD_CHECK:
+       name = "%check";
+       sb = spec->check;
+       mTemplate = "%{__spec_check_template}";
+       mPost = "%{__spec_check_post}";
+       mCmd = "%{__spec_check_cmd}";
        break;
-      case RPMBUILD_CLEAN:
+    case RPMBUILD_CLEAN:
        name = "%clean";
        sb = spec->clean;
+       mTemplate = "%{__spec_clean_template}";
+       mPost = "%{__spec_clean_post}";
+       mCmd = "%{__spec_clean_cmd}";
        break;
-      case RPMBUILD_RMBUILD:
+    case RPMBUILD_RMBUILD:
        name = "--clean";
+       mTemplate = "%{__spec_clean_template}";
+       mPost = "%{__spec_clean_post}";
+       mCmd = "%{__spec_clean_cmd}";
        break;
-      case RPMBUILD_STRINGBUF:
+    case RPMBUILD_STRINGBUF:
+    default:
+       mTemplate = "%{___build_template}";
+       mPost = "%{___build_post}";
+       mCmd = "%{___build_cmd}";
        break;
     }
+    if (name == NULL)  /* XXX shouldn't happen */
+       name = "???";
 
-    if ((what != RPMBUILD_RMBUILD) && sb == NULL)
-       return 0;
+    if ((what != RPMBUILD_RMBUILD) && sb == NULL) {
+       rc = RPMRC_OK;
+       goto exit;
+    }
     
-    if (makeTempFile(spec->rootdir, &scriptName, &fd)) {
-           Fclose(fd);
-           FREE(scriptName);
-           rpmError(RPMERR_SCRIPT, _("Unable to open temp file"));
-           return RPMERR_SCRIPT;
+    fd = rpmMkTempFile(rootDir, &scriptName);
+    if (fd == NULL || Ferror(fd)) {
+       rpmlog(RPMLOG_ERR, _("Unable to open temp file.\n"));
+       rc = RPMRC_FAIL;
+       goto exit;
+    }
+
+    if (fdGetFILE(fd) == NULL)
+       xfd = Fdopen(fd, "w.fpio");
+    else
+       xfd = fd;
+
+    if ((fp = fdGetFILE(xfd)) == NULL) {
+       rc = RPMRC_FAIL;
+       goto exit;
     }
-#ifdef HAVE_FCHMOD
-    (void)fchmod(Fileno(fd), 0600);    /* XXX fubar on ufdio */
-#endif
-/* XXX FIXME: build/build.c Fdopen assertion failure, makeTempFile uses fdio */
-    xfd = Fdopen(fd, "w.fdio");
     
-    strcpy(buf, _preScriptEnvironment);
-    expandMacros(spec, spec->macros, buf, sizeof(buf));
-    strcat(buf, "\n");
-    fputs(buf, fpio->ffileno(xfd));
+    if (*rootDir == '\0') rootDir = "/";
 
-    fprintf(fpio->ffileno(xfd), rpmIsVerbose() ? "set -x\n\n" : "exec > /dev/null\n\n");
+    buildTemplate = rpmExpand(mTemplate, NULL);
+    buildPost = rpmExpand(mPost, NULL);
 
-/* XXX umask 022; cd %{_builddir} */
-    strcpy(buf, _preScriptChdir);
-    expandMacros(spec, spec->macros, buf, sizeof(buf));
-    fputs(buf, fpio->ffileno(xfd));
+    (void) fputs(buildTemplate, fp);
+
+    if (what != RPMBUILD_PREP && what != RPMBUILD_RMBUILD && spec->buildSubdir)
+       fprintf(fp, "cd '%s'\n", spec->buildSubdir);
 
-    if (what != RPMBUILD_PREP && what != RPMBUILD_RMBUILD) {
-       if (spec->buildSubdir)
-           fprintf(fpio->ffileno(xfd), "cd %s\n", spec->buildSubdir);
-    }
     if (what == RPMBUILD_RMBUILD) {
        if (spec->buildSubdir)
-           fprintf(fpio->ffileno(xfd), "rm -rf %s\n", spec->buildSubdir);
-    } else
-       fprintf(fpio->ffileno(xfd), "%s", getStringBuf(sb));
-    fprintf(fpio->ffileno(xfd), "\nexit 0\n");
+           fprintf(fp, "rm -rf '%s'\n", spec->buildSubdir);
+    } else if (sb != NULL)
+       fprintf(fp, "%s", getStringBuf(sb));
+
+    (void) fputs(buildPost, fp);
     
-    Fclose(xfd);
+    (void) Fclose(xfd);
 
     if (test) {
-       FREE(scriptName);
-       return 0;
+       rc = RPMRC_OK;
+       goto exit;
     }
     
-    rpmMessage(RPMMESS_NORMAL, _("Executing: %s\n"), name);
-    if (!(pid = fork())) {
-       const char *buildShell = rpmGetPath("%{_buildshell}", NULL);
-
-       if (spec->rootdir)
-           Chroot(spec->rootdir);
-       chdir("/");
-
-       switch (urlIsURL(scriptName)) {
-       case URL_IS_PATH:
-           scriptName += sizeof("file://") - 1;
-           scriptName = strchr(scriptName, '/');
-           /*@fallthrough@*/
-       case URL_IS_UNKNOWN:
-           execl(buildShell, buildShell, "-e", scriptName, scriptName, NULL);
-           break;
-       default:
-           break;
-       }
+if (_build_debug)
+fprintf(stderr, "*** rootDir %s buildDir %s\n", rootDir, buildDir);
+    if (buildDir && buildDir[0] != '/') {
+       rc = RPMRC_FAIL;
+       goto exit;
+    }
+
+    buildCmd = rpmExpand(mCmd, " ", scriptName, NULL);
+    (void) poptParseArgvString(buildCmd, &argc, &argv);
+
+    rpmlog(RPMLOG_NOTICE, _("Executing(%s): %s\n"), name, buildCmd);
+    if (!(child = fork())) {
 
-       rpmError(RPMERR_SCRIPT, _("Exec of %s failed (%s)"), scriptName, name);
-       _exit(-1);
+       errno = 0;
+       (void) execvp(argv[0], (char *const *)argv);
+
+       rpmlog(RPMLOG_ERR, _("Exec of %s failed (%s): %s\n"),
+               scriptName, name, strerror(errno));
+
+       _exit(127); /* exit 127 for compatibility with bash(1) */
     }
 
-    (void)wait(&status);
-    if (! WIFEXITED(status) || WEXITSTATUS(status)) {
-       rpmError(RPMERR_SCRIPT, _("Bad exit status from %s (%s)"),
+    pid = waitpid(child, &status, 0);
+
+    if (!WIFEXITED(status) || WEXITSTATUS(status)) {
+       rpmlog(RPMLOG_ERR, _("Bad exit status from %s (%s)\n"),
                 scriptName, name);
-#if HACK
-       Unlink(scriptName);
-#endif
-       FREE(scriptName);
-       return RPMERR_SCRIPT;
-    }
+       rc = RPMRC_FAIL;
+    } else
+       rc = RPMRC_OK;
     
-    Unlink(scriptName);
-    FREE(scriptName);
+exit:
+    if (scriptName) {
+       if (rc == RPMRC_OK)
+           (void) unlink(scriptName);
+       scriptName = _free(scriptName);
+    }
+    argv = _free(argv);
+    buildCmd = _free(buildCmd);
+    buildTemplate = _free(buildTemplate);
+    buildPost = _free(buildPost);
+    buildDir = _free(buildDir);
 
-    return 0;
+    return rc;
 }
 
-int buildSpec(Spec spec, int what, int test)
+rpmRC buildSpec(rpmts ts, rpmSpec spec, int what, int test)
 {
-    int x, rc;
+    rpmRC rc = RPMRC_OK;
 
-    if (!spec->inBuildArchitectures && spec->buildArchitectureCount) {
-       /* When iterating over buildArchitectures, do the source    */
+    if (!spec->recursing && spec->BACount) {
+       int x;
+       /* When iterating over BANames, do the source    */
        /* packaging on the first run, and skip RMSOURCE altogether */
-       for (x = 0; x < spec->buildArchitectureCount; x++) {
-           if ((rc = buildSpec(spec->buildArchitectureSpecs[x],
+       if (spec->BASpecs != NULL)
+       for (x = 0; x < spec->BACount; x++) {
+           if ((rc = buildSpec(ts, spec->BASpecs[x],
                                (what & ~RPMBUILD_RMSOURCE) |
                                (x ? 0 : (what & RPMBUILD_PACKAGESOURCE)),
                                test))) {
-               return rc;
+               goto exit;
            }
        }
     } else {
        if ((what & RPMBUILD_PREP) &&
            (rc = doScript(spec, RPMBUILD_PREP, NULL, NULL, test)))
-               return rc;
+               goto exit;
 
        if ((what & RPMBUILD_BUILD) &&
            (rc = doScript(spec, RPMBUILD_BUILD, NULL, NULL, test)))
-               return rc;
+               goto exit;
 
        if ((what & RPMBUILD_INSTALL) &&
            (rc = doScript(spec, RPMBUILD_INSTALL, NULL, NULL, test)))
-               return rc;
+               goto exit;
+
+       if ((what & RPMBUILD_CHECK) &&
+           (rc = doScript(spec, RPMBUILD_CHECK, NULL, NULL, test)))
+               goto exit;
 
        if ((what & RPMBUILD_PACKAGESOURCE) &&
            (rc = processSourceFiles(spec)))
-               return rc;
+               goto exit;
 
        if (((what & RPMBUILD_INSTALL) || (what & RPMBUILD_PACKAGEBINARY) ||
            (what & RPMBUILD_FILECHECK)) &&
            (rc = processBinaryFiles(spec, what & RPMBUILD_INSTALL, test)))
-               return rc;
+               goto exit;
 
        if (((what & RPMBUILD_PACKAGESOURCE) && !test) &&
            (rc = packageSources(spec)))
@@ -204,22 +263,28 @@ int buildSpec(Spec spec, int what, int test)
 
        if (((what & RPMBUILD_PACKAGEBINARY) && !test) &&
            (rc = packageBinaries(spec)))
-               return rc;
+               goto exit;
        
        if ((what & RPMBUILD_CLEAN) &&
            (rc = doScript(spec, RPMBUILD_CLEAN, NULL, NULL, test)))
-               return rc;
+               goto exit;
 
        if ((what & RPMBUILD_RMBUILD) &&
            (rc = doScript(spec, RPMBUILD_RMBUILD, NULL, NULL, test)))
-               return rc;
+               goto exit;
     }
 
     if (what & RPMBUILD_RMSOURCE)
        doRmSource(spec);
 
     if (what & RPMBUILD_RMSPEC)
-       unlink(spec->specFile);
+       (void) unlink(spec->specFile);
+
+exit:
+    if (rc != RPMRC_OK && rpmlogGetNrecs() > 0) {
+       rpmlog(RPMLOG_NOTICE, _("\n\nRPM build errors:\n"));
+       rpmlogPrint(NULL);
+    }
 
-    return 0;
+    return rc;
 }