Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions source/bear/man/bear.1
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ Force to use the dynamic linker method of \f[C]intercept\f[R] command.
.TP
--force-wrapper
Force to use the compiler wrapper method of \f[C]intercept\f[R] command.
.TP
--enable-network-proxy
Forward HTTP proxy environment variables (\f[C]http_proxy\f[R],
\f[C]https_proxy\f[R], \f[C]grpc_proxy\f[R] and their capitalized
versions) to \f[C]intercept\f[R] command.
They are unset by default.
.SH COMMANDS
.TP
\f[B]\f[CB]bear-intercept(1)\f[B]\f[R]
Expand Down
5 changes: 5 additions & 0 deletions source/bear/man/bear.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ compilation database.
\--force-wrapper
: Force to use the compiler wrapper method of `intercept` command.

\--enable-network-proxy
: Forward HTTP proxy environment variables (`http_proxy`, `https_proxy`,
`grpc_proxy` and their capitalized versions) to `intercept` command.
They are unset by default.

# COMMANDS

`bear-intercept(1)`
Expand Down
48 changes: 30 additions & 18 deletions source/bear/source/Application.cc
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,11 @@ namespace {
auto verbose = arguments.as_bool(flags::VERBOSE).unwrap_or(false);
auto force_wrapper = arguments.as_bool(cmd::intercept::FLAG_FORCE_WRAPPER).unwrap_or(false);
auto force_preload = arguments.as_bool(cmd::intercept::FLAG_FORCE_PRELOAD).unwrap_or(false);
auto enable_network_proxy = arguments.as_bool(cmd::intercept::FLAG_ENABLE_NETWORK_PROXY).unwrap_or(false);

return rust::merge(program, command, rust::merge(library, wrapper, wrapper_dir))
.map<sys::Process::Builder>(
[&environment, &output, &verbose, &force_wrapper, &force_preload](auto tuple) {
[&environment, &output, &verbose, &force_wrapper, &force_preload, &enable_network_proxy](auto tuple) {
const auto&[program, command, pack] = tuple;
const auto&[library, wrapper, wrapper_dir] = pack;

Expand All @@ -57,6 +58,9 @@ namespace {
if (force_preload) {
builder.add_argument(cmd::intercept::FLAG_FORCE_PRELOAD);
}
if (enable_network_proxy) {
builder.add_argument(cmd::intercept::FLAG_ENABLE_NETWORK_PROXY);
}
if (verbose) {
builder.add_argument(flags::VERBOSE);
}
Expand Down Expand Up @@ -146,13 +150,14 @@ namespace bear {
rust::Result<flags::Arguments> Application::parse(int argc, const char **argv) const
{
const flags::Parser intercept_parser("intercept", cmd::VERSION, {
{cmd::intercept::FLAG_OUTPUT, {1, false, "path of the result file", {cmd::intercept::DEFAULT_OUTPUT}, std::nullopt}},
{cmd::intercept::FLAG_FORCE_PRELOAD, {0, false, "force to use library preload", std::nullopt, DEVELOPER_GROUP}},
{cmd::intercept::FLAG_FORCE_WRAPPER, {0, false, "force to use compiler wrappers", std::nullopt, DEVELOPER_GROUP}},
{cmd::intercept::FLAG_LIBRARY, {1, false, "path to the preload library", {cmd::library::DEFAULT_PATH}, DEVELOPER_GROUP}},
{cmd::intercept::FLAG_WRAPPER, {1, false, "path to the wrapper executable", {cmd::wrapper::DEFAULT_PATH}, DEVELOPER_GROUP}},
{cmd::intercept::FLAG_WRAPPER_DIR, {1, false, "path to the wrapper directory", {cmd::wrapper::DEFAULT_DIR_PATH}, DEVELOPER_GROUP}},
{cmd::intercept::FLAG_COMMAND, {-1, true, "command to execute", std::nullopt, std::nullopt}}
{cmd::intercept::FLAG_OUTPUT, {1, false, "path of the result file", {cmd::intercept::DEFAULT_OUTPUT}, std::nullopt}},
{cmd::intercept::FLAG_FORCE_PRELOAD, {0, false, "force to use library preload", std::nullopt, DEVELOPER_GROUP}},
{cmd::intercept::FLAG_FORCE_WRAPPER, {0, false, "force to use compiler wrappers", std::nullopt, DEVELOPER_GROUP}},
{cmd::intercept::FLAG_ENABLE_NETWORK_PROXY, {0, false, "enable http and https proxy", std::nullopt, DEVELOPER_GROUP}},
{cmd::intercept::FLAG_LIBRARY, {1, false, "path to the preload library", {cmd::library::DEFAULT_PATH}, DEVELOPER_GROUP}},
{cmd::intercept::FLAG_WRAPPER, {1, false, "path to the wrapper executable", {cmd::wrapper::DEFAULT_PATH}, DEVELOPER_GROUP}},
{cmd::intercept::FLAG_WRAPPER_DIR, {1, false, "path to the wrapper directory", {cmd::wrapper::DEFAULT_DIR_PATH}, DEVELOPER_GROUP}},
{cmd::intercept::FLAG_COMMAND, {-1, true, "command to execute", std::nullopt, std::nullopt}}
});

const flags::Parser citnames_parser("citnames", cmd::VERSION, {
Expand All @@ -164,16 +169,17 @@ namespace bear {
});

const flags::Parser parser("bear", cmd::VERSION, {intercept_parser, citnames_parser}, {
{cmd::citnames::FLAG_OUTPUT, {1, false, "path of the result file", {cmd::citnames::DEFAULT_OUTPUT}, std::nullopt}},
{cmd::citnames::FLAG_APPEND, {0, false, "append result to an existing output file", std::nullopt, ADVANCED_GROUP}},
{cmd::citnames::FLAG_CONFIG, {1, false, "path of the config file", std::nullopt, ADVANCED_GROUP}},
{cmd::intercept::FLAG_FORCE_PRELOAD, {0, false, "force to use library preload", std::nullopt, ADVANCED_GROUP}},
{cmd::intercept::FLAG_FORCE_WRAPPER, {0, false, "force to use compiler wrappers", std::nullopt, ADVANCED_GROUP}},
{cmd::bear::FLAG_BEAR, {1, false, "path to the bear executable", {cmd::bear::DEFAULT_PATH}, DEVELOPER_GROUP}},
{cmd::intercept::FLAG_LIBRARY, {1, false, "path to the preload library", {cmd::library::DEFAULT_PATH}, DEVELOPER_GROUP}},
{cmd::intercept::FLAG_WRAPPER, {1, false, "path to the wrapper executable", {cmd::wrapper::DEFAULT_PATH}, DEVELOPER_GROUP}},
{cmd::intercept::FLAG_WRAPPER_DIR, {1, false, "path to the wrapper directory", {cmd::wrapper::DEFAULT_DIR_PATH}, DEVELOPER_GROUP}},
{cmd::intercept::FLAG_COMMAND, {-1, true, "command to execute", std::nullopt, std::nullopt}}
{cmd::citnames::FLAG_OUTPUT, {1, false, "path of the result file", {cmd::citnames::DEFAULT_OUTPUT}, std::nullopt}},
{cmd::citnames::FLAG_APPEND, {0, false, "append result to an existing output file", std::nullopt, ADVANCED_GROUP}},
{cmd::citnames::FLAG_CONFIG, {1, false, "path of the config file", std::nullopt, ADVANCED_GROUP}},
{cmd::intercept::FLAG_FORCE_PRELOAD, {0, false, "force to use library preload", std::nullopt, ADVANCED_GROUP}},
{cmd::intercept::FLAG_FORCE_WRAPPER, {0, false, "force to use compiler wrappers", std::nullopt, ADVANCED_GROUP}},
{cmd::intercept::FLAG_ENABLE_NETWORK_PROXY, {0, false, "enable http and https proxy", std::nullopt, ADVANCED_GROUP}},
{cmd::bear::FLAG_BEAR, {1, false, "path to the bear executable", {cmd::bear::DEFAULT_PATH}, DEVELOPER_GROUP}},
{cmd::intercept::FLAG_LIBRARY, {1, false, "path to the preload library", {cmd::library::DEFAULT_PATH}, DEVELOPER_GROUP}},
{cmd::intercept::FLAG_WRAPPER, {1, false, "path to the wrapper executable", {cmd::wrapper::DEFAULT_PATH}, DEVELOPER_GROUP}},
{cmd::intercept::FLAG_WRAPPER_DIR, {1, false, "path to the wrapper directory", {cmd::wrapper::DEFAULT_DIR_PATH}, DEVELOPER_GROUP}},
{cmd::intercept::FLAG_COMMAND, {-1, true, "command to execute", std::nullopt, std::nullopt}}
});
return parser.parse_or_exit(argc, const_cast<const char **>(argv));
}
Expand All @@ -186,6 +192,12 @@ namespace bear {
return citnames.subcommand(args, envp);
}
if (auto intercept = ic::Intercept(log_config_); intercept.matches(args)) {
// Network proxy is disabled by default unless user explicitly enables it
if (!args.as_bool(cmd::intercept::FLAG_ENABLE_NETWORK_PROXY).unwrap_or(false)) {
for (auto proxyEnv : cmd::intercept::PROXY_ENV_VARS) {
unsetenv(proxyEnv);
}
}
return intercept.subcommand(args, envp);
}
return rust::Err(std::runtime_error("Invalid subcommand"));
Expand Down
2 changes: 2 additions & 0 deletions source/config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ namespace cmd {
constexpr char FLAG_COMMAND[] = "--";
constexpr char FLAG_FORCE_WRAPPER[] = "--force-wrapper";
constexpr char FLAG_FORCE_PRELOAD[] = "--force-preload";
constexpr char FLAG_ENABLE_NETWORK_PROXY[] = "--enable-network-proxy";
constexpr const char* PROXY_ENV_VARS[] = {"http_proxy", "https_proxy", "grpc_proxy","all_proxy", "HTTP_PROXY", "HTTPS_PROXY", "GRPC_PROXY", "ALL_PROXY"};

constexpr char DEFAULT_OUTPUT[] = "events.json";
}
Expand Down
4 changes: 2 additions & 2 deletions source/libflags/source/Flags.cc
Original file line number Diff line number Diff line change
Expand Up @@ -110,11 +110,11 @@ namespace {
// print flag name
os << flag_name;
// decide if the help text goes into the same line or not
if (flag_size > 22) {
if (flag_size > 25) {
os << std::endl
<< std::string(15, ' ');
} else {
os << std::string(23 - flag_size, ' ');
os << std::string(26 - flag_size, ' ');
}
os << option.help;
// print default value if exists
Expand Down
22 changes: 11 additions & 11 deletions source/libflags/test/FlagsTest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -177,16 +177,16 @@ namespace {
const char *expected =
"Usage: test [--flag] [--option <arg>] [--options <arg0> <arg1> <arg2>] [--verbose] [-- ...]\n"
"\n"
" --flag a single flag\n"
" --option <arg> a flag with a value\n"
" --flag a single flag\n"
" --option <arg> a flag with a value\n"
" --options <arg0> <arg1> <arg2>\n"
" a flag with 3 values\n"
" --verbose run in verbose mode\n"
" -- ... rest of the arguments\n"
" --verbose run in verbose mode\n"
" -- ... rest of the arguments\n"
"\n"
"query options\n"
" --help print help and exit\n"
" --version print version and exit\n";
" --help print help and exit\n"
" --version print version and exit\n";

std::ostringstream out;
sut.print_help(nullptr, out);
Expand Down Expand Up @@ -367,8 +367,8 @@ namespace {
" dump\n"
"\n"
"query options\n"
" --help print help and exit\n"
" --version print version and exit\n";
" --help print help and exit\n"
" --version print version and exit\n";

std::ostringstream out;
sut.print_help(nullptr, out);
Expand All @@ -378,11 +378,11 @@ namespace {
const char *expected =
"Usage: test append [--option <arg>] [--verbose]\n"
"\n"
" --option <arg> a flag with a value\n"
" --verbose run in verbose mode\n"
" --option <arg> a flag with a value\n"
" --verbose run in verbose mode\n"
"\n"
"query options\n"
" --help print help and exit\n";
" --help print help and exit\n";

std::ostringstream out;
sut.print_help(&append, out);
Expand Down
25 changes: 25 additions & 0 deletions test/cases/intercept/wrapper/shell_enable_network_proxy.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/usr/bin/env sh

# REQUIRES: shell, cc

# If an unreachable or an invalid http proxy is set, an error is returned if '--enable-network-proxy' is set
#
# RUN: env http_proxy=http://localhost:9999 %{intercept} --enable-network-proxy --output %t.json -- %{shell} %s 2> %t.stderr
# RUN: grep "failed to connect to all addresses" %t.stderr
# RUN: assert_intercepted %t.json count -eq 0

# If no http proxy is set, it should run correctly even with '--enable-network-proxy'
#
# RUN: %{intercept} --enable-network-proxy --output %t.json -- %{shell} %s
# RUN: assert_intercepted %t.json count -eq 1
# RUN: assert_intercepted %t.json contains -program %{c_compiler} -arguments %{c_compiler} -c shell_enable_network_proxy.c -o shell_enable_network_proxy.o

# By default, even with an invalid http proxy set, it should run correctly
#
# RUN: env http_proxy=http://localhost:9999 %{intercept} --output %t.json -- %{shell}
# RUN: assert_intercepted %t.json count -eq 1

touch shell_enable_network_proxy.c

$CC -c shell_enable_network_proxy.c -o shell_enable_network_proxy.o

Loading