Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multi-user Nix install doesn't initialize for non-interactive login bash shell on macOS #4376

Open
lilyball opened this issue Dec 16, 2020 · 12 comments
Labels

Comments

@lilyball
Copy link
Member

Describe the bug

The multi-user Nix installer will modify /etc/bashrc, /etc/profile.d/nix.sh, and /etc/zshenv to initialize itself. The /etc/profile.d/nix.sh modification only occurs if /etc/profile.d exists. This means that on systems that don't use /etc/profile.d, including but not limited to macOS, the installer will only modify /etc/bashrc and /etc/zshenv.

I'm not familiar with the zsh initialization process so I don't know if /etc/zshenv is sufficient there, but for Bash we really do need to put this into both the profile and the bashrc file. /etc/profile is sourced for login shells, and /etc/bashrc is sourced for interactive login shells¹. But our goal is actually to be configured for login shells, not for interactive ones. For single-user installs we install into ~/.bash_profile, ~/.bash_login, or ~/.profile (for bash).

It's not clear to me why we're targeting /etc/bashrc at all instead of /etc/profile. I feel like the logic here should be "install into /etc/profile.d/nix.sh if /etc/profile.d exists, otherwise install into /etc/profile". This way we'll get initialized for all login shells regardless of interactivity.

Beyond not initializing for non-interactive login shells, the use of /etc/bashrc also means we shouldn't² be initialized for sh shells³. Or for dash (which acts like sh).

It looks like this was changed 3 years ago in 27788f4 by @LnL7 with the rationale "The default profile already loads /etc/bashrc". Prior to that it was installing into both /etc/profile and /etc/bashrc, but there's no explanation as to why it was doing both (this dates back to the original darwin multi-user installer by @grahamc). I think this was a mistake, it should have chosen /etc/profile instead of /etc/bashrc.

¹This describes the setup on macOS. What actually happens is /etc/profile sources /etc/bashrc when running as Bash, and the latter bails early if it's not an interactive shell. Another system could do this differently, but I assume this is a standard initialization setup.

²We actually are if sh maps to bash, since the macOS /etc/profile uses if [ "${BASH-no}" != "no" ] as its guard, but Bash 3.2.57 apparently sets $BASH to the name of the shell regardless of how it's invoked, meaning invoking it as sh still sets it to /bin/sh. However if the user has mapped /bin/sh to /bin/dash or /bin/zsh (using /private/var/select/sh) then it won't work

³Single-user install does this mostly correctly, it targets the files used by login. But if ~/.bash_profile or ~/.bash_login exists it won't install into ~/.profile and therefore won't be sourced by sh -l or by dash -l. If neither of those two files exist and ~/.profile does, it will install there, and if none of them exist it instructs the user to install into ~/.profile.

Steps To Reproduce

  1. Install Nix on macOS using the multi-user install.
  2. In a terminal, run login -f $USER bash -c 'type nix'. This gives you clean environment but runs a non-interactive login shell.
  3. Also try login -f $USER dash -c 'type nix', which runs the sh initialization. Or point your /private/var/select/sh symlink at /bin/dash or /bin/zsh and run login -f $USER sh -c 'type nix'.

Expected behavior

All sh-compatible login shells should setup Nix.

nix-env --version output

nix-env (Nix) 2.3.8

Additional context

I get the feeling that macOS is primarily tested in a single-user install scenario. But single-user installs on macOS are going away in #4289 so it's important that we clean this stuff up.

This issue was discovered when a macOS app I use that invokes scripts using a non-interactive login shell was unable to find Nix after I switched from single-user to multi-user install.

@lilyball lilyball added the bug label Dec 16, 2020
@abathur
Copy link
Member

abathur commented Dec 18, 2020

I spent a little time on a few different occasions recently going through issues to figure out what the existing PR might be able to close.

While looking over the Nth shell-setup problem (but also, seeing the regular stream of these in IRC/discourse) I wondered if the installer can/should proactively test and report on the shell configurations at the end (perhaps with context/nudge for reporting any that fail)?

@lilyball
Copy link
Member Author

The only failure I'm aware of when setting up shell configurations is in the single-user approach if none of ~/.bash_profile, ~/.bash_login or ~/.profile exist, and in that case it already instructs the user to set it up themselves. In multi-user install, it should create or modify all files except for /etc/profile.d/nix.sh when /etc/profile.d/ doesn't exist. I suppose it could fail to create or modify one, but is that actually a scenario people run into?

The more common scenario AIUI is macOS updates wiping out the /etc/zshenv modification, which isn't an issue for the installer to deal with, it's something we should update nix-daemon to detect and fix.

@abathur
Copy link
Member

abathur commented Dec 18, 2020

Not sure I phrased that well. By proactively testing, I mean literally invoke the shell and run something trivial in it--for all of the shells/configurations/options we intend to support (where any that don't initialize should fail).

@lilyball
Copy link
Member Author

I suppose we could, but I’m not sure how much that will help with things.

@abathur
Copy link
Member

abathur commented Dec 18, 2020

It probably doesn't help much relative to having an install-healing nix-daemon.

@LnL7
Copy link
Member

LnL7 commented Dec 19, 2020

This is too long ago to remember why I picked bashrc, but I think it was because profile only gets loaded for login shells.

@lilyball
Copy link
Member Author

lilyball commented Jan 5, 2021

This is too long ago to remember why I picked bashrc, but I think it was because profile only gets loaded for login shells.

Interactive non-login shells load ~/.bashrc. They do not load /etc/bashrc. On macOS, /etc/bashrc is loaded from /etc/profile if and only if the $BASH env var is set (and /etc/bashrc then does the test for whether the shell is interactive).

@stale
Copy link

stale bot commented Jul 8, 2021

I marked this as stale due to inactivity. → More info

@stale stale bot added the stale label Jul 8, 2021
@lilyball
Copy link
Member Author

lilyball commented Jul 8, 2021

Last I checked this was still an issue.

@colemickens
Copy link
Member

This is definitely still an issue with 2.5-pre builds even.

@stale stale bot added the stale label Aug 13, 2022
@MrMinos
Copy link

MrMinos commented Jul 10, 2023

This is still an issue on non-interactive shell with linux

nix-env (Nix) 2.9.2

@stale stale bot removed the stale label Jul 10, 2023
@a-h
Copy link

a-h commented Nov 8, 2023

By not settings up the non-interactive shell, it means that nix copy operations to the target don't work. I set up a Ubuntu VM, installed Nix with --daemon options, and got this sort of error when attempting to copy projects to it:

nix copy --to ssh-ng://ubuntu@<ip> nixpkgs#sl 
bash: nix-daemon: command not found
error: cannot open connection to remote store 'ssh-ng://ubuntu@<ip>': error: unexpected end-of-file

However, when I used the Determinate Systems installer instead, everything worked.

I remember seeing an issue suggesting that it might replace the current Nix installer, so maybe that's the solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

6 participants