aboutsummaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2020-05-28 12:55:24 +0200
committerEelco Dolstra <edolstra@gmail.com>2020-05-28 12:55:24 +0200
commit17ca997fc6875071c7c0027b7a23c732c3ad02ee (patch)
treecf820d38955dee7cf33b36502f5b62b78b466a95 /scripts
parentc3eff22f46cc05ddae4f648413ab115edb817ef9 (diff)
parentd2a537568a7ed3fa8bee63c4298b771a27fdad89 (diff)
Merge remote-tracking branch 'origin/master' into flakes
Diffstat (limited to 'scripts')
-rwxr-xr-xscripts/create-darwin-volume.sh185
-rw-r--r--scripts/install-multi-user.sh31
-rw-r--r--scripts/install-nix-from-closure.sh129
-rw-r--r--scripts/install.in4
4 files changed, 306 insertions, 43 deletions
diff --git a/scripts/create-darwin-volume.sh b/scripts/create-darwin-volume.sh
new file mode 100755
index 000000000..dac30d72d
--- /dev/null
+++ b/scripts/create-darwin-volume.sh
@@ -0,0 +1,185 @@
+#!/bin/sh
+set -e
+
+root_disk() {
+ diskutil info -plist /
+}
+
+apfs_volumes_for() {
+ disk=$1
+ diskutil apfs list -plist "$disk"
+}
+
+disk_identifier() {
+ xpath "/plist/dict/key[text()='ParentWholeDisk']/following-sibling::string[1]/text()" 2>/dev/null
+}
+
+volume_list_true() {
+ key=$1
+ xpath "/plist/dict/array/dict/key[text()='Volumes']/following-sibling::array/dict/key[text()='$key']/following-sibling::true[1]" 2> /dev/null
+}
+
+volume_get_string() {
+ key=$1 i=$2
+ xpath "/plist/dict/array/dict/key[text()='Volumes']/following-sibling::array/dict[$i]/key[text()='$key']/following-sibling::string[1]/text()" 2> /dev/null
+}
+
+find_nix_volume() {
+ disk=$1
+ i=1
+ volumes=$(apfs_volumes_for "$disk")
+ while true; do
+ name=$(echo "$volumes" | volume_get_string "Name" "$i")
+ if [ -z "$name" ]; then
+ break
+ fi
+ case "$name" in
+ [Nn]ix*)
+ echo "$name"
+ break
+ ;;
+ esac
+ i=$((i+1))
+ done
+}
+
+test_fstab() {
+ grep -q "/nix apfs rw" /etc/fstab 2>/dev/null
+}
+
+test_nix_symlink() {
+ [ -L "/nix" ] || grep -q "^nix." /etc/synthetic.conf 2>/dev/null
+}
+
+test_synthetic_conf() {
+ grep -q "^nix$" /etc/synthetic.conf 2>/dev/null
+}
+
+test_nix() {
+ test -d "/nix"
+}
+
+test_t2_chip_present(){
+ # Use xartutil to see if system has a t2 chip.
+ #
+ # This isn't well-documented on its own; until it is,
+ # let's keep track of knowledge/assumptions.
+ #
+ # Warnings:
+ # - Don't search "xart" if porn will cause you trouble :)
+ # - Other xartutil flags do dangerous things. Don't run them
+ # naively. If you must, search "xartutil" first.
+ #
+ # Assumptions:
+ # - the "xART session seeds recovery utility"
+ # appears to interact with xartstorageremoted
+ # - `sudo xartutil --list` lists xART sessions
+ # and their seeds and exits 0 if successful. If
+ # not, it exits 1 and prints an error such as:
+ # xartutil: ERROR: No supported link to the SEP present
+ # - xART sessions/seeds are present when a T2 chip is
+ # (and not, otherwise)
+ # - the presence of a T2 chip means a newly-created
+ # volume on the primary drive will be
+ # encrypted at rest
+ # - all together: `sudo xartutil --list`
+ # should exit 0 if a new Nix Store volume will
+ # be encrypted at rest, and exit 1 if not.
+ sudo xartutil --list >/dev/null 2>/dev/null
+}
+
+test_filevault_in_use() {
+ disk=$1
+ # list vols on disk | get value of Filevault key | value is true
+ apfs_volumes_for "$disk" | volume_list_true FileVault | grep -q true
+}
+
+# use after error msg for conditions we don't understand
+suggest_report_error(){
+ # ex "error: something sad happened :(" >&2
+ echo " please report this @ https://github.com/nixos/nix/issues" >&2
+}
+
+main() {
+ (
+ echo ""
+ echo " ------------------------------------------------------------------ "
+ echo " | This installer will create a volume for the nix store and |"
+ echo " | configure it to mount at /nix. Follow these steps to uninstall. |"
+ echo " ------------------------------------------------------------------ "
+ echo ""
+ echo " 1. Remove the entry from fstab using 'sudo vifs'"
+ echo " 2. Destroy the data volume using 'diskutil apfs deleteVolume'"
+ echo " 3. Remove the 'nix' line from /etc/synthetic.conf or the file"
+ echo ""
+ ) >&2
+
+ if test_nix_symlink; then
+ echo "error: /nix is a symlink, please remove it and make sure it's not in synthetic.conf (in which case a reboot is required)" >&2
+ echo " /nix -> $(readlink "/nix")" >&2
+ exit 2
+ fi
+
+ if ! test_synthetic_conf; then
+ echo "Configuring /etc/synthetic.conf..." >&2
+ echo nix | sudo tee -a /etc/synthetic.conf
+ if ! test_synthetic_conf; then
+ echo "error: failed to configure synthetic.conf;" >&2
+ suggest_report_error
+ exit 1
+ fi
+ fi
+
+ if ! test_nix; then
+ echo "Creating mountpoint for /nix..." >&2
+ /System/Library/Filesystems/apfs.fs/Contents/Resources/apfs.util -B || true
+ if ! test_nix; then
+ sudo mkdir -p /nix 2>/dev/null || true
+ fi
+ if ! test_nix; then
+ echo "error: failed to bootstrap /nix; if a reboot doesn't help," >&2
+ suggest_report_error
+ exit 1
+ fi
+ fi
+
+ disk=$(root_disk | disk_identifier)
+ volume=$(find_nix_volume "$disk")
+ if [ -z "$volume" ]; then
+ echo "Creating a Nix Store volume..." >&2
+
+ if test_filevault_in_use "$disk"; then
+ # TODO: Not sure if it's in-scope now, but `diskutil apfs list`
+ # shows both filevault and encrypted at rest status, and it
+ # may be the more semantic way to test for this? It'll show
+ # `FileVault: No (Encrypted at rest)`
+ # `FileVault: No`
+ # `FileVault: Yes (Unlocked)`
+ # and so on.
+ if test_t2_chip_present; then
+ echo "warning: boot volume is FileVault-encrypted, but the Nix store volume" >&2
+ echo " is only encrypted at rest." >&2
+ echo " See https://nixos.org/nix/manual/#sect-macos-installation" >&2
+ else
+ echo "error: refusing to create Nix store volume because the boot volume is" >&2
+ echo " FileVault encrypted, but encryption-at-rest is not available." >&2
+ echo " Manually create a volume for the store and re-run this script." >&2
+ echo " See https://nixos.org/nix/manual/#sect-macos-installation" >&2
+ exit 1
+ fi
+ fi
+
+ sudo diskutil apfs addVolume "$disk" APFS 'Nix Store' -mountpoint /nix
+ volume="Nix Store"
+ else
+ echo "Using existing '$volume' volume" >&2
+ fi
+
+ if ! test_fstab; then
+ echo "Configuring /etc/fstab..." >&2
+ label=$(echo "$volume" | sed 's/ /\\040/g')
+ printf "\$a\nLABEL=%s /nix apfs rw,nobrowse\n.\nwq\n" "$label" | EDITOR=ed sudo vifs
+ fi
+}
+
+main "$@"
diff --git a/scripts/install-multi-user.sh b/scripts/install-multi-user.sh
index a0f1deb98..157e8ddb4 100644
--- a/scripts/install-multi-user.sh
+++ b/scripts/install-multi-user.sh
@@ -20,15 +20,18 @@ readonly GREEN='\033[32m'
readonly GREEN_UL='\033[4;32m'
readonly RED='\033[31m'
-readonly NIX_USER_COUNT="32"
+# installer allows overriding build user count to speed up installation
+# as creating each user takes non-trivial amount of time on macos
+readonly NIX_USER_COUNT=${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 NIX_EXTRA_CONF=${NIX_EXTRA_CONF:-}
-readonly PROFILE_TARGETS=("/etc/bashrc" "/etc/profile.d/nix.sh" "/etc/zshrc")
+readonly PROFILE_TARGETS=("/etc/bashrc" "/etc/profile.d/nix.sh" "/etc/zshenv")
readonly PROFILE_BACKUP_SUFFIX=".backup-before-nix"
readonly PROFILE_NIX_FILE="$NIX_ROOT/var/nix/profiles/default/etc/profile.d/nix-daemon.sh"
@@ -450,9 +453,11 @@ create_directories() {
}
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"
+ if [ -z "${NIX_INSTALLER_NO_CHANNEL_ADD:-}" ]; then
+ 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"
+ fi
}
welcome_to_nix() {
@@ -634,18 +639,20 @@ setup_default_profile() {
export NIX_SSL_CERT_FILE=/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt
fi
- # Have to explicitly pass NIX_SSL_CERT_FILE as part of the sudo call,
- # otherwise it will be lost in environments where sudo doesn't pass
- # all the environment variables by default.
- _sudo "to update the default channel in the default profile" \
- HOME="$ROOT_HOME" NIX_SSL_CERT_FILE="$NIX_SSL_CERT_FILE" "$NIX_INSTALLED_NIX/bin/nix-channel" --update nixpkgs \
- || channel_update_failed=1
-
+ if [ -z "${NIX_INSTALLER_NO_CHANNEL_ADD:-}" ]; then
+ # Have to explicitly pass NIX_SSL_CERT_FILE as part of the sudo call,
+ # otherwise it will be lost in environments where sudo doesn't pass
+ # all the environment variables by default.
+ _sudo "to update the default channel in the default profile" \
+ HOME="$ROOT_HOME" NIX_SSL_CERT_FILE="$NIX_SSL_CERT_FILE" "$NIX_INSTALLED_NIX/bin/nix-channel" --update nixpkgs \
+ || channel_update_failed=1
+ fi
}
place_nix_configuration() {
cat <<EOF > "$SCRATCH/nix.conf"
+$NIX_EXTRA_CONF
build-users-group = $NIX_BUILD_GROUP_NAME
EOF
_sudo "to place the default nix daemon configuration (part 2)" \
diff --git a/scripts/install-nix-from-closure.sh b/scripts/install-nix-from-closure.sh
index e00708f6c..826ca8b8c 100644
--- a/scripts/install-nix-from-closure.sh
+++ b/scripts/install-nix-from-closure.sh
@@ -40,29 +40,85 @@ elif [ "$(uname -s)" = "Linux" ] && [ -e /run/systemd/system ]; then
fi
INSTALL_MODE=no-daemon
-# Trivially handle the --daemon / --no-daemon options
-if [ "x${1:-}" = "x--no-daemon" ]; then
- INSTALL_MODE=no-daemon
-elif [ "x${1:-}" = "x--daemon" ]; then
- INSTALL_MODE=daemon
-elif [ "x${1:-}" != "x" ]; then
- (
- echo "Nix Installer [--daemon|--no-daemon]"
-
- echo "Choose installation method."
- echo ""
- echo " --daemon: Installs and configures a background daemon that manages the store,"
- echo " providing multi-user support and better isolation for local builds."
- echo " Both for security and reproducibility, this method is recommended if"
- echo " supported on your platform."
- echo " See https://nixos.org/nix/manual/#sect-multi-user-installation"
- echo ""
- echo " --no-daemon: Simple, single-user installation that does not require root and is"
- echo " trivial to uninstall."
- echo " (default)"
- echo ""
- ) >&2
- exit
+CREATE_DARWIN_VOLUME=0
+# handle the command line flags
+while [ $# -gt 0 ]; do
+ case $1 in
+ --daemon)
+ INSTALL_MODE=daemon;;
+ --no-daemon)
+ INSTALL_MODE=no-daemon;;
+ --no-channel-add)
+ export NIX_INSTALLER_NO_CHANNEL_ADD=1;;
+ --daemon-user-count)
+ export NIX_USER_COUNT=$2
+ shift;;
+ --no-modify-profile)
+ NIX_INSTALLER_NO_MODIFY_PROFILE=1;;
+ --darwin-use-unencrypted-nix-store-volume)
+ CREATE_DARWIN_VOLUME=1;;
+ --nix-extra-conf-file)
+ export NIX_EXTRA_CONF="$(cat $2)"
+ shift;;
+ *)
+ (
+ echo "Nix Installer [--daemon|--no-daemon] [--daemon-user-count INT] [--no-channel-add] [--no-modify-profile] [--darwin-use-unencrypted-nix-store-volume] [--nix-extra-conf-file FILE]"
+
+ echo "Choose installation method."
+ echo ""
+ echo " --daemon: Installs and configures a background daemon that manages the store,"
+ echo " providing multi-user support and better isolation for local builds."
+ echo " Both for security and reproducibility, this method is recommended if"
+ echo " supported on your platform."
+ echo " See https://nixos.org/nix/manual/#sect-multi-user-installation"
+ echo ""
+ echo " --no-daemon: Simple, single-user installation that does not require root and is"
+ echo " trivial to uninstall."
+ echo " (default)"
+ echo ""
+ echo " --no-channel-add: Don't add any channels. nixpkgs-unstable is installed by default."
+ echo ""
+ echo " --no-modify-profile: Skip channel installation. When not provided nixpkgs-unstable"
+ echo " is installed by default."
+ echo ""
+ echo " --daemon-user-count: Number of build users to create. Defaults to 32."
+ echo ""
+ echo " --nix-extra-conf-file: Path to nix.conf to prepend when installing /etc/nix.conf"
+ echo ""
+ ) >&2
+
+ # darwin and Catalina+
+ if [ "$(uname -s)" = "Darwin" ] && [ "$macos_major" -gt 14 ]; then
+ (
+ echo " --darwin-use-unencrypted-nix-store-volume: Create an APFS volume for the Nix"
+ echo " store and mount it at /nix. This is the recommended way to create"
+ echo " /nix with a read-only / on macOS >=10.15."
+ echo " See: https://nixos.org/nix/manual/#sect-macos-installation"
+ echo ""
+ ) >&2
+ fi
+ exit;;
+ esac
+ shift
+done
+
+if [ "$(uname -s)" = "Darwin" ]; then
+ if [ "$CREATE_DARWIN_VOLUME" = 1 ]; then
+ printf '\e[1;31mCreating volume and mountpoint /nix.\e[0m\n'
+ "$self/create-darwin-volume.sh"
+ fi
+
+ info=$(diskutil info -plist / | xpath "/plist/dict/key[text()='Writable']/following-sibling::true[1]" 2> /dev/null)
+ if ! [ -e $dest ] && [ -n "$info" ] && [ "$macos_major" -gt 14 ]; then
+ (
+ echo ""
+ echo "Installing on macOS >=10.15 requires relocating the store to an apfs volume."
+ echo "Use sh <(curl https://nixos.org/nix/install) --darwin-use-unencrypted-nix-store-volume or run the preparation steps manually."
+ echo "See https://nixos.org/nix/manual/#sect-macos-installation"
+ echo ""
+ ) >&2
+ exit 1
+ fi
fi
if [ "$INSTALL_MODE" = "daemon" ]; then
@@ -130,13 +186,15 @@ if [ -z "$NIX_SSL_CERT_FILE" ] || ! [ -f "$NIX_SSL_CERT_FILE" ]; then
fi
# Subscribe the user to the Nixpkgs channel and fetch it.
-if ! $nix/bin/nix-channel --list | grep -q "^nixpkgs "; then
- $nix/bin/nix-channel --add https://nixos.org/channels/nixpkgs-unstable
-fi
-if [ -z "$_NIX_INSTALLER_TEST" ]; then
- if ! $nix/bin/nix-channel --update nixpkgs; then
- echo "Fetching the nixpkgs channel failed. (Are you offline?)"
- echo "To try again later, run \"nix-channel --update nixpkgs\"."
+if [ -z "$NIX_INSTALLER_NO_CHANNEL_ADD" ]; then
+ if ! $nix/bin/nix-channel --list | grep -q "^nixpkgs "; then
+ $nix/bin/nix-channel --add https://nixos.org/channels/nixpkgs-unstable
+ fi
+ if [ -z "$_NIX_INSTALLER_TEST" ]; then
+ if ! $nix/bin/nix-channel --update nixpkgs; then
+ echo "Fetching the nixpkgs channel failed. (Are you offline?)"
+ echo "To try again later, run \"nix-channel --update nixpkgs\"."
+ fi
fi
fi
@@ -155,6 +213,17 @@ if [ -z "$NIX_INSTALLER_NO_MODIFY_PROFILE" ]; then
break
fi
done
+ for i in .zshenv .zshrc; do
+ fn="$HOME/$i"
+ if [ -w "$fn" ]; then
+ if ! grep -q "$p" "$fn"; then
+ echo "modifying $fn..." >&2
+ echo "if [ -e $p ]; then . $p; fi # added by Nix installer" >> "$fn"
+ fi
+ added=1
+ break
+ fi
+ done
fi
if [ -z "$added" ]; then
diff --git a/scripts/install.in b/scripts/install.in
index 6709f00d4..1d26c4ff0 100644
--- a/scripts/install.in
+++ b/scripts/install.in
@@ -36,7 +36,9 @@ tarball="$tmpDir/$(basename "$tmpDir/nix-@nixVersion@-$system.tar.xz")"
require_util curl "download the binary tarball"
require_util tar "unpack the binary tarball"
-require_util xz "unpack the binary tarball"
+if [ "$(uname -s)" != "Darwin" ]; then
+ require_util xz "unpack the binary tarball"
+fi
echo "downloading Nix @nixVersion@ binary tarball for $system from '$url' to '$tmpDir'..."
curl -L "$url" -o "$tarball" || oops "failed to download '$url'"