diff options
Diffstat (limited to 'scripts/install-darwin-multi-user.sh')
-rw-r--r-- | scripts/install-darwin-multi-user.sh | 123 |
1 files changed, 97 insertions, 26 deletions
diff --git a/scripts/install-darwin-multi-user.sh b/scripts/install-darwin-multi-user.sh index f6575ae2f..32a12f2ee 100644 --- a/scripts/install-darwin-multi-user.sh +++ b/scripts/install-darwin-multi-user.sh @@ -3,59 +3,110 @@ set -eu set -o pipefail -readonly PLIST_DEST=/Library/LaunchDaemons/org.nixos.nix-daemon.plist +readonly NIX_DAEMON_DEST=/Library/LaunchDaemons/org.nixos.nix-daemon.plist +# create by default; set 0 to DIY, use a symlink, etc. +readonly NIX_VOLUME_CREATE=${NIX_VOLUME_CREATE:-1} # now default NIX_FIRST_BUILD_UID="301" NIX_BUILD_USER_NAME_TEMPLATE="_nixbld%d" +# caution: may update times on / if not run as normal non-root user +read_only_root() { + # this touch command ~should~ always produce an error + # as of this change I confirmed /usr/bin/touch emits: + # "touch: /: Operation not permitted" Monterey + # "touch: /: Read-only file system" Catalina+ and Big Sur + # "touch: /: Permission denied" Mojave + # (not matching prefix for compat w/ coreutils touch in case using + # an explicit path causes problems; its prefix differs) + case "$(/usr/bin/touch / 2>&1)" in + *"Read-only file system") # Catalina, Big Sur + return 0 + ;; + *"Operation not permitted") # Monterey + return 0 + ;; + *) + return 1 + ;; + esac + + # Avoiding the slow semantic way to get this information (~330ms vs ~8ms) + # unless using touch causes problems. Just in case, that approach is: + # diskutil info -plist / | <find the Writable or WritableVolume keys>, i.e. + # diskutil info -plist / | xmllint --xpath "name(/plist/dict/key[text()='Writable']/following-sibling::*[1])" - +} + +if read_only_root && [ "$NIX_VOLUME_CREATE" = 1 ]; then + should_create_volume() { return 0; } +else + should_create_volume() { return 1; } +fi + +# shellcheck source=./create-darwin-volume.sh +. "$EXTRACTED_NIX_PATH/create-darwin-volume.sh" "no-main" + dsclattr() { /usr/bin/dscl . -read "$1" \ - | awk "/$2/ { print \$2 }" + | /usr/bin/awk "/$2/ { print \$2 }" +} + +test_nix_daemon_installed() { + test -e "$NIX_DAEMON_DEST" } -poly_validate_assumptions() { - if [ "$(uname -s)" != "Darwin" ]; then - failure "This script is for use with macOS!" +poly_cure_artifacts() { + if should_create_volume; then + task "Fixing any leftover Nix volume state" + cat <<EOF +Before I try to install, I'll check for any existing Nix volume config +and ask for your permission to remove it (so that the installer can +start fresh). I'll also ask for permission to fix any issues I spot. +EOF + cure_volumes + remove_volume_artifacts fi } poly_service_installed_check() { - [ -e "$PLIST_DEST" ] + if should_create_volume; then + test_nix_daemon_installed || test_nix_volume_mountd_installed + else + test_nix_daemon_installed + fi } poly_service_uninstall_directions() { - cat <<EOF -$1. Delete $PLIST_DEST - - sudo launchctl unload $PLIST_DEST - sudo rm $PLIST_DEST - -EOF + echo "$1. Remove macOS-specific components:" + if should_create_volume && test_nix_volume_mountd_installed; then + darwin_volume_uninstall_directions + fi + if test_nix_daemon_installed; then + nix_daemon_uninstall_directions + fi } poly_service_setup_note() { - cat <<EOF - - load and start a LaunchDaemon (at $PLIST_DEST) for nix-daemon - -EOF + if should_create_volume; then + echo " - create a Nix volume and a LaunchDaemon to mount it" + fi + echo " - create a LaunchDaemon (at $NIX_DAEMON_DEST) for nix-daemon" + echo "" } -poly_extra_try_me_commands(){ - : -} -poly_extra_setup_instructions(){ - : +poly_extra_try_me_commands() { + : } poly_configure_nix_daemon_service() { + task "Setting up the nix-daemon LaunchDaemon" _sudo "to set up the nix-daemon as a LaunchDaemon" \ - cp -f "/nix/var/nix/profiles/default$PLIST_DEST" "$PLIST_DEST" + /bin/cp -f "/nix/var/nix/profiles/default$NIX_DAEMON_DEST" "$NIX_DAEMON_DEST" _sudo "to load the LaunchDaemon plist for nix-daemon" \ launchctl load /Library/LaunchDaemons/org.nixos.nix-daemon.plist _sudo "to start the nix-daemon" \ - launchctl start org.nixos.nix-daemon - + launchctl kickstart -k system/org.nixos.nix-daemon } poly_group_exists() { @@ -96,6 +147,8 @@ poly_user_home_get() { } poly_user_home_set() { + # This can trigger a permission prompt now: + # "Terminal" would like to administer your computer. Administration can include modifying passwords, networking, and system settings. _sudo "in order to give $1 a safe home directory" \ /usr/bin/dscl . -create "/Users/$1" "NFSHomeDirectory" "$2" } @@ -121,7 +174,7 @@ poly_user_shell_set() { poly_user_in_group_check() { username=$1 group=$2 - dseditgroup -o checkmember -m "$username" "$group" > /dev/null 2>&1 + /usr/sbin/dseditgroup -o checkmember -m "$username" "$group" > /dev/null 2>&1 } poly_user_in_group_set() { @@ -151,3 +204,21 @@ poly_create_build_user() { /usr/bin/dscl . create "/Users/$username" \ UniqueID "${uid}" } + +poly_prepare_to_install() { + if should_create_volume; then + header "Preparing a Nix volume" + # intentional indent below to match task indent + cat <<EOF + Nix traditionally stores its data in the root directory $NIX_ROOT, but + macOS now (starting in 10.15 Catalina) has a read-only root directory. + To support Nix, I will create a volume and configure macOS to mount it + at $NIX_ROOT. +EOF + setup_darwin_volume + fi + + if [ "$(diskutil info -plist /nix | xmllint --xpath "(/plist/dict/key[text()='GlobalPermissionsEnabled'])/following-sibling::*[1]" -)" = "<false/>" ]; then + failure "This script needs a /nix volume with global permissions! This may require running sudo diskutil enableOwnership /nix." + fi +} |