rmyorston / busybox-w32

WIN32 native port of BusyBox.
https://frippery.org/busybox
Other
670 stars 124 forks source link

Issues with env -i #426

Open ale5000-git opened 2 months ago

ale5000-git commented 2 months ago

I'm not sure if I'm doing something wrong but this fail: env -i ./mytest.bat

The error is: env: can't execute './mytest.bat': Invalid argument

The content of ./mytest.bat file is just echo "Abc".


Also when using env -i a default PATH var is reestablished but this PATH var is not exported, is it supposed to be like this?

rmyorston commented 2 months ago

I've found two workarounds for the first problem:

env -i COMSPEC="$COMSPEC" ./mytest.bat
env -i SYSTEMROOT="$SYSTEMROOT ./mytest.bat

The resulting environment is as empty as it can be and still have batch files work. Details below.

How are you determining there's a default PATH with env -i? I'm not sure there is.

The details

Regarding the first problem: it doesn't require the entire environment to be cleared; it can also be seen with env -u COMSPEC -u SYSTEMROOT.

Those two environment variables are special: they're the ones that must have backslashes in their values, or bad things can happen. They're used by Windows when it needs to know how to run cmd.exe.

They both have to be unset for the problem to arise. If only COMSPEC is unset the call to spawnve() in win32/process.c succeeds, but with ERROR_ENVVAR_NOT_FOUND. When both are unset spawnve() fails with ERROR_DIRECTORY. This seems to suggest that if Windows can't find the environment variable COMSPEC it carries on by building a likely path using SYSTEMROOT, but if that can't be found it gives up.

Trying something else. This works:

unset COMSPEC SYSTEMROOT
./mytest.bat

Why the difference? What I think is going on:

In the case of the shell it's only the shell variables that are unset. The real environment is still present. When the shell comes to run ./mytest.bat a temporary environment is created from the shell variables and passed to the child process. When Windows tries to run cmd.exe to execute the batch file it can't find the environment variables it needs in the temporary environment so it looks in the real one (by accessing the global environ). That works, and indeed COMSPEC and SYSTEMROOT are both available in the batch script.

In the case of env the real environment is altered, so there isn't anything for Windows to fall back to. The workarounds restore just enough of the environment for it to work out how to run cmd.exe.

rmyorston commented 2 months ago

The shell has a PATH shell variable which isn't exported. It exports SHLVL and PWD. Support for globbing in busybox-w32 uses the BB_GLOBBING variable.

The environment created by env -i is empty, but the command it runs may set variables.

~ $ env -i env
BB_GLOBBING=0
~ $
~ $ env -i sh -c env
SHLVL=1
BB_GLOBBING=0
PWD=C:/Users/rmy
~ $
~ $ env -i sh -c 'echo $PATH'
C:/Windows/System32;C:/Windows
ale5000-git commented 2 months ago

How are you determining there's a default PATH with env -i? I'm not sure there is.

With this I see that there is a default path: env -i sh -c 'set'

Instead with this I see that it isn't exported: env -i sh -c 'env'

PS: I have seen that it is the same on bash online so probably this is correct but still it would be nice to have the batch execution working.


Isn't possible to set a default SYSTEMROOT near the code that set the default PATH? I said SYSTEMROOT because it should be easier to set compared to COMSPEC. This would allow to use env -i without breaking bath execution.

avih commented 2 months ago

Isn't possible to set...

Sure it's possible, but the question is whether that would be a good thing.

env -i is supposed to set the env exactly to the args. From POSIX:

env -i: Invoke utility with exactly the environment specified by the arguments; the inherited environment shall be ignored completely.

You should know what you're doing when you clean the environment, and part of that knowledge is knowing what you should preserve for your needs.

ale5000-git commented 2 months ago

You should know what you're doing when you clean the environment, and part of that knowledge is knowing what you should preserve for your needs.

Yes, but on Linux it set a default PATH otherwise everything will break (for example mktemp). On Linux it is able to execute shell files. On Windows there are batch files that aren't present on Linux, and it would nice to be able to execute them without workarounds.

Put the case that a code is like this: env -i ./MY_FILE

And 2 files: ./MY_FILE (shell) ./MY_FILE.bat (batch)

This code would execute the shell file on Linux but break on Windows.

PS: Maybe the SYSTEMROOT could be made to be available to batch files but not exported to shell.

avih commented 2 months ago

Yes, but on Linux it set a default PATH

Don't know who's "it", but env and bash and dash don't:

$ env -i env  # empty output

$ env -i sh -c export  # dash
export PWD='/<whatever PWD was originally>'

$ env -i bash -c export
declare -x OLDPWD
declare -x PWD="/<whatever PWD was originally>"
declare -x SHLVL="1"
ale5000-git commented 2 months ago

Yes, but on Linux it set a default PATH

Don't know who's "it", but env and bash and dash don't:

$ env -i env  # empty output

$ env -i sh -c export  # dash
export PWD='/<whatever PWD was originally>'

$ env -i bash -c export
declare -x OLDPWD
declare -x PWD="/<whatever PWD was originally>"
declare -x SHLVL="1"

They set a default "NOT exported" PATH, try this: env -i bash -c 'set'

rmyorston commented 2 months ago

The issue with env -i and batch files is a specific example of a general problem: any tampering with COMSPEC and SYSTEMROOT may result in batch files failing to run.

I don't think it's practical for busybox-w32 to detect and warn about such problems, much less mitigate them.

Consider:

Anything done in env or even at a lower level in spawnveq() can only be a partial solution. So I'm inclined not to make the attempt.