about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--doc/manual/conf-file.xml15
-rw-r--r--src/libstore/build.cc13
-rw-r--r--src/libstore/globals.cc2
-rw-r--r--src/libstore/globals.hh4
4 files changed, 34 insertions, 0 deletions
diff --git a/doc/manual/conf-file.xml b/doc/manual/conf-file.xml
index c37a2da47413..c832108fed06 100644
--- a/doc/manual/conf-file.xml
+++ b/doc/manual/conf-file.xml
@@ -148,6 +148,7 @@ flag, e.g. <literal>--option gc-keep-outputs false</literal>.</para>
 
   </varlistentry>
 
+
   <varlistentry xml:id="conf-build-timeout"><term><literal>build-timeout</literal></term>
 
     <listitem>
@@ -168,6 +169,20 @@ flag, e.g. <literal>--option gc-keep-outputs false</literal>.</para>
   </varlistentry>
 
 
+  <varlistentry xml:id="conf-build-max-log-size"><term><literal>build-max-log-size</literal></term>
+
+    <listitem>
+
+      <para>This option defines the maximum number of bytes that a
+      builder can write to its stdout/stderr.  If the builder exceeds
+      this limit, it’s killed.  A value of <literal>0</literal> (the
+      default) means that there is no limit.</para>
+
+    </listitem>
+
+  </varlistentry>
+
+
   <varlistentry xml:id="conf-build-users-group"><term><literal>build-users-group</literal></term>
 
     <listitem><para>This options specifies the Unix group containing
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index b5d064e8c60d..25bf848ca697 100644
--- a/src/libstore/build.cc
+++ b/src/libstore/build.cc
@@ -813,6 +813,9 @@ private:
     BZFILE * bzLogFile;
     AutoCloseFD fdLogFile;
 
+    /* Number of bytes received from the builder's stdout/stderr. */
+    unsigned long logSize;
+
     /* Pipe for the builder's standard output/error. */
     Pipe builderOut;
 
@@ -2403,6 +2406,8 @@ string drvsLogDir = "drvs";
 
 Path DerivationGoal::openLogFile()
 {
+    logSize = 0;
+
     if (!settings.keepLog) return "";
 
     string baseName = baseNameOf(drvPath);
@@ -2478,6 +2483,14 @@ void DerivationGoal::handleChildOutput(int fd, const string & data)
     if ((hook && fd == hook->builderOut.readSide) ||
         (!hook && fd == builderOut.readSide))
     {
+        logSize += data.size();
+        if (settings.maxLogSize && logSize > settings.maxLogSize) {
+            printMsg(lvlError,
+                format("%1% killed after writing more than %2% bytes of log output")
+                % getName() % settings.maxLogSize);
+            cancel(true); // not really a timeout, but close enough
+            return;
+        }
         if (verbosity >= settings.buildVerbosity)
             writeToStderr(data);
         if (bzLogFile) {
diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc
index d17bd947d3da..aeb52e1a8696 100644
--- a/src/libstore/globals.cc
+++ b/src/libstore/globals.cc
@@ -46,6 +46,7 @@ Settings::Settings()
     impersonateLinux26 = false;
     keepLog = true;
     compressLog = true;
+    maxLogSize = 0;
     cacheFailure = false;
     pollInterval = 5;
     checkRootReachability = false;
@@ -140,6 +141,7 @@ void Settings::update()
     get(impersonateLinux26, "build-impersonate-linux-26");
     get(keepLog, "build-keep-log");
     get(compressLog, "build-compress-log");
+    get(maxLogSize, "build-max-log-size");
     get(cacheFailure, "build-cache-failure");
     get(pollInterval, "build-poll-interval");
     get(checkRootReachability, "gc-check-reachability");
diff --git a/src/libstore/globals.hh b/src/libstore/globals.hh
index f129d9a11edc..50b61725c742 100644
--- a/src/libstore/globals.hh
+++ b/src/libstore/globals.hh
@@ -153,6 +153,10 @@ struct Settings {
     /* Whether to compress logs. */
     bool compressLog;
 
+    /* Maximum number of bytes a builder can write to stdout/stderr
+       before being killed (0 means no limit). */
+    unsigned long maxLogSize;
+
     /* Whether to cache build failures. */
     bool cacheFailure;