Fix race when extracting the install base when Bazel runs in a PID namespace.

The PID is not a unique identifier in that case and if multiple instances of Bazel tried to extract itself to a shared location at the same time, they occasionally corrupted their temporary extraction directories. This is sometimes the case on CI systems (most notably Bazel's own CI), because a shared install base reduces the overhead of running the integration test suite a lot, as otherwise every test will extract its individual copy of Bazel.

RELNOTES: None.
PiperOrigin-RevId: 291685865
diff --git a/src/main/cpp/blaze.cc b/src/main/cpp/blaze.cc
index 5eb0048..49aecff 100644
--- a/src/main/cpp/blaze.cc
+++ b/src/main/cpp/blaze.cc
@@ -54,6 +54,11 @@
 #include <utility>
 #include <vector>
 
+#if !defined(_WIN32)
+#include <sys/stat.h>
+#include <unistd.h>
+#endif
+
 #include "src/main/cpp/archive_utils.h"
 #include "src/main/cpp/blaze_util.h"
 #include "src/main/cpp/blaze_util_platform.h"
@@ -955,7 +960,29 @@
   if (!blaze_util::PathExists(install_base)) {
     uint64_t st = GetMillisecondsMonotonic();
     // Work in a temp dir to avoid races.
+#if defined(_WIN32)
     string tmp_install = install_base + ".tmp." + blaze::GetProcessIdAsString();
+#else
+    // On Linux, we can't use the PID as a unique identifier, because Bazel
+    // might run in a PID namespace and then all Bazel clients have the same
+    // PID, so we use mkdtemp instead.
+    std::vector<char> tmp_path(install_base.size() + strlen(".tmp.XXXXXX") + 1);
+    strcpy(tmp_path.data(), install_base.c_str());
+    strcat(tmp_path.data(), ".tmp.XXXXXX");
+    if (!blaze_util::MakeDirectories(blaze_util::Dirname(install_base), 0777)) {
+      BAZEL_DIE(blaze_exit_code::INTERNAL_ERROR)
+          << "couldn't create '" << blaze_util::Dirname(install_base)
+          << "': " << blaze_util::GetLastErrorString();
+    }
+    if (mkdtemp(tmp_path.data()) == nullptr) {
+      char *err = strerror(errno);
+      BAZEL_DIE(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR)
+          << "could not create temporary directory to extract install base"
+          << " (" << err << ")";
+    }
+    string tmp_install = tmp_path.data();
+    chmod(tmp_install.c_str(), 0777);
+#endif
     ExtractArchiveOrDie(self_path, startup_options.product_name,
                         expected_install_md5, tmp_install);
     BlessFiles(tmp_install);