zed-industries / zed

Code at the speed of thought – Zed is a high-performance, multiplayer code editor from the creators of Atom and Tree-sitter.
https://zed.dev
Other
49.44k stars 3.01k forks source link

Terminal won’t honor ~/.hushlogin #4827

Open exalted opened 1 year ago

exalted commented 1 year ago

Check for existing issues

Describe the bug / provide steps to reproduce it

Zed will show the “last login” message (e.g., “Last login: Thu Apr 6 08:35:35 on ttys000”) although I have ~/.hushlogin file in place. (I believe this is a standard Bash behavior?)

Environment

Zed: v0.80.5 (stable) OS: macOS 13.3.0 Memory: 64 GiB Architecture: aarch64

If applicable, add mockups / screenshots to help explain present your vision of the feature

No response

If applicable, attach your ~/Library/Logs/Zed/Zed.log file to this issue.

If you only need the most recent lines, you can run the zed: open log command palette action to see the last 1000.

No response

hovsater commented 1 year ago

I believe this is due to the fact that the integrated terminal spawn in the working directory of your project not in $HOME as it usually does. Try running the following in the root of your project:

$ touch .hushlogin
exalted commented 1 year ago

@hovsater thanks for the suggestion! However, I could only accept it only as a workaround. If possible, I think Zed Terminal should look for the presence of ~/.hushlogin, regardless.

hovsater commented 1 year ago

@exalted It's your shell (e.g., bash or zsh) that searches for the .hushlogin file. So it's not something Zed can "load" for you. Perhaps some kind of workaround can be implemented, like first spawning the shell in $HOME and then immediately execute a command to cd into the project directory. I'm not sure. Someone from the Zed team would have to investigate that further.

exalted commented 1 year ago

Yup. Let's wait for someone to chime in. All other "expected" Bash initialization stuff (e.g., ~/.bash_profile, ~.bashrc, etc.) are loaded (inherited?) fine.

Thanks! 🙌

hovsater commented 1 year ago

~/.bash_profile and ~/.bashrc are loaded from a statically known set of locations by your shell. .hushlogin is only read from your current working directory upon shell start. 🙂

exalted commented 1 year ago

I think we are talking about the same thing, but I am not understanding why are you suggesting ~/.hushlogin should have a different behavior than, say, ~/.bashrc, for example. Both are very well known places.

hovsater commented 1 year ago

Your shell (e.g., bash/zsh) have a set of statically known locations for where it will look for files such as .bash_profile, .bashrc and .profile. To my knowledge, login it does not have that for .hushlogin. Upon login, it will look for .hushlogin in the current working directory, which happens to be $HOME the majority of the time. Now, in Zed, the current working directory isn't $HOME but the root of your project, thus no .hushlogin can be found. I don't believe login fallbacks to $HOME if it can not find a .hushlogin inside the CWD.

For instance, try the following:

$ cd $HOME
$ login <username>

and

$ cd /tmp
$ login <username>

I get no prompt in the first example. I get the prompt in the second example.

exalted commented 1 year ago

I appreciate you @hovsater ! 🙇

From https://linux.die.net/sag/what-login-does.html:

Part of the initial setup is outputting the contents of the file /etc/motd (short for message of the day) and checking for electronic mail. These can be disabled by creating a file called .hushlogin in the user's home directory.

exalted commented 1 year ago

LOL. Let's wrap this with a link to a source code: https://github.com/util-linux/util-linux/blob/c7ffe0cf6b7bdf62db70bd7700d6ed40d9106ba9/lib/logindefs.c#L442-L452:

* Check the per-account or the global hush-login setting.
*
* Hushed mode is enabled:
*
* a) if a global (e.g. /etc/hushlogins) hush file exists:
*     1) for ALL ACCOUNTS if the file is empty
*     2) for the current user if the username or shell is found in the file
*
* b) if a ~/.hushlogin file exists
*
* The ~/.hushlogin file is ignored if the global hush file exists.
hovsater commented 1 year ago

Interesting. The man page of login states:

If the file .hushlogin exists in the user's home directory, all of these messages are suppressed. If -q is specified, all of these messages are suppressed.

While my example above clearly shows that's not the case. Further down in the man pages of login you can see a list of files it respects:

FILES .hushlogin makes login quieter

which indicates it's loaded from the CWD, not $HOME/.hushlogin. Perhaps this is broken on macOS, I could verify this on Linux, but I don't have a machine nearby right now.

exalted commented 1 year ago

Why are you assuming .hushlogin's path refers to CWD?

hovsater commented 1 year ago

Because the path is not absolute. I dove into the source code of macOS and it does not look like they traverse any directories other than CWD.

The path to .hushlogin is defined here:

https://github.com/apple-oss-distributions/system_cmds/blob/8fcbc8dee07e730ee5ff089519a7f78befcb8aa5/login.tproj/pathnames.h#L37

And in login.c they check for its existence here (note how they read the path as is, e.g., not respecting $HOME):

https://github.com/apple-oss-distributions/system_cmds/blob/8fcbc8dee07e730ee5ff089519a7f78befcb8aa5/login.tproj/login.c#L674-L675

So I guess the conclusion to all of this is: It's a bug in macOS? 😅

exalted commented 1 year ago

LOL. I don't know… All I know is that, I am using this config for as far back as I can remember, and FWIW, VSCode terminal honors it. So, I don't know. 🤷

hovsater commented 1 year ago

VSCode uses Xterm.js. I don't believe you would see the message in VSCode even if you removed .hushlogin completely. Given what I linked above it's clear that it will only check for a .hushlogin in the current working directory. Given that the documentation says something else, I'd argue it's a bug in macOS and it should be adressed.

exalted commented 1 year ago

I too think Zed team has plenty of feedback at this point to come up with a solution they think is the right one. Thanks, @hovsater ! 🙏

mitchellh commented 10 months ago

Hi! Hi @hovsater long time no see 😉 I'm working on fixing this for Ghostty as well and wanted to share some of my own research and discoveries that I think were not covered above. You've already [correctly] established that hushlogin is handled automatically by login(1), not by the shell. I want to add more complications to this for y'all.

Relevant Ghostty issue with all the research: https://github.com/mitchellh/ghostty/issues/1074 (this is private at the time of writing this so I don't expect you to see it, although @hovsater is in the beta. But one day it will be public so preemptively linking it here). I'll repeat my findings below:

First off, macOS users expect their terminals to be login shells. This is, as far as I can tell, a purely macOS user behavior. Linux terminals in every terminal I tried are not login shells. I don't know how the macOS dev community got to this point but it is where we're at. I know Zed is macOS only at the moment but in case you get to Linux, I'm mentioning that now, because Linux is generally unaffected by this.

So let's assume we're on macOS from here on out. I'll repeat this issue will not affect Linux when you get there.

To make a login shell, the typical unix approach is to set the argv[0] of the exec sys call to -. So for example if you're launching fish you'd do -fish, and the OS magically makes this a login environment. In fish that's status --is-login (sorry I'm a fish user).

There are a couple issues with this approach on macOS. First, $SHELL will not be properly set (this is also a responsibility of login(1)). Second, libc getlogin() of any process run within the shell will return "root" and not the correct logged in user. To fix both of these issues, you must use login(1). On the plus side, it doesn't go through login so the login message doesn't show up.

So now we get to /usr/bin/login. By opening up the shell via login, $SHELL will be set and getlogin() will return the right thing. But now we have new problems: by default, the login command will chdir to the user's home directory from /etc/passwd (ignores $HOME) and will reset env vars. You can set the -p flag to not reset the env vars and instead inherit them, but the chdir behavior still happens.

To fix the chdir behavior, you can specify -l which will NOT automatically make the command a login shell. You must now manually insert the - back into the argv0. But now it won't chdir to home. Awesome. But wait, now there's a new problem: login only checks for hushlogin in the working directory of the command. Since it isn't home anymore, it won't hush logins.

So how do we fix hushlogin? Well, there is ANOTHER flag -q which behaves as if hushlogin was present. But it is entirely up to the caller to check for hushlogin. There is no way to have login (1) not change chdir (2) make a login shell (3) honor hushlogin all at once. You have to do some manual work.

The way terminals such as Kitty or iTerm do this is by creating a wrapper program (iTerm calls this ShellLauncher) which primarily sets the proper env vars and chdirs to the proper place before exec-ing and replacing itself with the real shell. So the execution is Terminal => login(1) => ShellLauncher => shell.

I think you can also replace the ShellLauncher by manually copying the hushlogin detection logic and using login -fqlp, but I haven't 100% verified this yet. I'm going to try this first since I don't want to introduce that second step. In any case, the above should give you all the background you need on this topic.

JosephTLyons commented 10 months ago

@mitchellh - appreciate the super detailed write up here, thanks. :)

Also, as a side note, really digging what you're doing with the terminal - been in the beta pool for some time now - the new terminal inspector is a really cool addition! If you ever wanted to chat about terminal development, shoot us an email, Even though we are working in different languages, I'm sure there's a lot we could benefit from chatting with you. :)

ElijahLynn commented 9 months ago

I just want to add that as of right now, if one adds a .hushlogin to the project root (not ~/.hushlogin), it suppress the Last login... AND the You have mail. message, in case one ends up here searching for that:

Last login: Fri Jan 26 12:20:53 on ttys009
You have mail.
andrewthauer commented 8 months ago

I'm having an issue where my $PATH is evaluated in the wrong order when running in the zed terminal. This becomes an issue because /usr/bin:/bin get appended (and duplicated) in front of things like /opt/homebrew/bin and then bash scripts end up using the very old v3 bash shipped with macOS.

I'm not sure this is related, but based on @mitchellh's detailed explanation, it sounds like it could be related as a root cause. I do not have this problem in the native macOS terminal, iTerm, vscode, or IntelliJ.

Angelk90 commented 5 months ago

Is there any news?

Vscode: image Zed: image