bunpen: pasta setup (ip ...): never outlive parent bunpen instance
This commit is contained in:
@@ -8,6 +8,7 @@ use log;
|
||||
use os;
|
||||
use os::exec;
|
||||
use rt;
|
||||
use rt::ext;
|
||||
use unix::signal;
|
||||
|
||||
// fork and:
|
||||
@@ -65,6 +66,51 @@ fn wait_and_propagate(child_pid: os::exec::process) (void | os::exec::error) = {
|
||||
os::exit(rc); // propagate exit code
|
||||
};
|
||||
|
||||
// run the provided command in a new process, and wait for its return.
|
||||
// under the hood:
|
||||
// 1. fork
|
||||
// 2. in child: execvpe
|
||||
// 3. in parent: wait for child
|
||||
export fn shellvpe(name: str, argv: []str, envp: []str = []) (os::exec::status | os::exec::error | rt::errno) = {
|
||||
return match (fork_and_die_with_parent()?) {
|
||||
case void =>
|
||||
errors::ext::check("shellvpe", rt::ext::execvpe(name, argv, envp));
|
||||
assert(false, "unreachable");
|
||||
return os::exec::status { ... };
|
||||
case let child_pid: os::exec::process =>
|
||||
yield wait_child(child_pid);
|
||||
};
|
||||
};
|
||||
|
||||
// same as `shellvpe(name, argv, envp)` but fallback to `name=default` if `name`
|
||||
// isn't found on PATH
|
||||
export fn shellvpe_or_default(default: str, name: str, argv: []str, envp: []str = []) (os::exec::status | os::exec::error | rt::errno) = {
|
||||
return match (fork_and_die_with_parent()?) {
|
||||
case void =>
|
||||
errors::ext::check("shellvpe", rt::ext::execvpe_or_default(default, name, argv, envp));
|
||||
assert(false, "unreachable");
|
||||
return os::exec::status { ... };
|
||||
case let child_pid: os::exec::process =>
|
||||
yield wait_child(child_pid);
|
||||
};
|
||||
};
|
||||
|
||||
// fn wait_child(child_pid: os::exec::process) (os::exec::status | os::exec::error) = {
|
||||
// for (true) {
|
||||
// match (os::exec::wait(&child_pid)) {
|
||||
// case let e: os::exec::error => match (e) {
|
||||
// case errors::interrupted =>
|
||||
// // i guess before the days of `poll`, `wait` had to wait on either the
|
||||
// // child OR a signal sent to this pid; so we need to retry if the
|
||||
// // reason we woke isn't because the child died...
|
||||
// void;
|
||||
// case => return e;
|
||||
// };
|
||||
// case let status: os::exec::status => return status;
|
||||
// };
|
||||
// };
|
||||
// };
|
||||
|
||||
// block until the provided child exits, and then return its exit status.
|
||||
// this function actually waits on *any* child, in a loop, but only returns the
|
||||
// exit code for the specific child of interest.
|
||||
|
@@ -123,7 +123,7 @@ fn config_routing_in_ns(net: restrict::net_subset) (void | os::exec::error | rt:
|
||||
// forward dns to the desired endpoint
|
||||
let dnsdest = fmt::asprintf("{}:53", net.dns);
|
||||
defer free(dnsdest);
|
||||
let rc = rt::ext::shellvpe_or_default(
|
||||
let rc = shellvpe_or_default(
|
||||
config::IPTABLES,
|
||||
"iptables",
|
||||
[
|
||||
@@ -147,7 +147,7 @@ fn config_routing_in_ns(net: restrict::net_subset) (void | os::exec::error | rt:
|
||||
// therefore, set it up *now*, and delete the addrs, and then since it's
|
||||
// already up they won't re-appear when we exec pasta.
|
||||
|
||||
let rc = rt::ext::shellvpe_or_default(
|
||||
let rc = shellvpe_or_default(
|
||||
config::IP,
|
||||
"ip",
|
||||
[
|
||||
@@ -159,7 +159,7 @@ fn config_routing_in_ns(net: restrict::net_subset) (void | os::exec::error | rt:
|
||||
)?;
|
||||
log::printfln("[namespace/pasta] 'ip link set lo up' exited {}", rc.status);
|
||||
|
||||
let rc = rt::ext::shellvpe_or_default(
|
||||
let rc = shellvpe_or_default(
|
||||
config::IP,
|
||||
"ip",
|
||||
[
|
||||
|
@@ -47,51 +47,6 @@ export fn execvpe_or_default(default: str, name: str, argv: []str, envp: []str =
|
||||
};
|
||||
};
|
||||
|
||||
// run the provided command in a new process, and wait for its return.
|
||||
// under the hood:
|
||||
// 1. fork
|
||||
// 2. in child: execvpe
|
||||
// 3. in parent: wait for child
|
||||
export fn shellvpe(name: str, argv: []str, envp: []str = []) (os::exec::status | os::exec::error) = {
|
||||
return match (os::exec::fork()) {
|
||||
case void =>
|
||||
errors::ext::check("shellvpe", execvpe(name, argv, envp));
|
||||
assert(false, "unreachable");
|
||||
return os::exec::status { ... };
|
||||
case let child_pid: os::exec::process =>
|
||||
yield wait_child(child_pid);
|
||||
};
|
||||
};
|
||||
|
||||
// same as `shellvpe(name, argv, envp)` but fallback to `name=default` if `name`
|
||||
// isn't found on PATH
|
||||
export fn shellvpe_or_default(default: str, name: str, argv: []str, envp: []str = []) (os::exec::status | os::exec::error) = {
|
||||
return match (os::exec::fork()) {
|
||||
case void =>
|
||||
errors::ext::check("shellvpe", execvpe_or_default(default, name, argv, envp));
|
||||
assert(false, "unreachable");
|
||||
return os::exec::status { ... };
|
||||
case let child_pid: os::exec::process =>
|
||||
yield wait_child(child_pid);
|
||||
};
|
||||
};
|
||||
|
||||
fn wait_child(child_pid: os::exec::process) (os::exec::status | os::exec::error) = {
|
||||
for (true) {
|
||||
match (os::exec::wait(&child_pid)) {
|
||||
case let e: os::exec::error => match (e) {
|
||||
case errors::interrupted =>
|
||||
// i guess before the days of `poll`, `wait` had to wait on either the
|
||||
// child OR a signal sent to this pid; so we need to retry if the
|
||||
// reason we woke isn't because the child died...
|
||||
void;
|
||||
case => return e;
|
||||
};
|
||||
case let status: os::exec::status => return status;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
// allocate and return a NULL-terminated array of pointers to c strings.
|
||||
// caller is responsible for free'ing the resulting array AND its strings.
|
||||
fn to_cstr_array(strs: []str) []nullable *const c::char = {
|
||||
|
Reference in New Issue
Block a user