sandbox: Easier debugging of sandbox failures, when using both --verbose_failures and --sandbox_debug.
RELNOTES:
- When using both --verbose_failures and --sandbox_debug, Bazel prints instructions how to spawn a debugging shell inside the sandbox.
- When namespace-sandbox is run with the -D (debug) flag and inside a terminal, it spawns a shell inside the sandbox to aid in debugging when the sandboxed command fails.
--
MOS_MIGRATED_REVID=114953983
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/NamespaceSandboxRunner.java b/src/main/java/com/google/devtools/build/lib/sandbox/NamespaceSandboxRunner.java
index ed6f714..c6069bd 100644
--- a/src/main/java/com/google/devtools/build/lib/sandbox/NamespaceSandboxRunner.java
+++ b/src/main/java/com/google/devtools/build/lib/sandbox/NamespaceSandboxRunner.java
@@ -47,6 +47,11 @@
public class NamespaceSandboxRunner {
private static final String NAMESPACE_SANDBOX =
"namespace-sandbox" + OsUtils.executableExtension();
+ private static final String SANDBOX_TIP =
+ "\n\nSandboxed execution failed, which may be legitimate (e.g. a compiler error), "
+ + "or due to missing dependencies. To enter the sandbox environment for easier debugging,"
+ + " run the following command in brackets. On command failure, "
+ + "a bash shell running inside the sandbox will then automatically be spawned\n\n";
private final Path execRoot;
private final Path sandboxPath;
private final Path sandboxExecRoot;
@@ -198,8 +203,9 @@
}
String message =
CommandFailureUtils.describeCommandFailure(
- verboseFailures, spawnArguments, env, cwd.getPath());
- throw new UserExecException(message, e, timedOut);
+ verboseFailures, commandLineArgs, env, cwd.getPath());
+ String finalMsg = (sandboxDebug && verboseFailures) ? SANDBOX_TIP + message : message;
+ throw new UserExecException(finalMsg, e, timedOut);
} finally {
copyOutputs(outputs);
}
@@ -230,7 +236,7 @@
if (sandboxPath.exists()) {
FileSystemUtils.deleteTree(sandboxPath);
}
- if (argumentsFilePath.exists()) {
+ if (!sandboxDebug && argumentsFilePath.exists()) {
argumentsFilePath.delete();
}
}
diff --git a/src/main/tools/namespace-sandbox.c b/src/main/tools/namespace-sandbox.c
index ce81d57..04f1c9c 100644
--- a/src/main/tools/namespace-sandbox.c
+++ b/src/main/tools/namespace-sandbox.c
@@ -16,6 +16,7 @@
#include <errno.h>
#include <fcntl.h>
+#include <ftw.h>
#include <libgen.h>
#include <limits.h>
#include <pwd.h>
@@ -476,7 +477,31 @@
CHECK_CALL(symlink("/proc/self/fd", "dev/fd"));
}
+static int rmrf(const char *fpath, const struct stat *sb, int typeflag,
+ struct FTW *ftwbuf) {
+ if (typeflag == FTW_DP) {
+ return rmdir(fpath);
+ } else {
+ return unlink(fpath);
+ }
+}
+
static void SetupDirectories(struct Options *opt) {
+ // If in sandbox_debug mode and debugging, create the sandbox root dir first
+ if (global_debug && isatty(fileno(stdin))) {
+ // Enter sandbox_debug mode a second time, delete old sandbox
+ struct stat sb;
+ int err = stat(opt->sandbox_root, &sb);
+ if (err == 0) {
+ CHECK_CALL(nftw(opt->sandbox_root, *rmrf, sysconf(_SC_OPEN_MAX),
+ FTW_DEPTH | FTW_PHYS));
+ } else if (errno != ENOENT) {
+ CHECK_CALL(err);
+ }
+
+ CHECK_CALL(mkdir(opt->sandbox_root, 0755));
+ }
+
// Mount the sandbox and go there.
CHECK_CALL(mount(opt->sandbox_root, opt->sandbox_root, NULL,
MS_BIND | MS_NOSUID, NULL));
@@ -653,11 +678,11 @@
// Run the command specified by the argv array and kill it after timeout
// seconds.
-static void SpawnCommand(char *const *argv, double timeout_secs) {
+static void SpawnCommand(char *const *argv, double timeout_secs,
+ bool isFallback) {
for (int i = 0; argv[i] != NULL; i++) {
PRINT_DEBUG("arg: %s\n", argv[i]);
}
-
CHECK_CALL(global_child_pid = fork());
if (global_child_pid == 0) {
// In child.
@@ -691,6 +716,13 @@
UnHandle(global_signal);
raise(global_signal);
} else if (WIFEXITED(status)) {
+ if (global_debug && !isFallback && isatty(fileno(stdin)) &&
+ WEXITSTATUS(status) > 0) {
+ char **cmdList = calloc(2, sizeof(char *));
+ cmdList[0] = "/bin/bash";
+ cmdList[1] = NULL;
+ SpawnCommand(cmdList, 0, true);
+ }
exit(WEXITSTATUS(status));
} else {
int sig = WTERMSIG(status);
@@ -749,7 +781,7 @@
}
ChangeRoot(&opt);
- SpawnCommand(opt.args, opt.timeout_secs);
+ SpawnCommand(opt.args, opt.timeout_secs, false);
free(opt.create_dirs);
free(opt.mount_sources);