AU: Changes for deltas on traditional bios machines.

BUG=None
TEST=Attached unittests/tested on image

- Fix uninitialized variable err in action processor unittest

- Let Omaha dictate if an update is a delta or full update

- Bug fix in delta generator for differently-sized images

- More logging when applying delta updates

- Fix infinite loop in http fetcher unittest

- log each HTTP connection to know when a dropped connection is
  reestablished.

- Detect when speed goes below a threshold and reestablish HTTP
  connection (currently < 10bytes/sec for 90 contiguous seconds).

- Fix stack overflow in libcurl http fetcher.

- optimize out a lot of needless CPU usage in libcurl http fetcher
  (turns out adding a glib main loop source uses a lot of CPU).

- subprocess: pass PATH, log stdout/stderr

- postinstall runner: support for ext3 and ext4 target filesystems.

Review URL: http://codereview.chromium.org/2805027
diff --git a/libcurl_http_fetcher.cc b/libcurl_http_fetcher.cc
index 9ed0c64..7a032fe 100644
--- a/libcurl_http_fetcher.cc
+++ b/libcurl_http_fetcher.cc
@@ -19,6 +19,7 @@
 }
 
 void LibcurlHttpFetcher::ResumeTransfer(const std::string& url) {
+  LOG(INFO) << "Starting/Resuming transfer";
   CHECK(!transfer_in_progress_);
   url_ = url;
   curl_multi_handle_ = curl_multi_init();
@@ -49,9 +50,15 @@
   CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_WRITEFUNCTION,
                             StaticLibcurlWrite), CURLE_OK);
   CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_URL, url_.c_str()), CURLE_OK);
+
+  // If the connection drops under 10 bytes/sec for 90 seconds, reconnect.
+  CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_LOW_SPEED_LIMIT, 10),
+           CURLE_OK);
+  CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_LOW_SPEED_TIME, 90),
+           CURLE_OK);
+
   CHECK_EQ(curl_multi_add_handle(curl_multi_handle_, curl_handle_), CURLM_OK);
   transfer_in_progress_ = true;
-  CurlPerformOnce();
 }
 
 // Begins the transfer, which must not have already been started.
@@ -59,15 +66,16 @@
   transfer_size_ = -1;
   bytes_downloaded_ = 0;
   resume_offset_ = 0;
-  ResumeTransfer(url);
+  do {
+    ResumeTransfer(url);
+  } while (CurlPerformOnce());
 }
 
 void LibcurlHttpFetcher::TerminateTransfer() {
   CleanUp();
 }
 
-// TODO(adlr): detect network failures
-void LibcurlHttpFetcher::CurlPerformOnce() {
+bool LibcurlHttpFetcher::CurlPerformOnce() {
   CHECK(transfer_in_progress_);
   int running_handles = 0;
   CURLMcode retcode = CURLM_CALL_MULTI_PERFORM;
@@ -82,7 +90,8 @@
     CleanUp();
 
     if ((transfer_size_ >= 0) && (bytes_downloaded_ < transfer_size_)) {
-      ResumeTransfer(url_);
+      // Need to restart transfer
+      return true;
     } else {
       if (delegate_) {
         delegate_->TransferComplete(this, true);  // success
@@ -92,6 +101,7 @@
     // set up callback
     SetupMainloopSources();
   }
+  return false;
 }
 
 size_t LibcurlHttpFetcher::LibcurlWrite(void *ptr, size_t size, size_t nmemb) {
@@ -163,7 +173,6 @@
     // If we are already tracking this fd, continue.
     if (io_channels_.find(i) != io_channels_.end())
       continue;
-
     // We must track a new fd
     GIOChannel *io_channel = g_io_channel_unix_new(i);
     guint tag = g_io_add_watch(
@@ -173,6 +182,11 @@
         &StaticFDCallback,
         this);
     io_channels_[i] = make_pair(io_channel, tag);
+    static int io_counter = 0;
+    io_counter++;
+    if (io_counter % 50 == 0) {
+      LOG(INFO) << "io_counter = " << io_counter;
+    }
   }
 
   // Wet up a timeout callback for libcurl
@@ -186,51 +200,46 @@
     //     curl_multi_perform() again.
     ms = idle_ms_;
   }
-  if (timeout_source_) {
-    g_source_destroy(timeout_source_);
-    timeout_source_ = NULL;
+  if (!timeout_source_) {
+    LOG(INFO) << "setting up timeout source:" << ms;
+    timeout_source_ = g_timeout_source_new(1000);
+    CHECK(timeout_source_);
+    g_source_set_callback(timeout_source_, StaticTimeoutCallback, this,
+                          NULL);
+    g_source_attach(timeout_source_, NULL);
+    static int counter = 0;
+    counter++;
+    if (counter % 50 == 0) {
+      LOG(INFO) << "counter = " << counter;
+    }
   }
-  timeout_source_ = g_timeout_source_new(ms);
-  CHECK(timeout_source_);
-  g_source_set_callback(timeout_source_, StaticTimeoutCallback, this,
-                        NULL);
-  g_source_attach(timeout_source_, NULL);
 }
 
 bool LibcurlHttpFetcher::FDCallback(GIOChannel *source,
                                     GIOCondition condition) {
-  // Figure out which source it was; hopefully there aren't too many b/c
-  // this is a linear scan of our channels
-  bool found_in_set = false;
-  for (IOChannels::iterator it = io_channels_.begin();
-       it != io_channels_.end(); ++it) {
-    if (it->second.first == source) {
-      // We will return false from this method, meaning that we shouldn't keep
-      // this g_io_channel around. So we remove it now from our collection of
-      // g_io_channels so that the other code in this class doens't mess with
-      // this (doomed) GIOChannel.
-      // TODO(adlr): optimize by seeing if we should reuse this GIOChannel
-      g_source_remove(it->second.second);
-      g_io_channel_unref(it->second.first);
-      io_channels_.erase(it);
-      found_in_set = true;
-      break;
-    }
+  while (CurlPerformOnce()) {
+    ResumeTransfer(url_);
   }
-  CHECK(found_in_set);
-  CurlPerformOnce();
-  return false;
+  // We handle removing of this source elsewhere, so we always return true.
+  // The docs say, "the function should return FALSE if the event source
+  // should be removed."
+  // http://www.gtk.org/api/2.6/glib/glib-IO-Channels.html#GIOFunc
+  return true;
 }
 
-bool LibcurlHttpFetcher::TimeoutCallback() {
+gboolean LibcurlHttpFetcher::TimeoutCallback() {
+  if (!transfer_in_progress_)
+    return TRUE;
   // Since we will return false from this function, which tells glib to
   // destroy the timeout callback, we must NULL it out here. This way, when
   // setting up callback sources again, we won't try to delete this (doomed)
   // timeout callback then.
   // TODO(adlr): optimize by checking if we can keep this timeout callback.
-  timeout_source_ = NULL;
-  CurlPerformOnce();
-  return false;
+  //timeout_source_ = NULL;
+  while (CurlPerformOnce()) {
+    ResumeTransfer(url_);
+  }
+  return TRUE;
 }
 
 void LibcurlHttpFetcher::CleanUp() {