zsh-users / fizsh

Friendly Interactive ZSHell.
Other
299 stars 18 forks source link

Fizsh cannot be used as login shell due to missing PATH #6

Closed dbeecham closed 8 years ago

dbeecham commented 9 years ago

When using fizsh as login shell, PATH is not set and fails:

[user@host ~]# ssh user@localhost
user@localhost's password:
Last login: Thu Jan  8 10:24:00 2015 from localhost.localdomain
_fizsh: Make sure that fizsh is installed correctly and that your path is set accordingly

I solved this by sourcing /etc/zsh/zprofile in /usr/local/bin/fizsh before $(type fizsh), but I am unsure if this is the correct solution. Should zprofile be sourced every time?

I am running current Arch Linux, zsh version 5.0.7, fizsh version 1.0.8.

guidovansteen commented 9 years ago

Thank you for reporting this issue.

Currently fizsh only runs as a login shell if it is explicitly invoked as "fizsh -l" or "fizsh --login". Your ssh session calls fizsh without the l flag. This explains why the new instance of fizsh behaves as a non-login shell. This means that "zprofile" is not sourced. On Arch this means in turn that /etc/profile is not sourced either (see https://wiki.archlinux.org/index.php/zsh). The result on Arch is that no $path is set when fizsh is started, which explains the reported message.

Most other distros do not have this problem, because their zsh does not depend on $path being set in /etc/profile.

The issue can indeed be circumvented by manually sourcing zprofile before $(type fizsh) is evaluated.

dbeecham commented 9 years ago

All right, I have tried around with --login, but I cannot seem to quite figure it out.

Firstly, I cannot set /usr/local/bin/fizsh --login as shell in /etc/passwd; doing to gives me an error shell /path/fizsh --login does not exist. Not sure if I should add this to /etc/shells, of if I need to escape spaces in passwd, or if this just does not work. So, I created a script:

$ cat /usr/local/bin/fizsh-local
#!/usr/bin/env zsh

echo $PATH

/usr/local/bin/fizsh --login

I also added a echo $PATH at the top in fizsh.

/usr/bin:/bin:/usr/sbin:/sbin

Is the PATH echoed. So $PATH is not empty. But /usr/local/bin isn't added before /etc/profile is sourced. Also, --login in /usr/local/bin/fizsh-local did not work.

dbeecham commented 9 years ago

I am reading though the source code, trying to understand how to solve the problem. type fizsh is called on line 58. The only reference to --login is on line 148, but it falls into the same condition as no arguments. Am I missing something?

guidovansteen commented 9 years ago

Around line 170 you will find:

if [[ ( $@ == "" ) ]]; then zsh else zsh -l fi

So, if fizsh is invoked with a command-line argument (which in this case must be -l or --login) then it is started as "zsh -l" (after setting $ZDOTDIR and some other things).

guidovansteen commented 9 years ago

At this moment I do not have an arch machine to test things. I have one at home. I will look into it later.

dbeecham commented 9 years ago

Ah, I see. The shell is exiting at line 59 though. Should some code be moved around?

guidovansteen commented 9 years ago

But /usr/local/bin isn't added before /etc/profile is sourced.

So /usr/bin is in your path. In that case you could install fizsh as /usr/bin/fizsh. Try something like:

user@localmachine$ ./configure --bindir=/usr/bin

See https://github.com/zsh-users/fizsh#install

guidovansteen commented 9 years ago

Some further thought:

The script /usr/bin/fizsh (in your case /usr/local/bin/fizsh) is initially invoked as a non-login shell. This makes difficult to determine whether the eventual fizsh shell should be run as a login-shell or not. Because of this fizsh requires the "-l" or "--login" option in order to be started as a login shell.

Yet, after using "ssh -l user@...", "sudo -iu user" or "su -i user", you should get a login shell as well. As you already noted, the problem is that in this case the system logs you in through the /etc/password file, which makes it difficult to provide the -i flag.

If we don't find a proper solution, I will add a note about this in the manpage in the "BUGS" section.

dbeecham commented 9 years ago

Even if fizsh is started with the --login argument, the shell will still fail, though? The flag is not used until the call to zsh, $(type fizsh) will be empty anyway.

I can see the issue, though. zsh should be doing the sourcing, but it can't do it before fizsh has set up all it needs to, but it can't set it up before zsh has done the sourcing. It's a catch 22.

I also just realized my line numbers are different from yours since I edited the file.

dbeecham commented 9 years ago

A thought; is it possible to use $0?

guidovansteen commented 9 years ago

Even if fizsh is started with the --login argument, the shell will still fail, though? The flag is not used until the call to zsh, $(type fizsh) will be empty anyway.

If fizsh is installed as /usr/bin/fizsh and if /usr/bin is part of your path $(type fizsh) will yield /usr/bin/fizsh. This is how fizsh works by default on Debian.

If /usr/local/bin is added to the path at the same time as /usr/bin things will work as well.

Wouldn't you encounter similar problems if zsh is only installed in /usr/local/bin and /usr/local/bin is not part of the path? Or what if zsh is only installed in /usr/bin (as is the case on e.g. Debian) and /usr/bin is not part of the path?

$ zsh -fd % echo $path /usr/local/bin /usr/bin /bin /usr/bin/X11 /usr/games % path="/usr/local/bin /bin /usr/bin/X11 /usr/games" % zsh zsh: command not found: zsh

guidovansteen commented 9 years ago

Merged with the above comment

guidovansteen commented 9 years ago

Removed... Have to look at $0 once more.

guidovansteen commented 9 years ago

zsh actually distinguishes two types of login shells: (1) shells started by login and (2) shells started with the -l or --login option.

Type 1 login shells can be detected using the environment variable $SHLVL. For zsh type 1 login shells $SHLVL is always equal to 1. This implies that for fizsh type 1 login shells $SHLVL is always equal to 2. The reason for this is that /usr/bin/fizsh is a zsh script, in which $SHLVL is 1. /usr/bin/fizsh makes sure fizsh can be started with another call to zsh. This additional call to zsh increases $SHLVL to 2.

Type 2 login shells can be detected by exporting an additional environment variable, e.g. $_fizsh_F_LOGIN_OPTION_SET before fizsh is started in /usr/bin/fizsh. After fizsh has started this exported variable could copied to a local (i.e. unexported) version of the environment variable, e.g. $_fizsh_F_LOCAL_LOGIN_OPTION_SET. The original exported variable could subsequently be unset, so that it does not exist, when one more subshell is started.

Depending on the values of the environment variables $SHLVL, $_fizsh_F_LOGIN_OPTION_SET, zsh could be called with or without the -l flag in the script /usr/bin/fiszh.

Depending on the values of the environment variables $SHLVL, $_fizsh_F_LOCAL_LOGIN_OPTION_SET, $0 could be set to -fizsh or fizsh by /etc/fizsh/fizshrc.

In the next version of fizsh I intend to implement the treatment of loginshells as outlined above.

guidovansteen commented 9 years ago

http://www.zsh.org/mla/workers/2007/msg00270.html and subsequent reactions provide interesting information as well.

fizsh's man page should probably mention that things like ssh -t someserver "cd $(pwd) && ARGV0=-\$0 exec \$0" do not work as described there.

guidovansteen commented 9 years ago

Closing this issue (see the above commits).

guidovansteen commented 9 years ago

PS: The original issue of fizsh not being able to find its path, is IMO misconfiguration problem not specifically related to fizsh.

If Pacman had done the installation, the fizsh script should have been installed in /usr/bin. This would have prevented the problem. /usr/local/bin is the responsability of the local administrator. If he decides to install fizsh there, he should make sure that /usr/local/bin is available when fizsh is started as a login shell. This may for example be achieved by having zprofile or zlogin add /usr/local/bin to the $path variable.

ghost commented 8 years ago

On OSX the issue still persists. Due to security reasons, on OSX 10.11 /usr/bin is protected by SIP (Security Integrity Protection) http://arstechnica.com/apple/2015/09/os-x-10-11-el-capitan-the-ars-technica-review/8/

Installing 1.0.8 can be done by brew install fizsh and will place bin aliases into /usr/local

fibrics-Mac-Pro% fizsh
welcome to fizsh, the friendly interactive zshell
type man fizsh for instructions on how to use fizsh
fibric@fibrics-Mac-Pro ~>

But when changing my default shell from zsh to fizsh then I see this:

Last login: Sat Oct  3 08:32:55 on ttys001
_fizsh: Make sure that fizsh is installed correctly and that your path is set accordingly

[Process completed]

At the point of [Process completed] the terminal window is dead.

guidovansteen commented 8 years ago

Strange... This error message occurs when the command type fizsh cannot find the fizsh binary. Not finding the fizsh binary causes your seemingly dead terminal window. Usually this happens when the directory of the fizsh binary is not part of $path. Therefore, after you arrive at the seemingly dead terminal window, can you report the output of type fizsh and echo $path?

I do not have OS X and brew here. So I cannot test the issue myself.

You might want to check if the problem is related to brew install. To find out, just install fizsh manually:

mkdir ./fizsh_sources cd ./fizsh_sources git clone https://github.com/zsh-users/fizsh.git cd fizsh ./configure \ --prefix=/usr/local \ --includedir=/usr/local/include \ --datadir=/usr/local/share \ --bindir=/usr/local/bin \ --libexecdir=/usr/local/lib/fizsh \ --localstatedir=/var/local \ --sysconfdir=/etc/local make sudo make install chsh -s /usr/local/bin/fizsh su $USER

If this does work, I would expect the problem to be caused by brew install.

Best wishes,

Guido

gerstorfer commented 8 years ago

Manual installation makes no difference.

guidovansteen commented 8 years ago

Could you report the output of type fizsh and echo $path?

guidovansteen commented 8 years ago

And could you report the ouput of the manal installation process as well?

gerstorfer commented 8 years ago

It appears, that the path ist set only to /usr/bin and /bin and type fizsh says fizsh not found. Also fizsh sources none of the following: /etc/zprofile, /etc/zshrc, ~/.zlogin, ~/.zprofileBut /etc/zshenv is sourced, so the path can be set there and it works, without messing with /usr/local/bin/fizsh. But maybe there is still a better solution...

guidovansteen commented 8 years ago

Thank you for reporting this.

I have read some posts on the OSX-specific way of setting the system-wide path (e.g. https://serverfault.com/questions/16355/how-to-set-global-path-on-os-x). Directories to be included in it should be listed in the file /etc/paths.

So, local administrators who allow executables in /usr/local/bin/ should add the entry /usr/local/bin/ to the file /etc/paths. This should be done BEFORE any executable in /usr/local/bin/ is executed.

Changing PATH in /etc/zshenv may technically work as well. The same may apply to changing PATH in /etc/launchd.conf. However, if I were on OSX I would rather create the system-wide path correctly using /etc/paths.

guidovansteen commented 8 years ago

It would not hurt to add an extra configuration file called ~/.fprofile or ~/.zshenv. This file would be sourced immediately after fizsh is started. I might add such a file in the next fizsh release.

ADDED LATER: On second thought: it would hurt. Fizsh is meant to be a friendly shell, and additional configuration files would make fizsh less friendly.

gerstorfer commented 8 years ago

I would like to note, that I added /usr/local/bin to /etc/paths (and /etc/launchd.conf and /etc/paths.d/) without success. I tried a lot of other stuff too. In the end, using /etc/zshenv was the only feasible workaround.

guidovansteen commented 8 years ago

I have access to an OSX machine (10.8.5). On this machine there is a file called /etc/zshenv. It contains:

$ cat /etc/zshenv ... if [ -x /usr/libexec/path_helper ]; then eval /usr/libexec/path_helper -s fi

This path_helper program sets the path using the contents of /etc/paths. In my case this seems to work properly.

gerstorfer commented 8 years ago

On OSX 10.11 /etc/zshenv does not exist anymore and has to be created with this content.

guidovansteen commented 8 years ago

OK, now I understand.

Can you set the path in ~/.zshenv? Or is that not working either? Does the path_helper binary still exist in OSX 10.11?

gerstorfer commented 8 years ago

Yes! I can set the path in ~/.zshenv and path_helper still exists and works as advertised.

guidovansteen commented 8 years ago

Thank you, it is good to know this!

guidovansteen commented 8 years ago

The code commited to prevent this issue is https://github.com/zsh-users/fizsh/commit/9a128f3239bd72b52e97281a3377e17b011fd8b6.

guidovansteen commented 8 years ago

On second thought: Since this issue has now been solved in a relatively simple way, I will refrain from adding extra configuration files like /etc/fizsh/fizshenv and ~/.fizsh/.fizshenv. Fizsh is meant to be a friendly shell. Therefore, I will keep the number of configuration files as small as possible.

djbclark commented 8 years ago

I can report this does work on 10.11. Only comment is that it would be nice to have fizsh tell the user in the error message to try putting PATH in .zshenv rather than making thr user find this thread :-) (BTW great work in general, Iam really enjoying it.) Oh and also --login seems to no longer be required; or at least seems to be working fine without it via iterm and ssh.