Trying a series of fallbacks with Command::new?

I'd like to launch the user's preferred editor with Command::new, to edit a string and return the edited string. (I haven't found a crate to do that, so I'm looking to build one.) For the last fallback of that, after trying a configured editor and the standard environment variables ($VISUAL, $EDITOR), I need to try execing editor (common on Debian and derived systems), and then try launching vi (the historical default) if that doesn't exist.

Typically, programs do that kind of thing by calling fork once, then calling execvp multiple times. That also avoids the need to do any post-fork pre-exec setup multiple times.

How can I do that with Rust's Command::new or similar?

And if Command::new doesn't support this, should I propose adding it? Perhaps a .fallbacks method that provides a series of fallback commands to try if the first doesn't work?

1 Like

Typically, unix programs do that by forking once. Stdlib is cross-platform.

I'm not sure about a fallback method though, wouldn't that be solved by calling .or_else on the firsts command result? Adventurous natures could chain the whole thing using iterators.

That's traditional for $PATH search, but for $EDITOR and friends my understanding was that most programs did fallback strictly on the basis of environment variable existence, then execed once (example). Though, that doesn't help so much if you want to support both /usr/bin/editor (policy says nothing about a path search. Does that mean it's forbidden?) and vi.

There is an unstable hook that might be useful here; install a hook that runs after "post-fork pre-exec setup" but before execing vi, and tries to exec /usr/bin/editor instead.

I realize that; however, I'd also like to avoid running the complete stack of things that Command needs to do to run a process twice in full on POSIX systems given the common alternative. It may be necessary to do so on other platforms, depending on the process-spawning approach used on those platforms.

I wouldn't want to do this if the exec succeeds but the command fails, only if the exec fails.

I've seen both, depending on the program. I'd hoped to avoid needing to make the fallback editor configurable (since /usr/bin/editor doesn't exist on all POSIX systems), and I've seen code that tried editor and fell back to vi.

Good question; I don't know.

Interesting idea; it hadn't occurred to me to call exec from the before_exec hook. I'd have to look carefully at the code flow to feel confident that doing so wouldn't bypass some of the implementation of Command, but that sounds plausible.

That said, having to do something like that makes me quite tempted to propose a fallbacks method for Command instead.

Command::new is more similar to posix_spawn than fork+exec, but I'm not aware of any precedent there for multiple command choices.