mintty / wsltty

Mintty as a terminal for Bash on Ubuntu on Windows / WSL
Other
3.11k stars 104 forks source link

HOME env variable is drop when invoking windows exe from WSL #324

Closed entosen closed 1 year ago

entosen commented 1 year ago

relate to #84

I set HOME environment variable to C:\Users\bob\home by Windows setting.

When I invoke windows exe from WSL in WSLTTY, HOME environment is lost and exe points C:\Users\bob as default home.

I want to keep HOME env variable C:\Users\bob\home .

problem code is here https://github.com/mintty/mintty/blob/7fbb245df1128a5e7252b3bb49703620cc8fb1d7/src/winmain.c#L6231-L6233

my environment:

Reproduction:

  1. In Windows settings, set the %HOME% env var to something else
  2. Open wsltty (echo $HOME -> /home/bob)
  3. $ cmd.exe /c set
  4. HOME is not shown

Thanks

puellanivis commented 1 year ago

Unfortunately, by that point in the code, the value of HOME from windows has already been lost. In order to preserve something like this, the code would need to save a copy of the environment variable before calling into WSL, and “restore” it instead of simply unsetting it. At this point, I’m unsure how we would even know which environment variables should be backed up to be restored…

🤔 So, because of the interaction between windows and linux, there’s no easy solution… not saying someone couldn’t build this functionality, but it would be a bit more complex than a simple small feature—even if the description of the feature is so easy to formulate as you put it well here.

Biswa96 commented 1 year ago

I set HOME environment variable to C:\Users\bob\home by Windows setting.

How exactly?

mintty commented 1 year ago
  1. In Windows settings, set the %HOME% env var to something else

I guess this can be simulated by HOME being set within WSL, whether set before or not.

  1. Open wsltty (echo $HOME -> /home/bob)
  2. $ cmd.exe /c set
  3. HOME is not shown

The same happens if you run cmd.exe from a WSL default terminal, so sorry, I think this is not a wsltty issue.

Biswa96 commented 1 year ago

OK, now I understand. @entosen you need to use WSLENV variable to pass variable between Windows and WSL, see https://devblogs.microsoft.com/commandline/share-environment-vars-between-wsl-and-windows/

Also here HOME is the actual environment variable in Linux world. It could be overwritten by distribution's own $HOME variable. Instead %USERPROFILE% can be used like this set WSLENV=USERPROFILE/p.

puellanivis commented 1 year ago

My understanding is that this is being set through the system environment variables image

And it’s not being propagated through WTTY because we clear the HOME variable before calling a windows program.

entosen commented 1 year ago

Thank you, everyone.

However, it seems that my intentions have not been well conveyed to you.

I have 3 separate directories intended to be as home directory.

I intentionally add HOME environment variable to Windows environment setting

environment

What I want is:

Observed behavior

(case1) invoke from PowerShell

> cmd.exe /c set HOME

HOME=C:\Users\bob\home
HOMEDRIVE=C:
HOMEPATH=\Users\bob

(case2) invoke from Cygwin

% echo $HOME
/cygdrive/c/Users/bob/home

% cmd.exe /c set HOME
HOME=C:\Users\bob\home
HOMEDRIVE=C:
HOMEPATH=\Users\bob

(case3) invoke from WSL in wsltty: (HOME is lost !!!)

$ echo $HOME
/home/bob

$ cmd.exe /c set HOME
'\\wsl$\Ubuntu-20.04\home\bob'
CMD.EXE started in the current directory above.
UNC paths are not supported; use the Windows directory by default.
HOMEDRIVE=C:
HOMEPATH=\Users\bob

(case4) invoke from WSL in Windows Terminal

$ echo $HOME
/home/bob

$ cmd.exe /c set HOME
'\\wsl$\Ubuntu-20.04\home\bob'
CMD.EXE started in the current directory above.
UNC paths are not supported; use the Windows directory by default.
HOME=C:\Users\bob\home
HOMEDRIVE=C:
HOMEPATH=\Users\bob
Biswa96 commented 1 year ago

In short, you want to share the same home directory C:\Users\bob\home between cygwin and WSL, right?

entosen commented 1 year ago

No. I want to separate home directory.

What I want is:

  • In windows, HOME points C:\Users\bob\home (2)
  • In WSL, HOME points /home/bob (3)
  • In windows processes invoked from WSL, HOME points C:\Users\bob\home (2)
Biswa96 commented 1 year ago

C:\Users\bob\home and /home/bob are not same directory. Did you assume the opposite? /home/bob path is in the distribution in WSL which is totally different than C:\Users\bob\home.

entosen commented 1 year ago

@Biswa96

C:\Users\bob\home and /home/bob are not same directory.

I already know that.

The problem I am facing is that windows processes invoked from WSL point to which directory as home directory. (In other words, the processes read dot-files from which directory.) I want the processes to point to C:\Users\bob\home in accordance with HOME environment variable in Windows. However, Actually, the processes point to C:\Users\bob because HOME envrionment variable of them is lost.

This behavior (dropping HOME environment variable) occur only in wsltty, In other terminal (wsl original terminal, windows terminal, etc), It does not occur.

mintty commented 1 year ago

What I want is:

  • In windows, HOME points C:\Users\bob\home (2)
  • In WSL, HOME points /home/bob (3)
  • In windows processes invoked from WSL, HOME points C:\Users\bob\home (2)

Now understood. Checking:

See the comment above that unsetenv("HOME"); code. It was added to solve an issue.

(#76) If I disable this unsetenv, the current issue is not solved either, HOME will then be taken from the WSL HOME (path syntax converted).

I either case, behaviour without wsltty appears to be the same, so still no wsltty issue seen.

entosen commented 1 year ago

@mintty

If I disable this unsetenv, the current issue is not solved either, HOME will then be taken from the WSL HOME (path syntax converted).

Would this be accurate?

you wrote in https://github.com/mintty/wsltty/issues/76#issuecomment-351360055,

Apparently, if a Windows application is started from WSL, it inherits the environment from the embedding Windows program, which is the terminal application mintty in this case.

Environment variables in WSL world are not shared to Windows world ? (unless WSLENV is set.)

puellanivis commented 1 year ago

As I mentioned, we would have to squirrel away the original value of HOME at startup, and restore that value with a setenv rather than using unsetenv. This is a simple to describe feature request, that is actually quite complex in how it could be implemented.

mintty commented 1 year ago

If I disable this unsetenv, the current issue is not solved either. ...

I seem to have misinterpreted my test observations. Actually this change does fix the issue. Now it's only to be evaluated why it was introduced for that other issue and whether a fix for #76 is still needed after 5 years.

entosen commented 1 year ago

Perhaps this is what is happening: mintty_workaround

workaround pseudo code:

if (getenv("HOME") does not start with "/cygdrive/" ) {
    unsetenv("HOME")
}
mintty commented 1 year ago

Thanks for the analysis. Note that the /cygdrive prefix is reconfigurable and may be just / e.g. in MSYS or Git for Windows. I guess it's better to just check whether HOME was set or not (and unsetenv if it was empty). However, this appears to fix the issue if wsltty was started from a desktop shortcut, but not if mintty --WSL was run from another cygwin shell session. Would that be sufficient?

mintty commented 1 year ago

Actually, HOME is never empty when mintty code is started as it is being set by the cygwin runtime already. So it is still open how to handle the "empty/unset" case.

mintty commented 1 year ago

I think the following clause is needed to tackle the issue, please check:

    wchar * HOME = getregstr(HKEY_CURRENT_USER, W("Environment"), W("HOME"));
    if (HOME && *HOME)
      setenv("HOME", cs__wcstoutf(HOME), true);
    else
      unsetenv("HOME");
entosen commented 1 year ago

I have tried that code. But it did not work in some cases.

In case that HOME is set to C:\Users\bob\home in Windows world, the process invoked from WSL in wsltty has HOME=C:\Users\bob\home. This is good.

In another case tha HOME is set to %USERPROFILE%\home in Windows world, then HOME=C:\Users\bob\home\%USERPROFILE%\home . This is wrong.

I don't know why this happens.

entosen commented 1 year ago

How about the following ? Personally, the following would suffice .

    wchar * HOME = getregstr(HKEY_CURRENT_USER, W("Environment"), W("HOME"));
    if (! HOME || ! *HOME)
      unsetenv("HOME");
mintty commented 1 year ago

Your simplified proposal does not work for me, cmd.exe /c echo %HOME% always says "%HOME%". You're right, though, that % variable expansion needs to be added. For the records, it's not quite obvious how to test that as it seems impossible to set a literal %...% string in cmd.exe, powershell is needed to achieve it...

mintty commented 1 year ago

I've now uploaded a fix; I hope it's sufficient to handle one initial environment variable.

entosen commented 1 year ago

It looks good to me. Thnak you.

(I tried on Ubuntu in wsltty)

---------------------
(case1: HOME environment variable set with %USERPROFILE% in windows world)
$ reg.exe query 'HKEY_CURRENT_USER\Environment' /v HOME
HKEY_CURRENT_USER\Environment
    HOME    REG_EXPAND_SZ    %USERPROFILE%\home

$ cmd.exe /c echo %HOME%
C:\Users\bob\home

---------------------
(case2: HOME environment variable set by absolute path in windows world)
$ reg.exe query 'HKEY_CURRENT_USER\Environment' /v HOME
HKEY_CURRENT_USER\Environment
    HOME    REG_SZ    C:\Users\bob\home

$ cmd.exe /c echo %HOME%
C:\Users\bob\home

---------------------
(case3: HOME environment variable is not set in windows world)
$ reg.exe query 'HKEY_CURRENT_USER\Environment' /v HOME
error: not found

$ cmd.exe /c echo %HOME%
%HOME%
mintty commented 1 year ago

Released 3.6.4.