#!/usr/bin/env bash set -eu set -o pipefail # System specific settings # Notes: # - up to macOS Big Sur we used the same GID/UIDs as Linux (30000:30001-32) # - we changed UID to 301 because Big Sur updates failed into recovery mode # we're targeting the 200-400 UID range for role users mentioned in the # usage note for sysadminctl # - we changed UID to 350 because Sequoia now uses UIDs 300-304 for its own # daemon users # - we changed GID to 350 alongside above just because it hides the nixbld # group from the Users & Groups settings panel :) export NIX_FIRST_BUILD_UID="${NIX_FIRST_BUILD_UID:-350}" export NIX_BUILD_GROUP_ID="${NIX_BUILD_GROUP_ID:-350}" export NIX_BUILD_USER_NAME_TEMPLATE="_nixbld%d" 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 # 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 / | , 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" \ | /usr/bin/awk "/$2/ { print \$2 }" } test_nix_daemon_installed() { test -e "$NIX_DAEMON_DEST" } poly_cure_artifacts() { if should_create_volume; then task "Fixing any leftover Nix volume state" cat < /dev/null 2>&1 } poly_group_id_get() { dsclattr "/Groups/$1" "PrimaryGroupID" } 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() { # 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" } 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 shell" \ /usr/bin/dscl . -create "/Users/$1" "UserShell" "$2" } poly_user_in_group_check() { username=$1 group=$2 /usr/sbin/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}" } poly_prepare_to_install() { if should_create_volume; then header "Preparing a Nix volume" # intentional indent below to match task indent cat <