Skip to content

Commit 1edd91d

Browse files
Pass through the current working directory
Aside from just being better UX, some commands are sensitive to it and will not work correctly without it. Co-authored-by: Nikodem Rabuliński <nikodem@rabulinski.com> Signed-off-by: Nikodem Rabuliński <nikodem@rabulinski.com>
1 parent af98f63 commit 1edd91d

5 files changed

Lines changed: 35 additions & 7 deletions

File tree

crates/muvm/src/bin/muvm.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,13 @@ fn main() -> Result<ExitCode> {
8989
unreachable!("`launch_vm` never returns");
9090
}
9191

92+
let cwd = env::current_dir()?;
9293
let inherit_env = !options.no_inherit_env;
93-
let (lock_file, command, command_args, env) = match launch_or_lock(
94+
let (lock_file, command, command_args, env, cwd) = match launch_or_lock(
9495
options.command,
9596
options.command_args,
9697
options.env,
98+
cwd,
9799
options.no_tty,
98100
options.privileged,
99101
inherit_env,
@@ -108,7 +110,8 @@ fn main() -> Result<ExitCode> {
108110
command,
109111
command_args,
110112
env,
111-
} => (lock_file, command, command_args, env),
113+
cwd,
114+
} => (lock_file, command, command_args, env, cwd),
112115
};
113116

114117
// Make it lose CLOEXEC
@@ -121,6 +124,7 @@ fn main() -> Result<ExitCode> {
121124
command,
122125
command_args,
123126
env,
127+
cwd,
124128
options.no_tty,
125129
options.privileged,
126130
inherit_env,

crates/muvm/src/guest/server_worker.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,8 +200,9 @@ async fn handle_connection(mut stream: BufStream<UnixStream>) -> Result<ConnRequ
200200
vsock_port,
201201
tty,
202202
privileged,
203+
cwd,
203204
} = read_request(&mut stream).await?;
204-
debug!(command:?, command_args:?, env:?; "received launch request");
205+
debug!(command:?, command_args:?, env:?, cwd:?; "received launch request");
205206

206207
if command == Path::new("/muvmdropcaches") {
207208
// SAFETY: everything below should be async signal safe
@@ -274,7 +275,19 @@ async fn handle_connection(mut stream: BufStream<UnixStream>) -> Result<ConnRequ
274275
.envs(envs)
275276
.stdin(stdin)
276277
.stdout(stdout)
277-
.stderr(stderr);
278+
.stderr(stderr)
279+
// The documentation says that if `command` is a relative path,
280+
// it's ambiguous whether it should be interpreted relative
281+
// to the parent's working directory or relative to `current_dir`.[0]
282+
// Luckily for us, on UNIX in case of `Command::spawn`,
283+
// it's implemented by calling `posix_spawn_file_actions_add_chdir`.[1]
284+
// This is exactly what we want, as the user may want to run `muvm ./foo`
285+
// in which case we need `./foo` to be interpreted relative to `current_dir`,
286+
// not relative to cwd of the server worker.
287+
//
288+
// [0]: https://doc.rust-lang.org/stable/std/process/struct.Command.html#platform-specific-behavior-1
289+
// [1]: https://github.com/rust-lang/rust/blob/cb50d4d8566b1ee97e9a5ef95a37a40936a62c30/library/std/src/sys/pal/unix/process/process_unix.rs#L705-L707
290+
.current_dir(cwd);
278291
if tty {
279292
unsafe {
280293
cmd.pre_exec(|| {

crates/muvm/src/launch.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ pub enum LaunchResult {
2828
command: PathBuf,
2929
command_args: Vec<String>,
3030
env: Vec<(String, Option<String>)>,
31+
cwd: PathBuf,
3132
},
3233
}
3334

@@ -89,6 +90,7 @@ fn wrapped_launch(
8990
command: PathBuf,
9091
command_args: Vec<String>,
9192
env: HashMap<String, String>,
93+
cwd: PathBuf,
9294
no_tty: bool,
9395
privileged: bool,
9496
) -> Result<ExitCode> {
@@ -100,7 +102,7 @@ fn wrapped_launch(
100102
_ = unlink(&path);
101103
let listener = UnixListener::bind(path).context("Failed to listen on vm socket")?;
102104
let tty = !no_tty && stdout_is_tty();
103-
request_launch(command, command_args, env, vsock_port, tty, privileged)?;
105+
request_launch(command, command_args, env, cwd, vsock_port, tty, privileged)?;
104106
let raw_tty = tty.then(|| RawTerminal::set().expect("Stdout should be a tty"));
105107
let code = run_io_host(listener, tty)?;
106108
drop(raw_tty);
@@ -111,6 +113,7 @@ pub fn launch_or_lock(
111113
command: PathBuf,
112114
command_args: Vec<String>,
113115
env: Vec<(String, Option<String>)>,
116+
cwd: PathBuf,
114117
no_tty: bool,
115118
privileged: bool,
116119
inherit_env: bool,
@@ -122,6 +125,7 @@ pub fn launch_or_lock(
122125
command,
123126
command_args,
124127
env,
128+
cwd,
125129
}),
126130
None => {
127131
let env = prepare_env_vars(env, inherit_env)?;
@@ -131,6 +135,7 @@ pub fn launch_or_lock(
131135
command.clone(),
132136
command_args.clone(),
133137
env.clone(),
138+
cwd.clone(),
134139
no_tty,
135140
privileged,
136141
) {
@@ -182,6 +187,7 @@ pub fn request_launch(
182187
command: PathBuf,
183188
command_args: Vec<String>,
184189
env: HashMap<String, String>,
190+
cwd: PathBuf,
185191
vsock_port: u32,
186192
tty: bool,
187193
privileged: bool,
@@ -195,6 +201,7 @@ pub fn request_launch(
195201
command,
196202
command_args,
197203
env,
204+
cwd,
198205
vsock_port,
199206
tty,
200207
privileged,

crates/muvm/src/monitor.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::collections::HashMap;
2+
use std::env::current_dir;
23
use std::path::PathBuf;
34
use std::thread;
45
use std::time;
@@ -43,7 +44,8 @@ fn set_guest_pressure(pressure: GuestPressure) -> Result<()> {
4344
let command = PathBuf::from("/muvmdropcaches");
4445
let command_args = vec![];
4546
let env = HashMap::new();
46-
request_launch(command, command_args, env, 0, false, true)?;
47+
let cwd = current_dir()?;
48+
request_launch(command, command_args, env, cwd, 0, false, true)?;
4749
}
4850

4951
let wsf: u32 = pressure.into();
@@ -52,7 +54,8 @@ fn set_guest_pressure(pressure: GuestPressure) -> Result<()> {
5254
let command = PathBuf::from("/sbin/sysctl");
5355
let command_args = vec![format!("vm.watermark_scale_factor={}", wsf)];
5456
let env = HashMap::new();
55-
request_launch(command, command_args, env, 0, false, true)
57+
let cwd = current_dir()?;
58+
request_launch(command, command_args, env, cwd, 0, false, true)
5659
}
5760

5861
fn run() {

crates/muvm/src/utils/launch.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ pub struct Launch {
1212
pub vsock_port: u32,
1313
pub tty: bool,
1414
pub privileged: bool,
15+
pub cwd: PathBuf,
1516
}
1617

1718
#[derive(Clone, Eq, PartialEq, Debug, Deserialize, Serialize)]

0 commit comments

Comments
 (0)