Merge pull request #2026 from grahamc/multi-user-linux
Expand the multi-user installer to support Linuxes with systemd
This commit is contained in:
		
						commit
						3fbaa230a2
					
				
					 5 changed files with 1090 additions and 783 deletions
				
			
		
							
								
								
									
										34
									
								
								release.nix
									
										
									
									
									
								
							
							
						
						
									
										34
									
								
								release.nix
									
										
									
									
									
								
							|  | @ -127,17 +127,39 @@ let | |||
|           substitute ${./scripts/install-nix-from-closure.sh} $TMPDIR/install \ | ||||
|             --subst-var-by nix ${toplevel} \ | ||||
|             --subst-var-by cacert ${cacert} | ||||
|           substitute ${./scripts/install-darwin-multi-user.sh} $TMPDIR/install-darwin-multi-user \ | ||||
| 
 | ||||
|           substitute ${./scripts/install-darwin-multi-user.sh} $TMPDIR/install-darwin-multi-user.sh \ | ||||
|             --subst-var-by nix ${toplevel} \ | ||||
|             --subst-var-by cacert ${cacert} | ||||
|           substitute ${./scripts/install-systemd-multi-user.sh} $TMPDIR/install-systemd-multi-user.sh \ | ||||
|             --subst-var-by nix ${toplevel} \ | ||||
|             --subst-var-by cacert ${cacert} | ||||
|           substitute ${./scripts/install-multi-user.sh} $TMPDIR/install-multi-user \ | ||||
|             --subst-var-by nix ${toplevel} \ | ||||
|             --subst-var-by cacert ${cacert} | ||||
| 
 | ||||
|           if type -p shellcheck; then | ||||
|             shellcheck -e SC1090 $TMPDIR/install | ||||
|             shellcheck -e SC1091,SC2002 $TMPDIR/install-darwin-multi-user | ||||
|             # SC1090: Don't worry about not being able to find | ||||
|             #         $nix/etc/profile.d/nix.sh | ||||
|             shellcheck --exclude SC1090 $TMPDIR/install | ||||
|             shellcheck $TMPDIR/install-darwin-multi-user.sh | ||||
|             shellcheck $TMPDIR/install-systemd-multi-user.sh | ||||
| 
 | ||||
|             # SC1091: Don't panic about not being able to source | ||||
|             #         /etc/profile | ||||
|             # SC2002: Ignore "useless cat" "error", when loading | ||||
|             #         .reginfo, as the cat is a much cleaner | ||||
|             #         implementation, even though it is "useless" | ||||
|             # SC2116: Allow ROOT_HOME=$(echo ~root) for resolving | ||||
|             #         root's home directory | ||||
|             shellcheck --external-sources \ | ||||
|               --exclude SC1091,SC2002,SC2116 $TMPDIR/install-multi-user | ||||
|           fi | ||||
| 
 | ||||
|           chmod +x $TMPDIR/install | ||||
|           chmod +x $TMPDIR/install-darwin-multi-user | ||||
|           chmod +x $TMPDIR/install-darwin-multi-user.sh | ||||
|           chmod +x $TMPDIR/install-systemd-multi-user.sh | ||||
|           chmod +x $TMPDIR/install-multi-user | ||||
|           dir=nix-${version}-${system} | ||||
|           fn=$out/$dir.tar.bz2 | ||||
|           mkdir -p $out/nix-support | ||||
|  | @ -149,7 +171,9 @@ let | |||
|             --transform "s,$TMPDIR/install,$dir/install," \ | ||||
|             --transform "s,$TMPDIR/reginfo,$dir/.reginfo," \ | ||||
|             --transform "s,$NIX_STORE,$dir/store,S" \ | ||||
|             $TMPDIR/install $TMPDIR/install-darwin-multi-user $TMPDIR/reginfo \ | ||||
|             $TMPDIR/install $TMPDIR/install-darwin-multi-user.sh \ | ||||
|             $TMPDIR/install-systemd-multi-user.sh \ | ||||
|             $TMPDIR/install-multi-user $TMPDIR/reginfo \ | ||||
|             $(cat ${installerClosureInfo}/store-paths) | ||||
|         ''); | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,772 +1,43 @@ | |||
| #!/bin/bash | ||||
| #!/usr/bin/env bash | ||||
| 
 | ||||
| set -eu | ||||
| set -o pipefail | ||||
| 
 | ||||
| # Sourced from: | ||||
| # - https://github.com/LnL7/nix-darwin/blob/8c29d0985d74b4a990238497c47a2542a5616b3c/bootstrap.sh | ||||
| # - https://gist.github.com/expipiplus1/e571ce88c608a1e83547c918591b149f/ac504c6c1b96e65505fbda437a28ce563408ecb0 | ||||
| # - https://github.com/NixOS/nixos-org-configurations/blob/a122f418797713d519aadf02e677fce0dc1cb446/delft/scripts/nix-mac-installer.sh | ||||
| # - https://github.com/matthewbauer/macNixOS/blob/f6045394f9153edea417be90c216788e754feaba/install-macNixOS.sh | ||||
| # - https://gist.github.com/LnL7/9717bd6cdcb30b086fd7f2093e5f8494/86b26f852ce563e973acd30f796a9a416248c34a | ||||
| # | ||||
| # however tracking which bits came from which would be impossible. | ||||
| 
 | ||||
| readonly ESC='\033[0m' | ||||
| readonly BOLD='\033[38;1m' | ||||
| readonly BLUE='\033[38;34m' | ||||
| readonly BLUE_UL='\033[38;4;34m' | ||||
| readonly GREEN='\033[38;32m' | ||||
| readonly GREEN_UL='\033[38;4;32m' | ||||
| readonly RED='\033[38;31m' | ||||
| readonly RED_UL='\033[38;4;31m' | ||||
| readonly YELLOW='\033[38;33m' | ||||
| readonly YELLOW_UL='\033[38;4;33m' | ||||
| 
 | ||||
| readonly CORES=$(sysctl -n hw.ncpu) | ||||
| readonly NIX_USER_COUNT="32" | ||||
| readonly NIX_BUILD_GROUP_ID="30000" | ||||
| readonly NIX_BUILD_GROUP_NAME="nixbld" | ||||
| readonly NIX_FIRST_BUILD_UID="30001" | ||||
| # Please don't change this. We don't support it, because the | ||||
| # default shell profile that comes with Nix doesn't support it. | ||||
| readonly NIX_ROOT="/nix" | ||||
| readonly PLIST_DEST=/Library/LaunchDaemons/org.nixos.nix-daemon.plist | ||||
| 
 | ||||
| readonly PROFILE_TARGETS=("/etc/bashrc" "/etc/zshrc") | ||||
| readonly PROFILE_BACKUP_SUFFIX=".backup-before-nix" | ||||
| readonly PROFILE_NIX_FILE="$NIX_ROOT/var/nix/profiles/default/etc/profile.d/nix-daemon.sh" | ||||
| 
 | ||||
| readonly NIX_INSTALLED_NIX="@nix@" | ||||
| readonly NIX_INSTALLED_CACERT="@cacert@" | ||||
| readonly EXTRACTED_NIX_PATH="$(dirname "$0")" | ||||
| 
 | ||||
| readonly ROOT_HOME="/var/root" | ||||
| 
 | ||||
| if [ -t 0 ]; then | ||||
|     readonly IS_HEADLESS='no' | ||||
| else | ||||
|     readonly IS_HEADLESS='yes' | ||||
| fi | ||||
| 
 | ||||
| headless() { | ||||
|     if [ "$IS_HEADLESS" = "yes" ]; then | ||||
|         return 0 | ||||
|     else | ||||
|         return 1 | ||||
|     fi | ||||
| } | ||||
| 
 | ||||
| contactme() { | ||||
|     echo "We'd love to help if you need it." | ||||
|     echo "" | ||||
|     echo "If you can, open an issue at https://github.com/nixos/nix/issues" | ||||
|     echo "" | ||||
|     echo "Or feel free to contact the team," | ||||
|     echo " - on IRC #nixos on irc.freenode.net" | ||||
|     echo " - on twitter @nixos_org" | ||||
| } | ||||
| 
 | ||||
| uninstall_directions() { | ||||
|     subheader "Uninstalling nix:" | ||||
|     local step=0 | ||||
| 
 | ||||
|     if [ -e "$PLIST_DEST" ]; then | ||||
|         step=$((step + 1)) | ||||
|         cat <<EOF | ||||
| $step. Delete $PLIST_DEST | ||||
| 
 | ||||
|   sudo launchctl unload $PLIST_DEST | ||||
|   sudo rm $PLIST_DEST | ||||
| 
 | ||||
| EOF | ||||
|     fi | ||||
| 
 | ||||
|     for profile_target in "${PROFILE_TARGETS[@]}"; do | ||||
|         if [ -e "$profile_target" ] && [ -e "$profile_target$PROFILE_BACKUP_SUFFIX" ]; then | ||||
|             step=$((step + 1)) | ||||
|             cat <<EOF | ||||
| $step. Restore $profile_target$PROFILE_BACKUP_SUFFIX back to $profile_target | ||||
| 
 | ||||
|   sudo mv $profile_target$PROFILE_BACKUP_SUFFIX $profile_target | ||||
| 
 | ||||
| (after this one, you may need to re-open any terminals that were | ||||
| opened while it existed.) | ||||
| 
 | ||||
| EOF | ||||
|         fi | ||||
|     done | ||||
| 
 | ||||
|     step=$((step + 1)) | ||||
|     cat <<EOF | ||||
| $step. Delete the files Nix added to your system: | ||||
| 
 | ||||
|   sudo rm -rf /etc/nix $NIX_ROOT $ROOT_HOME/.nix-profile $ROOT_HOME/.nix-defexpr $ROOT_HOME/.nix-channels $HOME/.nix-profile $HOME/.nix-defexpr $HOME/.nix-channels | ||||
| 
 | ||||
| and that is it. | ||||
| 
 | ||||
| EOF | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| nix_user_for_core() { | ||||
|     printf "nixbld%d" "$1" | ||||
| } | ||||
| 
 | ||||
| nix_uid_for_core() { | ||||
|     echo $((NIX_FIRST_BUILD_UID + $1 - 1)) | ||||
| } | ||||
| 
 | ||||
| dsclattr() { | ||||
|     /usr/bin/dscl . -read "$1" \ | ||||
|         | awk "/$2/ { print \$2 }" | ||||
| } | ||||
| 
 | ||||
| _textout() { | ||||
|     echo -en "$1" | ||||
|     shift | ||||
|     if [ "$*" = "" ]; then | ||||
|         cat | ||||
|     else | ||||
|         echo "$@" | ||||
|     fi | ||||
|     echo -en "$ESC" | ||||
| } | ||||
| 
 | ||||
| header() { | ||||
|     follow="---------------------------------------------------------" | ||||
|     header=$(echo "---- $* $follow$follow$follow" | head -c 80) | ||||
|     echo "" | ||||
|     _textout "$BLUE" "$header" | ||||
| } | ||||
| 
 | ||||
| warningheader() { | ||||
|     follow="---------------------------------------------------------" | ||||
|     header=$(echo "---- $* $follow$follow$follow" | head -c 80) | ||||
|     echo "" | ||||
|     _textout "$RED" "$header" | ||||
| } | ||||
| 
 | ||||
| subheader() { | ||||
|     echo "" | ||||
|     _textout "$BLUE_UL" "$*" | ||||
| } | ||||
| 
 | ||||
| row() { | ||||
|     printf "$BOLD%s$ESC:\\t%s\\n" "$1" "$2" | ||||
| } | ||||
| 
 | ||||
| task() { | ||||
|     echo "" | ||||
|     ok "~~> $1" | ||||
| } | ||||
| 
 | ||||
| bold() { | ||||
|     echo "$BOLD$*$ESC" | ||||
| } | ||||
| 
 | ||||
| ok() { | ||||
|     _textout "$GREEN" "$@" | ||||
| } | ||||
| 
 | ||||
| warning() { | ||||
|     warningheader "warning!" | ||||
|     cat | ||||
|     echo "" | ||||
| } | ||||
| 
 | ||||
| failure() { | ||||
|     header "oh no!" | ||||
|     _textout "$RED" "$@" | ||||
|     echo "" | ||||
|     _textout "$RED" "$(contactme)" | ||||
|     trap finish_cleanup EXIT | ||||
|     exit 1 | ||||
| } | ||||
| 
 | ||||
| ui_confirm() { | ||||
|     _textout "$GREEN$GREEN_UL" "$1" | ||||
| 
 | ||||
|     if headless; then | ||||
|         echo "No TTY, assuming you would say yes :)" | ||||
|         return 0 | ||||
|     fi | ||||
| 
 | ||||
|     local prompt="[y/n] " | ||||
|     echo -n "$prompt" | ||||
|     while read -r y; do | ||||
|         if [ "$y" = "y" ]; then | ||||
|             echo "" | ||||
|             return 0 | ||||
|         elif [ "$y" = "n" ]; then | ||||
|             echo "" | ||||
|             return 1 | ||||
|         else | ||||
|             _textout "$RED" "Sorry, I didn't understand. I can only understand answers of y or n" | ||||
|             echo -n "$prompt" | ||||
|         fi | ||||
|     done | ||||
|     echo "" | ||||
|     return 1 | ||||
| } | ||||
| 
 | ||||
| __sudo() { | ||||
|     local expl="$1" | ||||
|     local cmd="$2" | ||||
|     shift | ||||
|     header "sudo execution" | ||||
| 
 | ||||
|     echo "I am executing:" | ||||
|     echo "" | ||||
|     printf "    $ sudo %s\\n" "$cmd" | ||||
|     echo "" | ||||
|     echo "$expl" | ||||
|     echo "" | ||||
| 
 | ||||
|     return 0 | ||||
| } | ||||
| 
 | ||||
| _sudo() { | ||||
|     local expl="$1" | ||||
|     shift | ||||
|     if ! headless; then | ||||
|         __sudo "$expl" "$*" | ||||
|     fi | ||||
|     sudo "$@" | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| readonly SCRATCH=$(mktemp -d -t tmp.XXXXXXXXXX) | ||||
| function finish_cleanup { | ||||
|     rm -rf "$SCRATCH" | ||||
| } | ||||
| 
 | ||||
| function finish_fail { | ||||
|     finish_cleanup | ||||
| 
 | ||||
|     failure <<EOF | ||||
| Jeeze, something went wrong. If you can take all the output and open | ||||
| an issue, we'd love to fix the problem so nobody else has this issue. | ||||
| 
 | ||||
| :( | ||||
| EOF | ||||
| } | ||||
| trap finish_fail EXIT | ||||
| 
 | ||||
| function finish_success { | ||||
|     finish_cleanup | ||||
| 
 | ||||
|     ok "Alright! We're done!" | ||||
|     cat <<EOF | ||||
| 
 | ||||
| Before Nix will work in your existing shells, you'll need to close | ||||
| them and open them again. Other than that, you should be ready to go. | ||||
| 
 | ||||
| Try it! Open a new terminal, and type: | ||||
| 
 | ||||
|   $ nix-shell -p nix-info --run "nix-info -m" | ||||
| 
 | ||||
| Thank you for using this installer. If you have any feedback, don't | ||||
| hesitate: | ||||
| 
 | ||||
| $(contactme) | ||||
| EOF | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| validate_starting_assumptions() { | ||||
| poly_validate_assumptions() { | ||||
|     if [ "$(uname -s)" != "Darwin" ]; then | ||||
|         failure "This script is for use with macOS!" | ||||
|     fi | ||||
| 
 | ||||
|     if [ $EUID -eq 0 ]; then | ||||
|         failure <<EOF | ||||
| Please do not run this script with root privileges. We will call sudo | ||||
| when we need to. | ||||
| EOF | ||||
|     fi | ||||
| 
 | ||||
|     if type nix-env 2> /dev/null >&2; then | ||||
|         failure <<EOF | ||||
| Nix already appears to be installed, and this tool assumes it is | ||||
| _not_ yet installed. | ||||
| 
 | ||||
| $(uninstall_directions) | ||||
| EOF | ||||
|     fi | ||||
| 
 | ||||
|     if [ "${NIX_REMOTE:-}" != "" ]; then | ||||
|         failure <<EOF | ||||
| For some reason, \$NIX_REMOTE is set. It really should not be set | ||||
| before this installer runs, and it hints that Nix is currently | ||||
| installed. Please delete the old Nix installation and start again. | ||||
| 
 | ||||
| Note: You might need to close your shell window and open a new shell | ||||
| to clear the variable. | ||||
| EOF | ||||
|     fi | ||||
| 
 | ||||
|     if echo "${SSL_CERT_FILE:-}" | grep -qE "(nix/var/nix|nix-profile)"; then | ||||
|         failure <<EOF | ||||
| It looks like \$SSL_CERT_FILE is set to a path that used to be part of | ||||
| the old Nix installation. Please unset that variable and try again: | ||||
| 
 | ||||
|   $ unset SSL_CERT_FILE | ||||
| 
 | ||||
| EOF | ||||
|     fi | ||||
| 
 | ||||
|     for file in ~/.bash_profile ~/.bash_login ~/.profile ~/.zshenv ~/.zprofile ~/.zshrc ~/.zlogin; do | ||||
|         if [ -f "$file" ]; then | ||||
|             if grep -l "^[^#].*.nix-profile" "$file"; then | ||||
|                 failure <<EOF | ||||
| I found a reference to a ".nix-profile" in $file. | ||||
| This has a high chance of breaking a new nix installation. It was most | ||||
| likely put there by a previous Nix installer. | ||||
| 
 | ||||
| Please remove this reference and try running this again. You should | ||||
| also look for similar references in: | ||||
| 
 | ||||
|  - ~/.bash_profile | ||||
|  - ~/.bash_login | ||||
|  - ~/.profile | ||||
| 
 | ||||
| or other shell init files that you may have. | ||||
| 
 | ||||
| $(uninstall_directions) | ||||
| EOF | ||||
|             fi | ||||
|         fi | ||||
|     done | ||||
| 
 | ||||
|     if [ -d /nix ]; then | ||||
|         failure <<EOF | ||||
| There are some relics of a previous installation of Nix at /nix, and | ||||
| this scripts assumes Nix is _not_ yet installed. Please delete the old | ||||
| Nix installation and start again. | ||||
| 
 | ||||
| $(uninstall_directions) | ||||
| EOF | ||||
|     fi | ||||
| 
 | ||||
|     if [ -d /etc/nix ]; then | ||||
|         failure <<EOF | ||||
| There are some relics of a previous installation of Nix at /etc/nix, and | ||||
| this scripts assumes Nix is _not_ yet installed. Please delete the old | ||||
| Nix installation and start again. | ||||
| 
 | ||||
| $(uninstall_directions) | ||||
| EOF | ||||
|     fi | ||||
| 
 | ||||
|     for profile_target in "${PROFILE_TARGETS[@]}"; do | ||||
|         if [ -e "$profile_target$PROFILE_BACKUP_SUFFIX" ]; then | ||||
|         failure <<EOF | ||||
| When this script runs, it backs up the current $profile_target to | ||||
| $profile_target$PROFILE_BACKUP_SUFFIX. This backup file already exists, though. | ||||
| 
 | ||||
| Please follow these instructions to clean up the old backup file: | ||||
| 
 | ||||
| 1. Copy $profile_target and $profile_target$PROFILE_BACKUP_SUFFIX to another place, just | ||||
| in case. | ||||
| 
 | ||||
| 2. Take care to make sure that $profile_target$PROFILE_BACKUP_SUFFIX doesn't look like | ||||
| it has anything nix-related in it. If it does, something is probably | ||||
| quite wrong. Please open an issue or get in touch immediately. | ||||
| 
 | ||||
| 3. Take care to make sure that $profile_target doesn't look like it has | ||||
| anything nix-related in it. If it does, and $profile_target _did not_, | ||||
| run: | ||||
| 
 | ||||
|   $ /usr/bin/sudo /bin/mv $profile_target$PROFILE_BACKUP_SUFFIX $profile_target | ||||
| 
 | ||||
| and try again. | ||||
| EOF | ||||
|         fi | ||||
| 
 | ||||
|         if grep -qi "nix" "$profile_target"; then | ||||
|             failure <<EOF | ||||
| It looks like $profile_target already has some Nix configuration in | ||||
| there. There should be no reason to run this again. If you're having | ||||
| trouble, please open an issue. | ||||
| EOF | ||||
|         fi | ||||
|     done | ||||
| 
 | ||||
|     danger_paths=("$ROOT_HOME/.nix-defexpr" "$ROOT_HOME/.nix-channels" "$ROOT_HOME/.nix-profile") | ||||
|     for danger_path in "${danger_paths[@]}"; do | ||||
|         if _sudo "making sure that $danger_path doesn't exist" \ | ||||
|            test -e "$danger_path"; then | ||||
|             failure <<EOF | ||||
| I found a file at $danger_path, which is a relic of a previous | ||||
| installation. You must first delete this file before continuing. | ||||
| 
 | ||||
| $(uninstall_directions) | ||||
| EOF | ||||
|         fi | ||||
|     done | ||||
| } | ||||
| 
 | ||||
| setup_report() { | ||||
|     header "hardware report" | ||||
|     row "           Cores" "$CORES" | ||||
| 
 | ||||
|     header "Nix config report" | ||||
|     row "        Temp Dir" "$SCRATCH" | ||||
|     row "        Nix Root" "$NIX_ROOT" | ||||
|     row "     Build Users" "$NIX_USER_COUNT" | ||||
|     row "  Build Group ID" "$NIX_BUILD_GROUP_ID" | ||||
|     row "Build Group Name" "$NIX_BUILD_GROUP_NAME" | ||||
|     if [ "${ALLOW_PREEXISTING_INSTALLATION:-}" != "" ]; then | ||||
|         row "Preexisting Install" "Allowed" | ||||
|     fi | ||||
| 
 | ||||
|     subheader "build users:" | ||||
| 
 | ||||
|     row "    Username" "UID" | ||||
|     for i in $(seq 1 "$NIX_USER_COUNT"); do | ||||
|         row "     $(nix_user_for_core "$i")" "$(nix_uid_for_core "$i")" | ||||
|     done | ||||
|     echo "" | ||||
| poly_service_installed_check() { | ||||
|     [ -e "$PLIST_DEST" ] | ||||
| } | ||||
| 
 | ||||
| create_build_group() { | ||||
|     local primary_group_id | ||||
| 
 | ||||
|     task "Setting up the build group $NIX_BUILD_GROUP_NAME" | ||||
|     if ! /usr/bin/dscl . -read "/Groups/$NIX_BUILD_GROUP_NAME" > /dev/null 2>&1; then | ||||
|         _sudo "Create the Nix build group, $NIX_BUILD_GROUP_NAME" \ | ||||
|               /usr/sbin/dseditgroup -o create \ | ||||
|               -r "Nix build group for nix-daemon" \ | ||||
|               -i "$NIX_BUILD_GROUP_ID" \ | ||||
|               "$NIX_BUILD_GROUP_NAME" >&2 | ||||
|         row "            Created" "Yes" | ||||
|     else | ||||
|         primary_group_id=$(dsclattr "/Groups/$NIX_BUILD_GROUP_NAME" "PrimaryGroupID") | ||||
|         if [ "$primary_group_id" -ne "$NIX_BUILD_GROUP_ID" ]; then | ||||
|             failure <<EOF | ||||
| It seems the build group $NIX_BUILD_GROUP_NAME already exists, but | ||||
| with the UID $primary_group_id. This script can't really handle | ||||
| that right now, so I'm going to give up. | ||||
| 
 | ||||
| You can fix this by editing this script and changing the | ||||
| NIX_BUILD_GROUP_ID variable near the top to from $NIX_BUILD_GROUP_ID | ||||
| to $primary_group_id and re-run. | ||||
| EOF | ||||
|         else | ||||
|             row "            Exists" "Yes" | ||||
|         fi | ||||
|     fi | ||||
| } | ||||
| 
 | ||||
| create_build_user_for_core() { | ||||
|     local coreid | ||||
|     local username | ||||
|     local uid | ||||
| 
 | ||||
|     coreid="$1" | ||||
|     username=$(nix_user_for_core "$coreid") | ||||
|     uid=$(nix_uid_for_core "$coreid") | ||||
|     dsclpath="/Users/$username" | ||||
| 
 | ||||
|     task "Setting up the build user $username" | ||||
| 
 | ||||
|     if ! /usr/bin/dscl . -read "$dsclpath" > /dev/null 2>&1; then | ||||
|         _sudo "Creating the Nix build user, $username" \ | ||||
|               /usr/bin/dscl . create "$dsclpath" \ | ||||
|               UniqueID "${uid}" | ||||
|         row "           Created" "Yes" | ||||
|     else | ||||
|         actual_uid=$(dsclattr "$dsclpath" "UniqueID") | ||||
|         if [ "$actual_uid" -ne "$uid" ]; then | ||||
|             failure <<EOF | ||||
| It seems the build user $username already exists, but with the UID | ||||
| with the UID $actual_uid. This script can't really handle that right | ||||
| now, so I'm going to give up. | ||||
| 
 | ||||
| If you already created the users and you know they start from | ||||
| $actual_uid and go up from there, you can edit this script and change | ||||
| NIX_FIRST_BUILD_UID near the top of the file to $actual_uid and try | ||||
| again. | ||||
| EOF | ||||
|         else | ||||
|             row "            Exists" "Yes" | ||||
|         fi | ||||
|     fi | ||||
| 
 | ||||
|     if [ "$(dsclattr "$dsclpath" "IsHidden")" = "1" ]; then | ||||
|         row "          IsHidden" "Yes" | ||||
|     else | ||||
|         _sudo "in order to make $username a hidden user" \ | ||||
|               /usr/bin/dscl . -create "$dsclpath" "IsHidden" "1" | ||||
|         row "          IsHidden" "Yes" | ||||
|     fi | ||||
| 
 | ||||
|     if [ "$(dsclattr "$dsclpath" "NFSHomeDirectory")" = "/var/empty" ]; then | ||||
|         row "          NFSHomeDirectory" "/var/empty" | ||||
|     else | ||||
|         _sudo "in order to give $username a safe home directory" \ | ||||
|               /usr/bin/dscl . -create "$dsclpath" "NFSHomeDirectory" "/var/empty" | ||||
|         row "          NFSHomeDirectory" "/var/empty" | ||||
|     fi | ||||
| 
 | ||||
|     if [ "$(dsclattr "$dsclpath" "RealName")" = "Nix build user $coreid" ]; then | ||||
|         row "          RealName" "Nix build user $coreid" | ||||
|     else | ||||
|         _sudo "in order to give $username a useful name" \ | ||||
|               /usr/bin/dscl . -create "$dsclpath" "RealName" "Nix build user $coreid" | ||||
|         row "          RealName" "Nix build user $coreid" | ||||
|     fi | ||||
| 
 | ||||
|     if [ "$(dsclattr "$dsclpath" "UserShell")" = "/sbin/nologin" ]; then | ||||
|         row "   Logins Disabled" "Yes" | ||||
|     else | ||||
|         _sudo "in order to prevent $username from logging in" \ | ||||
|               /usr/bin/dscl . -create "$dsclpath" "UserShell" "/sbin/nologin" | ||||
|         row "   Logins Disabled" "Yes" | ||||
|     fi | ||||
| 
 | ||||
|     if dseditgroup -o checkmember -m "$username" "$NIX_BUILD_GROUP_NAME" > /dev/null 2>&1 ; then | ||||
|         row "  Member of $NIX_BUILD_GROUP_NAME" "Yes" | ||||
|     else | ||||
|         _sudo "Add $username to the $NIX_BUILD_GROUP_NAME group"\ | ||||
|             /usr/sbin/dseditgroup -o edit -t user \ | ||||
|             -a "$username" "$NIX_BUILD_GROUP_NAME" | ||||
|         row "  Member of $NIX_BUILD_GROUP_NAME" "Yes" | ||||
|     fi | ||||
| 
 | ||||
|     if [ "$(dsclattr "$dsclpath" "PrimaryGroupID")" = "$NIX_BUILD_GROUP_ID" ]; then | ||||
|         row "    PrimaryGroupID" "$NIX_BUILD_GROUP_ID" | ||||
|     else | ||||
|         _sudo "to let the nix daemon use this user for builds (this might seem redundant, but there are two concepts of group membership)" \ | ||||
|               /usr/bin/dscl . -create "$dsclpath" "PrimaryGroupID" "$NIX_BUILD_GROUP_ID" | ||||
|         row "    PrimaryGroupID" "$NIX_BUILD_GROUP_ID" | ||||
| 
 | ||||
|     fi | ||||
| } | ||||
| 
 | ||||
| create_build_users() { | ||||
|     for i in $(seq 1 "$NIX_USER_COUNT"); do | ||||
|         create_build_user_for_core "$i" | ||||
|     done | ||||
| } | ||||
| 
 | ||||
| create_directories() { | ||||
|     _sudo "to make the basic directory structure of Nix (part 1)" \ | ||||
|           mkdir -pv -m 0755 /nix /nix/var /nix/var/log /nix/var/log/nix /nix/var/log/nix/drvs /nix/var/nix{,/db,/gcroots,/profiles,/temproots,/userpool} | ||||
| 
 | ||||
|     _sudo "to make the basic directory structure of Nix (part 2)" \ | ||||
|           mkdir -pv -m 1777 /nix/var/nix/{gcroots,profiles}/per-user | ||||
| 
 | ||||
|     _sudo "to make the basic directory structure of Nix (part 3)" \ | ||||
|           mkdir -pv -m 1775 /nix/store | ||||
| 
 | ||||
|     _sudo "to make the basic directory structure of Nix (part 4)" \ | ||||
|           chgrp "$NIX_BUILD_GROUP_NAME" /nix/store | ||||
| 
 | ||||
|     _sudo "to set up the root user's profile (part 1)" \ | ||||
|           mkdir -pv -m 0755 /nix/var/nix/profiles/per-user/root | ||||
| 
 | ||||
|     _sudo "to set up the root user's profile (part 2)" \ | ||||
|           mkdir -pv -m 0700 "$ROOT_HOME/.nix-defexpr" | ||||
| 
 | ||||
|     _sudo "to place the default nix daemon configuration (part 1)" \ | ||||
|           mkdir -pv -m 0555 /etc/nix | ||||
| } | ||||
| 
 | ||||
| place_channel_configuration() { | ||||
|     echo "https://nixos.org/channels/nixpkgs-unstable nixpkgs" > "$SCRATCH/.nix-channels" | ||||
|     _sudo "to set up the default system channel (part 1)" \ | ||||
|           install -m 0664 "$SCRATCH/.nix-channels" "$ROOT_HOME/.nix-channels" | ||||
| } | ||||
| 
 | ||||
| welcome_to_nix() { | ||||
|     ok "Welcome to the Multi-User Nix Installation" | ||||
| 
 | ||||
| poly_service_uninstall_directions() { | ||||
|         cat <<EOF | ||||
| $1. Delete $PLIST_DEST | ||||
| 
 | ||||
| This installation tool will set up your computer with the Nix package | ||||
| manager. This will happen in a few stages: | ||||
| 
 | ||||
| 1. Make sure your computer doesn't already have Nix. If it does, I | ||||
|    will show you instructions on how to clean up your old one. | ||||
| 
 | ||||
| 2. Show you what we are going to install and where. Then we will ask | ||||
|    if you are ready to continue. | ||||
| 
 | ||||
| 3. Create the system users and groups that the Nix daemon uses to run | ||||
|    builds. | ||||
| 
 | ||||
| 4. Perform the basic installation of the Nix files daemon. | ||||
| 
 | ||||
| 5. Configure your shell to import special Nix Profile files, so you | ||||
|    can use Nix. | ||||
| 
 | ||||
| 6. Start the Nix daemon. | ||||
|   sudo launchctl unload $PLIST_DEST | ||||
|   sudo rm $PLIST_DEST | ||||
| 
 | ||||
| EOF | ||||
| } | ||||
| 
 | ||||
|     if ui_confirm "Would you like to see a more detailed list of what we will do?"; then | ||||
|         cat <<EOF | ||||
| 
 | ||||
| We will: | ||||
| 
 | ||||
|  - make sure your computer doesn't already have Nix files | ||||
|    (if it does, I  will tell you how to clean them up.) | ||||
|  - create local users (see the list above for the users we'll make) | ||||
|  - create a local group ($NIX_BUILD_GROUP_NAME) | ||||
|  - install Nix in to $NIX_ROOT | ||||
|  - create a configuration file in /etc/nix | ||||
|  - set up the "default profile" by creating some Nix-related files in | ||||
|    $ROOT_HOME | ||||
| EOF | ||||
|         for profile_target in "${PROFILE_TARGETS[@]}"; do | ||||
|             if [ -e "$profile_target" ]; then | ||||
|                 cat <<EOF | ||||
|  - back up $profile_target to $profile_target$PROFILE_BACKUP_SUFFIX | ||||
|  - update $profile_target to include some Nix configuration | ||||
| EOF | ||||
|             fi | ||||
|         done | ||||
| poly_service_setup_note() { | ||||
|     cat <<EOF | ||||
|  - load and start a LaunchDaemon (at $PLIST_DEST) for nix-daemon | ||||
| 
 | ||||
| EOF | ||||
|         if ! ui_confirm "Ready to continue?"; then | ||||
|             failure <<EOF | ||||
| Okay, maybe you would like to talk to the team. | ||||
| EOF | ||||
|         fi | ||||
|     fi | ||||
| } | ||||
| 
 | ||||
| chat_about_sudo() { | ||||
|     header "let's talk about sudo" | ||||
| 
 | ||||
|     if headless; then | ||||
|         cat <<EOF | ||||
| This script is going to call sudo a lot. Normally, it would show you | ||||
| exactly what commands it is running and why. However, the script is | ||||
| run in a headless fashion, like this: | ||||
| 
 | ||||
|   $ curl https://nixos.org/nix/install | sh | ||||
| 
 | ||||
| or maybe in a CI pipeline. Because of that, we're going to skip the | ||||
| verbose output in the interest of brevity. | ||||
| 
 | ||||
| If you would like to | ||||
| see the output, try like this: | ||||
| 
 | ||||
|   $ curl -o install-nix https://nixos.org/nix/install | ||||
|   $ sh ./install-nix | ||||
| 
 | ||||
| EOF | ||||
|         return 0 | ||||
|     fi | ||||
| 
 | ||||
|     cat <<EOF | ||||
| This script is going to call sudo a lot. Every time we do, it'll | ||||
| output exactly what it'll do, and why. | ||||
| 
 | ||||
| Just like this: | ||||
| EOF | ||||
| 
 | ||||
|     __sudo "to demonstrate how our sudo prompts look" \ | ||||
|            echo "this is a sudo prompt" | ||||
| 
 | ||||
|     cat <<EOF | ||||
| 
 | ||||
| This might look scary, but everything can be undone by running just a | ||||
| few commands. We used to ask you to confirm each time sudo ran, but it | ||||
| was too many times. Instead, I'll just ask you this one time: | ||||
| 
 | ||||
| EOF | ||||
|     if ui_confirm "Can we use sudo?"; then | ||||
|         ok "Yay! Thanks! Let's get going!" | ||||
|     else | ||||
|         failure <<EOF | ||||
| That is okay, but we can't install. | ||||
| EOF | ||||
|     fi | ||||
| } | ||||
| 
 | ||||
| install_from_extracted_nix() { | ||||
|     ( | ||||
|         cd "$EXTRACTED_NIX_PATH" | ||||
| 
 | ||||
|         _sudo "to copy the basic Nix files to the new store at $NIX_ROOT/store" \ | ||||
|               rsync -rlpt ./store/* "$NIX_ROOT/store/" | ||||
| 
 | ||||
|         if [ -d "$NIX_INSTALLED_NIX" ]; then | ||||
|             echo "      Alright! We have our first nix at $NIX_INSTALLED_NIX" | ||||
|         else | ||||
|             failure <<EOF | ||||
| Something went wrong, and I didn't find Nix installed at | ||||
| $NIX_INSTALLED_NIX. | ||||
| EOF | ||||
|         fi | ||||
| 
 | ||||
|         _sudo "to initialize the Nix Database" \ | ||||
|               $NIX_INSTALLED_NIX/bin/nix-store --init | ||||
| 
 | ||||
|         cat ./.reginfo \ | ||||
|             | _sudo "to load data for the first time in to the Nix Database" \ | ||||
|                    "$NIX_INSTALLED_NIX/bin/nix-store" --load-db | ||||
| 
 | ||||
|         echo "      Just finished getting the nix database ready." | ||||
|     ) | ||||
| } | ||||
| 
 | ||||
| shell_source_lines() { | ||||
|     cat <<EOF | ||||
| 
 | ||||
| # Nix | ||||
| if [ -e '$PROFILE_NIX_FILE' ]; then | ||||
|   . '$PROFILE_NIX_FILE' | ||||
| fi | ||||
| # End Nix | ||||
| 
 | ||||
| EOF | ||||
| } | ||||
| configure_shell_profile() { | ||||
|     for profile_target in "${PROFILE_TARGETS[@]}"; do | ||||
|         if [ -e "$profile_target" ]; then | ||||
|             _sudo "to back up your current $profile_target to $profile_target$PROFILE_BACKUP_SUFFIX" \ | ||||
|                   cp "$profile_target" "$profile_target$PROFILE_BACKUP_SUFFIX" | ||||
| 
 | ||||
|             shell_source_lines \ | ||||
|                 | _sudo "extend your $profile_target with nix-daemon settings" \ | ||||
|                         tee -a "$profile_target" | ||||
|         fi | ||||
|     done | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| setup_default_profile() { | ||||
|     _sudo "to installing a bootstrapping Nix in to the default Profile" \ | ||||
|           HOME=$ROOT_HOME "$NIX_INSTALLED_NIX/bin/nix-env" -i "$NIX_INSTALLED_NIX" | ||||
| 
 | ||||
|     _sudo "to installing a bootstrapping SSL certificate just for Nix in to the default Profile" \ | ||||
|           HOME=$ROOT_HOME "$NIX_INSTALLED_NIX/bin/nix-env" -i "$NIX_INSTALLED_CACERT" | ||||
| 
 | ||||
|     _sudo "to update the default channel in the default profile" \ | ||||
|           HOME=$ROOT_HOME NIX_SSL_CERT_FILE=/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt "$NIX_INSTALLED_NIX/bin/nix-channel" --update nixpkgs | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| place_nix_configuration() { | ||||
|     cat <<EOF > "$SCRATCH/nix.conf" | ||||
| build-users-group = $NIX_BUILD_GROUP_NAME | ||||
| 
 | ||||
| max-jobs = $NIX_USER_COUNT | ||||
| cores = 1 | ||||
| sandbox = false | ||||
| EOF | ||||
|     _sudo "to place the default nix daemon configuration (part 2)" \ | ||||
|           install -m 0664 "$SCRATCH/nix.conf" /etc/nix/nix.conf | ||||
| } | ||||
| 
 | ||||
| configure_nix_daemon_plist() { | ||||
| poly_configure_nix_daemon_service() { | ||||
|     _sudo "to set up the nix-daemon as a LaunchDaemon" \ | ||||
|           ln -sfn "/nix/var/nix/profiles/default$PLIST_DEST" "$PLIST_DEST" | ||||
| 
 | ||||
|  | @ -778,42 +49,96 @@ configure_nix_daemon_plist() { | |||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| main() { | ||||
|     welcome_to_nix | ||||
|     chat_about_sudo | ||||
| 
 | ||||
|     if [ "${ALLOW_PREEXISTING_INSTALLATION:-}" = "" ]; then | ||||
|         validate_starting_assumptions | ||||
|     fi | ||||
| 
 | ||||
|     setup_report | ||||
| 
 | ||||
|     if ! ui_confirm "Ready to continue?"; then | ||||
|         ok "Alright, no changes have been made :)" | ||||
|         contactme | ||||
|         trap finish_cleanup EXIT | ||||
|         exit 1 | ||||
|     fi | ||||
| 
 | ||||
|     create_build_group | ||||
|     create_build_users | ||||
|     create_directories | ||||
|     place_channel_configuration | ||||
|     install_from_extracted_nix | ||||
| 
 | ||||
|     configure_shell_profile | ||||
| 
 | ||||
|     set +eu | ||||
|     . /etc/profile | ||||
|     set -eu | ||||
| 
 | ||||
|     setup_default_profile | ||||
|     place_nix_configuration | ||||
|     configure_nix_daemon_plist | ||||
| 
 | ||||
|     trap finish_success EXIT | ||||
| poly_group_exists() { | ||||
|     /usr/bin/dscl . -read "/Groups/$1" > /dev/null 2>&1 | ||||
| } | ||||
| 
 | ||||
| poly_group_id_get() { | ||||
|     dsclattr "/Groups/$1" "PrimaryGroupID" | ||||
| } | ||||
| 
 | ||||
| main | ||||
| poly_create_build_group() { | ||||
|     _sudo "Create the Nix build group, $NIX_BUILD_GROUP_NAME" \ | ||||
|           /usr/sbin/dseditgroup -o create \ | ||||
|           -r "Nix build group for nix-daemon" \ | ||||
|           -i "$NIX_BUILD_GROUP_ID" \ | ||||
|           "$NIX_BUILD_GROUP_NAME" >&2 | ||||
| } | ||||
| 
 | ||||
| poly_user_exists() { | ||||
|     /usr/bin/dscl . -read "/Users/$1" > /dev/null 2>&1 | ||||
| } | ||||
| 
 | ||||
| poly_user_id_get() { | ||||
|     dsclattr "/Users/$1" "UniqueID" | ||||
| } | ||||
| 
 | ||||
| poly_user_hidden_get() { | ||||
|     dsclattr "/Users/$1" "IsHidden" | ||||
| } | ||||
| 
 | ||||
| poly_user_hidden_set() { | ||||
|     _sudo "in order to make $1 a hidden user" \ | ||||
|           /usr/bin/dscl . -create "/Users/$1" "IsHidden" "1" | ||||
| } | ||||
| 
 | ||||
| poly_user_home_get() { | ||||
|     dsclattr "/Users/$1" "NFSHomeDirectory" | ||||
| } | ||||
| 
 | ||||
| poly_user_home_set() { | ||||
|     _sudo "in order to give $1 a safe home directory" \ | ||||
|           /usr/bin/dscl . -create "/Users/$1" "NFSHomeDirectory" "$2" | ||||
| } | ||||
| 
 | ||||
| poly_user_note_get() { | ||||
|     dsclattr "/Users/$1" "RealName" | ||||
| } | ||||
| 
 | ||||
| poly_user_note_set() { | ||||
|     _sudo "in order to give $username a useful note" \ | ||||
|           /usr/bin/dscl . -create "/Users/$1" "RealName" "$2" | ||||
| } | ||||
| 
 | ||||
| poly_user_shell_get() { | ||||
|     dsclattr "/Users/$1" "UserShell" | ||||
| } | ||||
| 
 | ||||
| poly_user_shell_set() { | ||||
|     _sudo "in order to give $1 a safe home directory" \ | ||||
|           /usr/bin/dscl . -create "/Users/$1" "UserShell" "$2" | ||||
| } | ||||
| 
 | ||||
| poly_user_in_group_check() { | ||||
|     username=$1 | ||||
|     group=$2 | ||||
|     dseditgroup -o checkmember -m "$username" "$group" > /dev/null 2>&1 | ||||
| } | ||||
| 
 | ||||
| poly_user_in_group_set() { | ||||
|     username=$1 | ||||
|     group=$2 | ||||
| 
 | ||||
|     _sudo "Add $username to the $group group"\ | ||||
|           /usr/sbin/dseditgroup -o edit -t user \ | ||||
|           -a "$username" "$group" | ||||
| } | ||||
| 
 | ||||
| poly_user_primary_group_get() { | ||||
|     dsclattr "/Users/$1" "PrimaryGroupID" | ||||
| } | ||||
| 
 | ||||
| poly_user_primary_group_set() { | ||||
|     _sudo "to let the nix daemon use this user for builds (this might seem redundant, but there are two concepts of group membership)" \ | ||||
|           /usr/bin/dscl . -create "/Users/$1" "PrimaryGroupID" "$2" | ||||
| } | ||||
| 
 | ||||
| poly_create_build_user() { | ||||
|     username=$1 | ||||
|     uid=$2 | ||||
|     builder_num=$3 | ||||
| 
 | ||||
|     _sudo "Creating the Nix build user (#$builder_num), $username" \ | ||||
|           /usr/bin/dscl . create "/Users/$username" \ | ||||
|           UniqueID "${uid}" | ||||
| } | ||||
|  |  | |||
							
								
								
									
										797
									
								
								scripts/install-multi-user.sh
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										797
									
								
								scripts/install-multi-user.sh
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,797 @@ | |||
| #!/usr/bin/env bash | ||||
| 
 | ||||
| set -eu | ||||
| set -o pipefail | ||||
| 
 | ||||
| # Sourced from: | ||||
| # - https://github.com/LnL7/nix-darwin/blob/8c29d0985d74b4a990238497c47a2542a5616b3c/bootstrap.sh | ||||
| # - https://gist.github.com/expipiplus1/e571ce88c608a1e83547c918591b149f/ac504c6c1b96e65505fbda437a28ce563408ecb0 | ||||
| # - https://github.com/NixOS/nixos-org-configurations/blob/a122f418797713d519aadf02e677fce0dc1cb446/delft/scripts/nix-mac-installer.sh | ||||
| # - https://github.com/matthewbauer/macNixOS/blob/f6045394f9153edea417be90c216788e754feaba/install-macNixOS.sh | ||||
| # - https://gist.github.com/LnL7/9717bd6cdcb30b086fd7f2093e5f8494/86b26f852ce563e973acd30f796a9a416248c34a | ||||
| # | ||||
| # however tracking which bits came from which would be impossible. | ||||
| 
 | ||||
| readonly ESC='\033[0m' | ||||
| readonly BOLD='\033[38;1m' | ||||
| readonly BLUE='\033[38;34m' | ||||
| readonly BLUE_UL='\033[38;4;34m' | ||||
| readonly GREEN='\033[38;32m' | ||||
| readonly GREEN_UL='\033[38;4;32m' | ||||
| readonly RED='\033[38;31m' | ||||
| readonly RED_UL='\033[38;4;31m' | ||||
| readonly YELLOW='\033[38;33m' | ||||
| readonly YELLOW_UL='\033[38;4;33m' | ||||
| 
 | ||||
| readonly NIX_USER_COUNT="32" | ||||
| readonly NIX_BUILD_GROUP_ID="30000" | ||||
| readonly NIX_BUILD_GROUP_NAME="nixbld" | ||||
| readonly NIX_FIRST_BUILD_UID="30001" | ||||
| # Please don't change this. We don't support it, because the | ||||
| # default shell profile that comes with Nix doesn't support it. | ||||
| readonly NIX_ROOT="/nix" | ||||
| 
 | ||||
| readonly PROFILE_TARGETS=("/etc/bashrc" "/etc/profile.d/nix.sh" "/etc/zshrc") | ||||
| readonly PROFILE_BACKUP_SUFFIX=".backup-before-nix" | ||||
| readonly PROFILE_NIX_FILE="$NIX_ROOT/var/nix/profiles/default/etc/profile.d/nix-daemon.sh" | ||||
| 
 | ||||
| readonly NIX_INSTALLED_NIX="@nix@" | ||||
| readonly NIX_INSTALLED_CACERT="@cacert@" | ||||
| readonly EXTRACTED_NIX_PATH="$(dirname "$0")" | ||||
| 
 | ||||
| readonly ROOT_HOME=$(echo ~root) | ||||
| 
 | ||||
| if [ -t 0 ]; then | ||||
|     readonly IS_HEADLESS='no' | ||||
| else | ||||
|     readonly IS_HEADLESS='yes' | ||||
| fi | ||||
| 
 | ||||
| headless() { | ||||
|     if [ "$IS_HEADLESS" = "yes" ]; then | ||||
|         return 0 | ||||
|     else | ||||
|         return 1 | ||||
|     fi | ||||
| } | ||||
| 
 | ||||
| contactme() { | ||||
|     echo "We'd love to help if you need it." | ||||
|     echo "" | ||||
|     echo "If you can, open an issue at https://github.com/nixos/nix/issues" | ||||
|     echo "" | ||||
|     echo "Or feel free to contact the team," | ||||
|     echo " - on IRC #nixos on irc.freenode.net" | ||||
|     echo " - on twitter @nixos_org" | ||||
| } | ||||
| 
 | ||||
| uninstall_directions() { | ||||
|     subheader "Uninstalling nix:" | ||||
|     local step=0 | ||||
| 
 | ||||
|     if poly_service_installed_check; then | ||||
|         step=$((step + 1)) | ||||
|         poly_service_uninstall_directions "$step" | ||||
|     fi | ||||
| 
 | ||||
|     for profile_target in "${PROFILE_TARGETS[@]}"; do | ||||
|         if [ -e "$profile_target" ] && [ -e "$profile_target$PROFILE_BACKUP_SUFFIX" ]; then | ||||
|             step=$((step + 1)) | ||||
|             cat <<EOF | ||||
| $step. Restore $profile_target$PROFILE_BACKUP_SUFFIX back to $profile_target | ||||
| 
 | ||||
|   sudo mv $profile_target$PROFILE_BACKUP_SUFFIX $profile_target | ||||
| 
 | ||||
| (after this one, you may need to re-open any terminals that were | ||||
| opened while it existed.) | ||||
| 
 | ||||
| EOF | ||||
|         fi | ||||
|     done | ||||
| 
 | ||||
|     step=$((step + 1)) | ||||
|     cat <<EOF | ||||
| $step. Delete the files Nix added to your system: | ||||
| 
 | ||||
|   sudo rm -rf /etc/nix $NIX_ROOT $ROOT_HOME/.nix-profile $ROOT_HOME/.nix-defexpr $ROOT_HOME/.nix-channels $HOME/.nix-profile $HOME/.nix-defexpr $HOME/.nix-channels | ||||
| 
 | ||||
| and that is it. | ||||
| 
 | ||||
| EOF | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| nix_user_for_core() { | ||||
|     printf "nixbld%d" "$1" | ||||
| } | ||||
| 
 | ||||
| nix_uid_for_core() { | ||||
|     echo $((NIX_FIRST_BUILD_UID + $1 - 1)) | ||||
| } | ||||
| 
 | ||||
| _textout() { | ||||
|     echo -en "$1" | ||||
|     shift | ||||
|     if [ "$*" = "" ]; then | ||||
|         cat | ||||
|     else | ||||
|         echo "$@" | ||||
|     fi | ||||
|     echo -en "$ESC" | ||||
| } | ||||
| 
 | ||||
| header() { | ||||
|     follow="---------------------------------------------------------" | ||||
|     header=$(echo "---- $* $follow$follow$follow" | head -c 80) | ||||
|     echo "" | ||||
|     _textout "$BLUE" "$header" | ||||
| } | ||||
| 
 | ||||
| warningheader() { | ||||
|     follow="---------------------------------------------------------" | ||||
|     header=$(echo "---- $* $follow$follow$follow" | head -c 80) | ||||
|     echo "" | ||||
|     _textout "$RED" "$header" | ||||
| } | ||||
| 
 | ||||
| subheader() { | ||||
|     echo "" | ||||
|     _textout "$BLUE_UL" "$*" | ||||
| } | ||||
| 
 | ||||
| row() { | ||||
|     printf "$BOLD%s$ESC:\\t%s\\n" "$1" "$2" | ||||
| } | ||||
| 
 | ||||
| task() { | ||||
|     echo "" | ||||
|     ok "~~> $1" | ||||
| } | ||||
| 
 | ||||
| bold() { | ||||
|     echo "$BOLD$*$ESC" | ||||
| } | ||||
| 
 | ||||
| ok() { | ||||
|     _textout "$GREEN" "$@" | ||||
| } | ||||
| 
 | ||||
| warning() { | ||||
|     warningheader "warning!" | ||||
|     cat | ||||
|     echo "" | ||||
| } | ||||
| 
 | ||||
| failure() { | ||||
|     header "oh no!" | ||||
|     _textout "$RED" "$@" | ||||
|     echo "" | ||||
|     _textout "$RED" "$(contactme)" | ||||
|     trap finish_cleanup EXIT | ||||
|     exit 1 | ||||
| } | ||||
| 
 | ||||
| ui_confirm() { | ||||
|     _textout "$GREEN$GREEN_UL" "$1" | ||||
| 
 | ||||
|     if headless; then | ||||
|         echo "No TTY, assuming you would say yes :)" | ||||
|         return 0 | ||||
|     fi | ||||
| 
 | ||||
|     local prompt="[y/n] " | ||||
|     echo -n "$prompt" | ||||
|     while read -r y; do | ||||
|         if [ "$y" = "y" ]; then | ||||
|             echo "" | ||||
|             return 0 | ||||
|         elif [ "$y" = "n" ]; then | ||||
|             echo "" | ||||
|             return 1 | ||||
|         else | ||||
|             _textout "$RED" "Sorry, I didn't understand. I can only understand answers of y or n" | ||||
|             echo -n "$prompt" | ||||
|         fi | ||||
|     done | ||||
|     echo "" | ||||
|     return 1 | ||||
| } | ||||
| 
 | ||||
| __sudo() { | ||||
|     local expl="$1" | ||||
|     local cmd="$2" | ||||
|     shift | ||||
|     header "sudo execution" | ||||
| 
 | ||||
|     echo "I am executing:" | ||||
|     echo "" | ||||
|     printf "    $ sudo %s\\n" "$cmd" | ||||
|     echo "" | ||||
|     echo "$expl" | ||||
|     echo "" | ||||
| 
 | ||||
|     return 0 | ||||
| } | ||||
| 
 | ||||
| _sudo() { | ||||
|     local expl="$1" | ||||
|     shift | ||||
|     if ! headless; then | ||||
|         __sudo "$expl" "$*" | ||||
|     fi | ||||
|     sudo "$@" | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| readonly SCRATCH=$(mktemp -d -t tmp.XXXXXXXXXX) | ||||
| function finish_cleanup { | ||||
|     rm -rf "$SCRATCH" | ||||
| } | ||||
| 
 | ||||
| function finish_fail { | ||||
|     finish_cleanup | ||||
| 
 | ||||
|     failure <<EOF | ||||
| Jeeze, something went wrong. If you can take all the output and open | ||||
| an issue, we'd love to fix the problem so nobody else has this issue. | ||||
| 
 | ||||
| :( | ||||
| EOF | ||||
| } | ||||
| trap finish_fail EXIT | ||||
| 
 | ||||
| function finish_success { | ||||
|     finish_cleanup | ||||
| 
 | ||||
|     ok "Alright! We're done!" | ||||
|     cat <<EOF | ||||
| 
 | ||||
| Before Nix will work in your existing shells, you'll need to close | ||||
| them and open them again. Other than that, you should be ready to go. | ||||
| 
 | ||||
| Try it! Open a new terminal, and type: | ||||
| 
 | ||||
|   $ nix-shell -p nix-info --run "nix-info -m" | ||||
| 
 | ||||
| Thank you for using this installer. If you have any feedback, don't | ||||
| hesitate: | ||||
| 
 | ||||
| $(contactme) | ||||
| EOF | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| validate_starting_assumptions() { | ||||
|     poly_validate_assumptions | ||||
| 
 | ||||
|     if [ $EUID -eq 0 ]; then | ||||
|         failure <<EOF | ||||
| Please do not run this script with root privileges. We will call sudo | ||||
| when we need to. | ||||
| EOF | ||||
|     fi | ||||
| 
 | ||||
|     if type nix-env 2> /dev/null >&2; then | ||||
|         failure <<EOF | ||||
| Nix already appears to be installed, and this tool assumes it is | ||||
| _not_ yet installed. | ||||
| 
 | ||||
| $(uninstall_directions) | ||||
| EOF | ||||
|     fi | ||||
| 
 | ||||
|     if [ "${NIX_REMOTE:-}" != "" ]; then | ||||
|         failure <<EOF | ||||
| For some reason, \$NIX_REMOTE is set. It really should not be set | ||||
| before this installer runs, and it hints that Nix is currently | ||||
| installed. Please delete the old Nix installation and start again. | ||||
| 
 | ||||
| Note: You might need to close your shell window and open a new shell | ||||
| to clear the variable. | ||||
| EOF | ||||
|     fi | ||||
| 
 | ||||
|     if echo "${SSL_CERT_FILE:-}" | grep -qE "(nix/var/nix|nix-profile)"; then | ||||
|         failure <<EOF | ||||
| It looks like \$SSL_CERT_FILE is set to a path that used to be part of | ||||
| the old Nix installation. Please unset that variable and try again: | ||||
| 
 | ||||
|   $ unset SSL_CERT_FILE | ||||
| 
 | ||||
| EOF | ||||
|     fi | ||||
| 
 | ||||
|     for file in ~/.bash_profile ~/.bash_login ~/.profile ~/.zshenv ~/.zprofile ~/.zshrc ~/.zlogin; do | ||||
|         if [ -f "$file" ]; then | ||||
|             if grep -l "^[^#].*.nix-profile" "$file"; then | ||||
|                 failure <<EOF | ||||
| I found a reference to a ".nix-profile" in $file. | ||||
| This has a high chance of breaking a new nix installation. It was most | ||||
| likely put there by a previous Nix installer. | ||||
| 
 | ||||
| Please remove this reference and try running this again. You should | ||||
| also look for similar references in: | ||||
| 
 | ||||
|  - ~/.bash_profile | ||||
|  - ~/.bash_login | ||||
|  - ~/.profile | ||||
| 
 | ||||
| or other shell init files that you may have. | ||||
| 
 | ||||
| $(uninstall_directions) | ||||
| EOF | ||||
|             fi | ||||
|         fi | ||||
|     done | ||||
| 
 | ||||
|     if [ -d /nix ]; then | ||||
|         failure <<EOF | ||||
| There are some relics of a previous installation of Nix at /nix, and | ||||
| this scripts assumes Nix is _not_ yet installed. Please delete the old | ||||
| Nix installation and start again. | ||||
| 
 | ||||
| $(uninstall_directions) | ||||
| EOF | ||||
|     fi | ||||
| 
 | ||||
|     if [ -d /etc/nix ]; then | ||||
|         failure <<EOF | ||||
| There are some relics of a previous installation of Nix at /etc/nix, and | ||||
| this scripts assumes Nix is _not_ yet installed. Please delete the old | ||||
| Nix installation and start again. | ||||
| 
 | ||||
| $(uninstall_directions) | ||||
| EOF | ||||
|     fi | ||||
| 
 | ||||
|     for profile_target in "${PROFILE_TARGETS[@]}"; do | ||||
|         if [ -e "$profile_target$PROFILE_BACKUP_SUFFIX" ]; then | ||||
|         failure <<EOF | ||||
| When this script runs, it backs up the current $profile_target to | ||||
| $profile_target$PROFILE_BACKUP_SUFFIX. This backup file already exists, though. | ||||
| 
 | ||||
| Please follow these instructions to clean up the old backup file: | ||||
| 
 | ||||
| 1. Copy $profile_target and $profile_target$PROFILE_BACKUP_SUFFIX to another place, just | ||||
| in case. | ||||
| 
 | ||||
| 2. Take care to make sure that $profile_target$PROFILE_BACKUP_SUFFIX doesn't look like | ||||
| it has anything nix-related in it. If it does, something is probably | ||||
| quite wrong. Please open an issue or get in touch immediately. | ||||
| 
 | ||||
| 3. Take care to make sure that $profile_target doesn't look like it has | ||||
| anything nix-related in it. If it does, and $profile_target _did not_, | ||||
| run: | ||||
| 
 | ||||
|   $ /usr/bin/sudo /bin/mv $profile_target$PROFILE_BACKUP_SUFFIX $profile_target | ||||
| 
 | ||||
| and try again. | ||||
| EOF | ||||
|         fi | ||||
| 
 | ||||
|         if [ -e "$profile_target" ] && grep -qi "nix" "$profile_target"; then | ||||
|             failure <<EOF | ||||
| It looks like $profile_target already has some Nix configuration in | ||||
| there. There should be no reason to run this again. If you're having | ||||
| trouble, please open an issue. | ||||
| EOF | ||||
|         fi | ||||
|     done | ||||
| 
 | ||||
|     danger_paths=("$ROOT_HOME/.nix-defexpr" "$ROOT_HOME/.nix-channels" "$ROOT_HOME/.nix-profile") | ||||
|     for danger_path in "${danger_paths[@]}"; do | ||||
|         if _sudo "making sure that $danger_path doesn't exist" \ | ||||
|            test -e "$danger_path"; then | ||||
|             failure <<EOF | ||||
| I found a file at $danger_path, which is a relic of a previous | ||||
| installation. You must first delete this file before continuing. | ||||
| 
 | ||||
| $(uninstall_directions) | ||||
| EOF | ||||
|         fi | ||||
|     done | ||||
| } | ||||
| 
 | ||||
| setup_report() { | ||||
|     header "Nix config report" | ||||
|     row "        Temp Dir" "$SCRATCH" | ||||
|     row "        Nix Root" "$NIX_ROOT" | ||||
|     row "     Build Users" "$NIX_USER_COUNT" | ||||
|     row "  Build Group ID" "$NIX_BUILD_GROUP_ID" | ||||
|     row "Build Group Name" "$NIX_BUILD_GROUP_NAME" | ||||
|     if [ "${ALLOW_PREEXISTING_INSTALLATION:-}" != "" ]; then | ||||
|         row "Preexisting Install" "Allowed" | ||||
|     fi | ||||
| 
 | ||||
|     subheader "build users:" | ||||
| 
 | ||||
|     row "    Username" "UID" | ||||
|     for i in $(seq 1 "$NIX_USER_COUNT"); do | ||||
|         row "     $(nix_user_for_core "$i")" "$(nix_uid_for_core "$i")" | ||||
|     done | ||||
|     echo "" | ||||
| } | ||||
| 
 | ||||
| create_build_group() { | ||||
|     local primary_group_id | ||||
| 
 | ||||
|     task "Setting up the build group $NIX_BUILD_GROUP_NAME" | ||||
|     if ! poly_group_exists "$NIX_BUILD_GROUP_NAME"; then | ||||
|         poly_create_build_group | ||||
|         row "            Created" "Yes" | ||||
|     else | ||||
|         primary_group_id=$(poly_group_id_get "$NIX_BUILD_GROUP_NAME") | ||||
|         if [ "$primary_group_id" -ne "$NIX_BUILD_GROUP_ID" ]; then | ||||
|             failure <<EOF | ||||
| It seems the build group $NIX_BUILD_GROUP_NAME already exists, but | ||||
| with the UID $primary_group_id. This script can't really handle | ||||
| that right now, so I'm going to give up. | ||||
| 
 | ||||
| You can fix this by editing this script and changing the | ||||
| NIX_BUILD_GROUP_ID variable near the top to from $NIX_BUILD_GROUP_ID | ||||
| to $primary_group_id and re-run. | ||||
| EOF | ||||
|         else | ||||
|             row "            Exists" "Yes" | ||||
|         fi | ||||
|     fi | ||||
| } | ||||
| 
 | ||||
| create_build_user_for_core() { | ||||
|     local coreid | ||||
|     local username | ||||
|     local uid | ||||
| 
 | ||||
|     coreid="$1" | ||||
|     username=$(nix_user_for_core "$coreid") | ||||
|     uid=$(nix_uid_for_core "$coreid") | ||||
| 
 | ||||
|     task "Setting up the build user $username" | ||||
| 
 | ||||
|     if ! poly_user_exists "$username"; then | ||||
|         poly_create_build_user "$username" "$uid" "$coreid" | ||||
|         row "           Created" "Yes" | ||||
|     else | ||||
|         actual_uid=$(poly_user_id_get "$username") | ||||
|         if [ "$actual_uid" != "$uid" ]; then | ||||
|             failure <<EOF | ||||
| It seems the build user $username already exists, but with the UID | ||||
| with the UID '$actual_uid'. This script can't really handle that right | ||||
| now, so I'm going to give up. | ||||
| 
 | ||||
| If you already created the users and you know they start from | ||||
| $actual_uid and go up from there, you can edit this script and change | ||||
| NIX_FIRST_BUILD_UID near the top of the file to $actual_uid and try | ||||
| again. | ||||
| EOF | ||||
|         else | ||||
|             row "            Exists" "Yes" | ||||
|         fi | ||||
|     fi | ||||
| 
 | ||||
|     if [ "$(poly_user_hidden_get "$username")" = "1" ]; then | ||||
|         row "            Hidden" "Yes" | ||||
|     else | ||||
|         poly_user_hidden_set "$username" | ||||
|         row "            Hidden" "Yes" | ||||
|     fi | ||||
| 
 | ||||
|     if [ "$(poly_user_home_get "$username")" = "/var/empty" ]; then | ||||
|         row "    Home Directory" "/var/empty" | ||||
|     else | ||||
|         poly_user_home_set "$username" "/var/empty" | ||||
|         row "    Home Directory" "/var/empty" | ||||
|     fi | ||||
| 
 | ||||
|     # We use grep instead of an equality check because it is difficult | ||||
|     # to extract _just_ the user's note, instead it is prefixed with | ||||
|     # some plist junk. This was causing the user note to always be set, | ||||
|     # even if there was no reason for it. | ||||
|     if ! poly_user_note_get "$username" | grep -q "Nix build user $coreid"; then | ||||
|         row "              Note" "Nix build user $coreid" | ||||
|     else | ||||
|         poly_user_note_set "$username" "Nix build user $coreid" | ||||
|         row "              Note" "Nix build user $coreid" | ||||
|     fi | ||||
| 
 | ||||
|     if [ "$(poly_user_shell_get "$username")" = "/sbin/nologin" ]; then | ||||
|         row "   Logins Disabled" "Yes" | ||||
|     else | ||||
|         poly_user_shell_set "$username" "/sbin/nologin" | ||||
|         row "   Logins Disabled" "Yes" | ||||
|     fi | ||||
| 
 | ||||
|     if poly_user_in_group_check "$username" "$NIX_BUILD_GROUP_NAME"; then | ||||
|         row "  Member of $NIX_BUILD_GROUP_NAME" "Yes" | ||||
|     else | ||||
|         poly_user_in_group_set "$username" "$NIX_BUILD_GROUP_NAME" | ||||
|         row "  Member of $NIX_BUILD_GROUP_NAME" "Yes" | ||||
|     fi | ||||
| 
 | ||||
|     if [ "$(poly_user_primary_group_get "$username")" = "$NIX_BUILD_GROUP_ID" ]; then | ||||
|         row "    PrimaryGroupID" "$NIX_BUILD_GROUP_ID" | ||||
|     else | ||||
|         poly_user_primary_group_set "$username" "$NIX_BUILD_GROUP_ID" | ||||
|         row "    PrimaryGroupID" "$NIX_BUILD_GROUP_ID" | ||||
|     fi | ||||
| } | ||||
| 
 | ||||
| create_build_users() { | ||||
|     for i in $(seq 1 "$NIX_USER_COUNT"); do | ||||
|         create_build_user_for_core "$i" | ||||
|     done | ||||
| } | ||||
| 
 | ||||
| create_directories() { | ||||
|     _sudo "to make the basic directory structure of Nix (part 1)" \ | ||||
|           mkdir -pv -m 0755 /nix /nix/var /nix/var/log /nix/var/log/nix /nix/var/log/nix/drvs /nix/var/nix{,/db,/gcroots,/profiles,/temproots,/userpool} | ||||
| 
 | ||||
|     _sudo "to make the basic directory structure of Nix (part 2)" \ | ||||
|           mkdir -pv -m 1777 /nix/var/nix/{gcroots,profiles}/per-user | ||||
| 
 | ||||
|     _sudo "to make the basic directory structure of Nix (part 3)" \ | ||||
|           mkdir -pv -m 1775 /nix/store | ||||
| 
 | ||||
|     _sudo "to make the basic directory structure of Nix (part 4)" \ | ||||
|           chgrp "$NIX_BUILD_GROUP_NAME" /nix/store | ||||
| 
 | ||||
|     _sudo "to set up the root user's profile (part 1)" \ | ||||
|           mkdir -pv -m 0755 /nix/var/nix/profiles/per-user/root | ||||
| 
 | ||||
|     _sudo "to set up the root user's profile (part 2)" \ | ||||
|           mkdir -pv -m 0700 "$ROOT_HOME/.nix-defexpr" | ||||
| 
 | ||||
|     _sudo "to place the default nix daemon configuration (part 1)" \ | ||||
|           mkdir -pv -m 0555 /etc/nix | ||||
| } | ||||
| 
 | ||||
| place_channel_configuration() { | ||||
|     echo "https://nixos.org/channels/nixpkgs-unstable nixpkgs" > "$SCRATCH/.nix-channels" | ||||
|     _sudo "to set up the default system channel (part 1)" \ | ||||
|           install -m 0664 "$SCRATCH/.nix-channels" "$ROOT_HOME/.nix-channels" | ||||
| } | ||||
| 
 | ||||
| welcome_to_nix() { | ||||
|     ok "Welcome to the Multi-User Nix Installation" | ||||
| 
 | ||||
|     cat <<EOF | ||||
| 
 | ||||
| This installation tool will set up your computer with the Nix package | ||||
| manager. This will happen in a few stages: | ||||
| 
 | ||||
| 1. Make sure your computer doesn't already have Nix. If it does, I | ||||
|    will show you instructions on how to clean up your old one. | ||||
| 
 | ||||
| 2. Show you what we are going to install and where. Then we will ask | ||||
|    if you are ready to continue. | ||||
| 
 | ||||
| 3. Create the system users and groups that the Nix daemon uses to run | ||||
|    builds. | ||||
| 
 | ||||
| 4. Perform the basic installation of the Nix files daemon. | ||||
| 
 | ||||
| 5. Configure your shell to import special Nix Profile files, so you | ||||
|    can use Nix. | ||||
| 
 | ||||
| 6. Start the Nix daemon. | ||||
| 
 | ||||
| EOF | ||||
| 
 | ||||
|     if ui_confirm "Would you like to see a more detailed list of what we will do?"; then | ||||
|         cat <<EOF | ||||
| 
 | ||||
| We will: | ||||
| 
 | ||||
|  - make sure your computer doesn't already have Nix files | ||||
|    (if it does, I  will tell you how to clean them up.) | ||||
|  - create local users (see the list above for the users we'll make) | ||||
|  - create a local group ($NIX_BUILD_GROUP_NAME) | ||||
|  - install Nix in to $NIX_ROOT | ||||
|  - create a configuration file in /etc/nix | ||||
|  - set up the "default profile" by creating some Nix-related files in | ||||
|    $ROOT_HOME | ||||
| EOF | ||||
|         for profile_target in "${PROFILE_TARGETS[@]}"; do | ||||
|             if [ -e "$profile_target" ]; then | ||||
|                 cat <<EOF | ||||
|  - back up $profile_target to $profile_target$PROFILE_BACKUP_SUFFIX | ||||
|  - update $profile_target to include some Nix configuration | ||||
| EOF | ||||
|             fi | ||||
|         done | ||||
|         poly_service_setup_note | ||||
|         if ! ui_confirm "Ready to continue?"; then | ||||
|             failure <<EOF | ||||
| Okay, maybe you would like to talk to the team. | ||||
| EOF | ||||
|         fi | ||||
|     fi | ||||
| } | ||||
| 
 | ||||
| chat_about_sudo() { | ||||
|     header "let's talk about sudo" | ||||
| 
 | ||||
|     if headless; then | ||||
|         cat <<EOF | ||||
| This script is going to call sudo a lot. Normally, it would show you | ||||
| exactly what commands it is running and why. However, the script is | ||||
| run in a headless fashion, like this: | ||||
| 
 | ||||
|   $ curl https://nixos.org/nix/install | sh | ||||
| 
 | ||||
| or maybe in a CI pipeline. Because of that, we're going to skip the | ||||
| verbose output in the interest of brevity. | ||||
| 
 | ||||
| If you would like to | ||||
| see the output, try like this: | ||||
| 
 | ||||
|   $ curl -o install-nix https://nixos.org/nix/install | ||||
|   $ sh ./install-nix | ||||
| 
 | ||||
| EOF | ||||
|         return 0 | ||||
|     fi | ||||
| 
 | ||||
|     cat <<EOF | ||||
| This script is going to call sudo a lot. Every time we do, it'll | ||||
| output exactly what it'll do, and why. | ||||
| 
 | ||||
| Just like this: | ||||
| EOF | ||||
| 
 | ||||
|     __sudo "to demonstrate how our sudo prompts look" \ | ||||
|            echo "this is a sudo prompt" | ||||
| 
 | ||||
|     cat <<EOF | ||||
| 
 | ||||
| This might look scary, but everything can be undone by running just a | ||||
| few commands. We used to ask you to confirm each time sudo ran, but it | ||||
| was too many times. Instead, I'll just ask you this one time: | ||||
| 
 | ||||
| EOF | ||||
|     if ui_confirm "Can we use sudo?"; then | ||||
|         ok "Yay! Thanks! Let's get going!" | ||||
|     else | ||||
|         failure <<EOF | ||||
| That is okay, but we can't install. | ||||
| EOF | ||||
|     fi | ||||
| } | ||||
| 
 | ||||
| install_from_extracted_nix() { | ||||
|     ( | ||||
|         cd "$EXTRACTED_NIX_PATH" | ||||
| 
 | ||||
|         _sudo "to copy the basic Nix files to the new store at $NIX_ROOT/store" \ | ||||
|               rsync -rlpt ./store/* "$NIX_ROOT/store/" | ||||
| 
 | ||||
|         if [ -d "$NIX_INSTALLED_NIX" ]; then | ||||
|             echo "      Alright! We have our first nix at $NIX_INSTALLED_NIX" | ||||
|         else | ||||
|             failure <<EOF | ||||
| Something went wrong, and I didn't find Nix installed at | ||||
| $NIX_INSTALLED_NIX. | ||||
| EOF | ||||
|         fi | ||||
| 
 | ||||
|         _sudo "to initialize the Nix Database" \ | ||||
|               $NIX_INSTALLED_NIX/bin/nix-store --init | ||||
| 
 | ||||
|         cat ./.reginfo \ | ||||
|             | _sudo "to load data for the first time in to the Nix Database" \ | ||||
|                    "$NIX_INSTALLED_NIX/bin/nix-store" --load-db | ||||
| 
 | ||||
|         echo "      Just finished getting the nix database ready." | ||||
|     ) | ||||
| } | ||||
| 
 | ||||
| shell_source_lines() { | ||||
|     cat <<EOF | ||||
| 
 | ||||
| # Nix | ||||
| if [ -e '$PROFILE_NIX_FILE' ]; then | ||||
|   . '$PROFILE_NIX_FILE' | ||||
| fi | ||||
| # End Nix | ||||
| 
 | ||||
| EOF | ||||
| } | ||||
| 
 | ||||
| configure_shell_profile() { | ||||
|     # If there is an /etc/profile.d directory, we want to ensure there | ||||
|     # is a nix.sh within it, so we can use the following loop to add | ||||
|     # the source lines to it. Note that I'm _not_ adding the source | ||||
|     # lines here, because we want to be using the regular machinery. | ||||
|     # | ||||
|     # If we go around that machinery, it becomes more complicated and | ||||
|     # adds complications to the uninstall instruction generator and | ||||
|     # old instruction sniffer as well. | ||||
|     if [ -d /etc/profile.d ]; then | ||||
|         _sudo "create a stub /etc/profile.d/nix.sh which will be updated" \ | ||||
|               touch /etc/profile.d/nix.sh | ||||
|     fi | ||||
| 
 | ||||
|     for profile_target in "${PROFILE_TARGETS[@]}"; do | ||||
|         if [ -e "$profile_target" ]; then | ||||
|             _sudo "to back up your current $profile_target to $profile_target$PROFILE_BACKUP_SUFFIX" \ | ||||
|                   cp "$profile_target" "$profile_target$PROFILE_BACKUP_SUFFIX" | ||||
| 
 | ||||
|             shell_source_lines \ | ||||
|                 | _sudo "extend your $profile_target with nix-daemon settings" \ | ||||
|                         tee -a "$profile_target" | ||||
|         fi | ||||
|     done | ||||
| } | ||||
| 
 | ||||
| setup_default_profile() { | ||||
|     _sudo "to installing a bootstrapping Nix in to the default Profile" \ | ||||
|           HOME="$ROOT_HOME" "$NIX_INSTALLED_NIX/bin/nix-env" -i "$NIX_INSTALLED_NIX" | ||||
| 
 | ||||
|     _sudo "to installing a bootstrapping SSL certificate just for Nix in to the default Profile" \ | ||||
|           HOME="$ROOT_HOME" "$NIX_INSTALLED_NIX/bin/nix-env" -i "$NIX_INSTALLED_CACERT" | ||||
| 
 | ||||
|     _sudo "to update the default channel in the default profile" \ | ||||
|           HOME="$ROOT_HOME" NIX_SSL_CERT_FILE=/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt "$NIX_INSTALLED_NIX/bin/nix-channel" --update nixpkgs | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| place_nix_configuration() { | ||||
|     cat <<EOF > "$SCRATCH/nix.conf" | ||||
| build-users-group = $NIX_BUILD_GROUP_NAME | ||||
| 
 | ||||
| max-jobs = $NIX_USER_COUNT | ||||
| cores = 1 | ||||
| sandbox = false | ||||
| EOF | ||||
|     _sudo "to place the default nix daemon configuration (part 2)" \ | ||||
|           install -m 0664 "$SCRATCH/nix.conf" /etc/nix/nix.conf | ||||
| } | ||||
| 
 | ||||
| main() { | ||||
|     if [ "$(uname -s)" = "Darwin" ]; then | ||||
|         # shellcheck source=./install-darwin-multi-user.sh | ||||
|         . "$EXTRACTED_NIX_PATH/install-darwin-multi-user.sh" | ||||
|     elif [ "$(uname -s)" = "Linux" ] && [ -e /run/systemd/system ]; then | ||||
|         # shellcheck source=./install-systemd-multi-user.sh | ||||
|         . "$EXTRACTED_NIX_PATH/install-systemd-multi-user.sh" | ||||
|     else | ||||
|         failure "Sorry, I don't know what to do on $(uname)" | ||||
|     fi | ||||
| 
 | ||||
|     welcome_to_nix | ||||
|     chat_about_sudo | ||||
| 
 | ||||
|     if [ "${ALLOW_PREEXISTING_INSTALLATION:-}" = "" ]; then | ||||
|         validate_starting_assumptions | ||||
|     fi | ||||
| 
 | ||||
|     setup_report | ||||
| 
 | ||||
|     if ! ui_confirm "Ready to continue?"; then | ||||
|         ok "Alright, no changes have been made :)" | ||||
|         contactme | ||||
|         trap finish_cleanup EXIT | ||||
|         exit 1 | ||||
|     fi | ||||
| 
 | ||||
|     create_build_group | ||||
|     create_build_users | ||||
|     create_directories | ||||
|     place_channel_configuration | ||||
|     install_from_extracted_nix | ||||
| 
 | ||||
|     configure_shell_profile | ||||
| 
 | ||||
|     set +eu | ||||
|     . /etc/profile | ||||
|     set -eu | ||||
| 
 | ||||
|     setup_default_profile | ||||
|     place_nix_configuration | ||||
|     poly_configure_nix_daemon_service | ||||
| 
 | ||||
|     trap finish_success EXIT | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| main | ||||
|  | @ -29,8 +29,15 @@ if [ "$(uname -s)" = "Darwin" ]; then | |||
|         exit 1 | ||||
|     fi | ||||
| 
 | ||||
|     printf '\e[1;31mSwitching to the Multi-User Darwin Installer\e[0m\n' | ||||
|     exec "$self/install-darwin-multi-user" | ||||
|     printf '\e[1;31mSwitching to the Daemon-based Installer\e[0m\n' | ||||
|     exec "$self/install-multi-user" | ||||
|     exit 0 | ||||
| fi | ||||
| 
 | ||||
| # Linux & Systemd support | ||||
| if [ "$(uname -s)" = "Linux" ] && [ -e /run/systemd/system ]; then | ||||
|     printf '\e[1;31mSwitching to the Daemon-based Installer\e[0m\n' | ||||
|     exec "$self/install-multi-user" | ||||
|     exit 0 | ||||
| fi | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										154
									
								
								scripts/install-systemd-multi-user.sh
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								scripts/install-systemd-multi-user.sh
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,154 @@ | |||
| #!/usr/bin/env bash | ||||
| 
 | ||||
| set -eu | ||||
| set -o pipefail | ||||
| 
 | ||||
| readonly SERVICE_SRC=/lib/systemd/system/nix-daemon.service | ||||
| readonly SERVICE_DEST=/etc/systemd/system/nix-daemon.service | ||||
| 
 | ||||
| readonly SOCKET_SRC=/lib/systemd/system/nix-daemon.socket | ||||
| readonly SOCKET_DEST=/etc/systemd/system/nix-daemon.socket | ||||
| 
 | ||||
| poly_validate_assumptions() { | ||||
|     if [ "$(uname -s)" != "Linux" ]; then | ||||
|         failure "This script is for use with Linux!" | ||||
|     fi | ||||
| } | ||||
| 
 | ||||
| poly_service_installed_check() { | ||||
|     [ "$(systemctl is-enabled nix-daemon.service)" = "linked" ] \ | ||||
|         || [ "$(systemctl is-enabled nix-daemon.socket)" = "enabled" ] | ||||
| } | ||||
| 
 | ||||
| poly_service_uninstall_directions() { | ||||
|         cat <<EOF | ||||
| $1. Delete the systemd service and socket units | ||||
| 
 | ||||
|   sudo systemctl stop nix-daemon.socket | ||||
|   sudo systemctl stop nix-daemon.service | ||||
|   sudo systemctl disable nix-daemon.socket | ||||
|   sudo systemctl disable nix-daemon.service | ||||
|   sudo systemctl daemon-reload | ||||
| EOF | ||||
| } | ||||
| 
 | ||||
| poly_service_setup_note() { | ||||
|     cat <<EOF | ||||
|  - load and start a service (at $SERVICE_DEST | ||||
|    and $SOCKET_DEST) for nix-daemon | ||||
| 
 | ||||
| EOF | ||||
| } | ||||
| 
 | ||||
| poly_configure_nix_daemon_service() { | ||||
|     _sudo "to set up the nix-daemon service" \ | ||||
|           systemctl link "/nix/var/nix/profiles/default$SERVICE_SRC" | ||||
| 
 | ||||
|     _sudo "to set up the nix-daemon socket service" \ | ||||
|           systemctl enable "/nix/var/nix/profiles/default$SOCKET_SRC" | ||||
| 
 | ||||
|     _sudo "to load the systemd unit for nix-daemon" \ | ||||
|           systemctl daemon-reload | ||||
| 
 | ||||
|     _sudo "to start the nix-daemon.socket" \ | ||||
|           systemctl start nix-daemon.socket | ||||
| 
 | ||||
|     _sudo "to start the nix-daemon.service" \ | ||||
|           systemctl start nix-daemon.service | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| poly_group_exists() { | ||||
|     getent group "$1" > /dev/null 2>&1 | ||||
| } | ||||
| 
 | ||||
| poly_group_id_get() { | ||||
|     getent group "$1" | cut -d: -f3 | ||||
| } | ||||
| 
 | ||||
| poly_create_build_group() { | ||||
|     _sudo "Create the Nix build group, $NIX_BUILD_GROUP_NAME" \ | ||||
|           groupadd -g "$NIX_BUILD_GROUP_ID" --system \ | ||||
|           "$NIX_BUILD_GROUP_NAME" >&2 | ||||
| } | ||||
| 
 | ||||
| poly_user_exists() { | ||||
|     getent passwd "$1" > /dev/null 2>&1 | ||||
| } | ||||
| 
 | ||||
| poly_user_id_get() { | ||||
|     getent passwd "$1" | cut -d: -f3 | ||||
| } | ||||
| 
 | ||||
| poly_user_hidden_get() { | ||||
|     echo "1" | ||||
| } | ||||
| 
 | ||||
| poly_user_hidden_set() { | ||||
|     true | ||||
| } | ||||
| 
 | ||||
| poly_user_home_get() { | ||||
|     getent passwd "$1" | cut -d: -f6 | ||||
| } | ||||
| 
 | ||||
| poly_user_home_set() { | ||||
|     _sudo "in order to give $1 a safe home directory" \ | ||||
|           usermod --home "$2" "$1" | ||||
| } | ||||
| 
 | ||||
| poly_user_note_get() { | ||||
|     getent passwd "$1" | cut -d: -f5 | ||||
| } | ||||
| 
 | ||||
| poly_user_note_set() { | ||||
|     _sudo "in order to give $1 a useful comment" \ | ||||
|           usermod --comment "$2" "$1" | ||||
| } | ||||
| 
 | ||||
| poly_user_shell_get() { | ||||
|     getent passwd "$1" | cut -d: -f7 | ||||
| } | ||||
| 
 | ||||
| poly_user_shell_set() { | ||||
|     _sudo "in order to prevent $1 from logging in" \ | ||||
|           usermod --shell "$2" "$1" | ||||
| } | ||||
| 
 | ||||
| poly_user_in_group_check() { | ||||
|     groups "$1" | grep -q "$2" > /dev/null 2>&1 | ||||
| } | ||||
| 
 | ||||
| poly_user_in_group_set() { | ||||
|     _sudo "Add $1 to the $2 group"\ | ||||
|           usermod --append --groups "$2" "$1" | ||||
| } | ||||
| 
 | ||||
| poly_user_primary_group_get() { | ||||
|     getent passwd "$1" | cut -d: -f4 | ||||
| } | ||||
| 
 | ||||
| poly_user_primary_group_set() { | ||||
|     _sudo "to let the nix daemon use this user for builds (this might seem redundant, but there are two concepts of group membership)" \ | ||||
|           usermod --gid "$2" "$1" | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| poly_create_build_user() { | ||||
|     username=$1 | ||||
|     uid=$2 | ||||
|     builder_num=$3 | ||||
| 
 | ||||
|     _sudo "Creating the Nix build user, $username" \ | ||||
|           useradd \ | ||||
|           --home-dir /var/empty \ | ||||
|           --comment "Nix build user $builder_num" \ | ||||
|           --gid "$NIX_BUILD_GROUP_ID" \ | ||||
|           --groups "$NIX_BUILD_GROUP_NAME" \ | ||||
|           --no-user-group \ | ||||
|           --system \ | ||||
|           --shell /sbin/nologin \ | ||||
|           --uid "$uid" \ | ||||
|           --password "!" \ | ||||
|           "$username" | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue