Merge changes I2e432eea,Id7de8f89

* changes:
  Write file list to stdin of next stage in fetch_cvd.
  Implement SharedFD::MemfdCreate.
diff --git a/common/libs/fs/shared_fd.cpp b/common/libs/fs/shared_fd.cpp
index 2f6d100..b85cf7c 100644
--- a/common/libs/fs/shared_fd.cpp
+++ b/common/libs/fs/shared_fd.cpp
@@ -17,6 +17,8 @@
 
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/syscall.h>
 #include <cstddef>
 #include <errno.h>
 #include <fcntl.h>
@@ -52,6 +54,34 @@
     }
   }
 }
+
+/*
+ * Android currently has host prebuilts of glibc 2.15 and 2.17, but
+ * memfd_create was only added in glibc 2.27. It was defined in Linux 3.17,
+ * so we consider it safe to use the low-level arbitrary syscall wrapper.
+ */
+#ifndef __NR_memfd_create
+# if defined(__x86_64__)
+#  define __NR_memfd_create 319
+# elif defined(__i386__)
+#  define __NR_memfd_create 356
+# elif defined(__aarch64__)
+#  define __NR_memfd_create 279
+# else
+/* No interest in other architectures. */
+#  error "Unknown architecture."
+# endif
+#endif
+
+int memfd_create_wrapper(const char* name, unsigned int flags) {
+#ifdef CUTTLEFISH_HOST
+  // TODO(schuffelen): Use memfd_create with a newer host libc.
+  return syscall(__NR_memfd_create, name, flags);
+#else
+  return memfd_create(name, flags);
+#endif
+}
+
 }  // namespace
 
 namespace cvd {
@@ -256,6 +286,12 @@
   return std::shared_ptr<FileInstance>(new FileInstance(fd, errno));
 }
 
+SharedFD SharedFD::MemfdCreate(const char* name, unsigned int flags) {
+  int fd = memfd_create_wrapper(name, flags);
+  int error_num = errno;
+  return std::shared_ptr<FileInstance>(new FileInstance(fd, error_num));
+}
+
 bool SharedFD::SocketPair(int domain, int type, int protocol,
                           SharedFD* fd0, SharedFD* fd1) {
   int fds[2];
diff --git a/common/libs/fs/shared_fd.h b/common/libs/fs/shared_fd.h
index eec17b1..044c7cc 100644
--- a/common/libs/fs/shared_fd.h
+++ b/common/libs/fs/shared_fd.h
@@ -145,6 +145,7 @@
   static bool Pipe(SharedFD* fd0, SharedFD* fd1);
   static SharedFD Event(int initval = 0, int flags = 0);
   static SharedFD Epoll(int flags = 0);
+  static SharedFD MemfdCreate(const char* name, unsigned int flags = 0);
   static bool SocketPair(int domain, int type, int protocol, SharedFD* fd0,
                          SharedFD* fd1);
   static SharedFD Socket(int domain, int socket_type, int protocol);
diff --git a/host/commands/fetcher/fetch_cvd.cc b/host/commands/fetcher/fetch_cvd.cc
index 5e314c8..abaede1 100644
--- a/host/commands/fetcher/fetch_cvd.cc
+++ b/host/commands/fetcher/fetch_cvd.cc
@@ -23,6 +23,7 @@
 #include "gflags/gflags.h"
 #include <glog/logging.h>
 
+#include "common/libs/fs/shared_fd.h"
 #include "common/libs/utils/archive.h"
 #include "common/libs/utils/files.h"
 #include "common/libs/utils/subprocess.h"
@@ -390,15 +391,9 @@
     return 0;
   }
 
-  if (chdir(target_dir.c_str()) != 0) {
-    int error_num = errno;
-    LOG(FATAL) << "Could not change directory to \"" << target_dir << "\"."
-        << "errno was " << error_num << " \"" << strerror(error_num) << "\"";
-  }
-
   // Ignore return code. We want to make sure there is no running instance,
   // and stop_cvd will exit with an error code if there is already no running instance.
-  cvd::Command stop_cmd("bin/stop_cvd");
+  cvd::Command stop_cmd(target_dir + "/bin/stop_cvd");
   stop_cmd.RedirectStdIO(cvd::Subprocess::StdIOChannel::kStdOut,
                          cvd::Subprocess::StdIOChannel::kStdErr);
   stop_cmd.Start().Wait();
@@ -406,9 +401,35 @@
   // gflags::ParseCommandLineFlags will remove fetch_cvd's flags from this.
   // This depends the remove_flags argument (3rd) is "true".
 
+  auto filelist_fd = cvd::SharedFD::MemfdCreate("files_list");
+  if (!filelist_fd->IsOpen()) {
+    LOG(FATAL) << "Unable to create temp file to write file list. "
+               << filelist_fd->StrError() << " (" << filelist_fd->GetErrno() << ")";
+  }
+
+  for (const auto& file : config.get_cvd_files()) {
+    std::string file_entry = file.second.file_path + "\n";
+    auto chars_written = filelist_fd->Write(file_entry.c_str(), file_entry.size());
+    if (chars_written != file_entry.size()) {
+      LOG(FATAL) << "Unable to write entry to file list. Expected to write "
+                 << file_entry.size() << " but wrote " << chars_written << ". "
+                 << filelist_fd->StrError() << " (" << filelist_fd->GetErrno() << ")";
+    }
+  }
+  auto seek_result = filelist_fd->LSeek(0, SEEK_SET);
+  if (seek_result != 0) {
+    LOG(FATAL) << "Unable to seek on file list file. Expected 0, received " << seek_result
+               << filelist_fd->StrError() << " (" << filelist_fd->GetErrno() << ")";
+  }
+
+  if (filelist_fd->UNMANAGED_Dup2(0) == -1) {
+    LOG(FATAL) << "Unable to set file list to stdin. "
+               << filelist_fd->StrError() << " (" << filelist_fd->GetErrno() << ")";
+  }
+
   // TODO(b/139199114): Go into assemble_cvd when the interface is stable and implemented.
 
-  std::string next_stage = "bin/launch_cvd";
+  std::string next_stage = target_dir + "/bin/launch_cvd";
   std::vector<const char*> next_stage_argv = {"launch_cvd"};
   LOG(INFO) << "Running " << next_stage;
   for (int i = 1; i < argc; i++) {