diff --git a/scripts/sequoia-nixbld-user-migration.sh b/scripts/sequoia-nixbld-user-migration.sh old mode 100644 new mode 100755 index 778a95688104..98923d0f8a6c --- a/scripts/sequoia-nixbld-user-migration.sh +++ b/scripts/sequoia-nixbld-user-migration.sh @@ -2,35 +2,110 @@ ((NEW_NIX_FIRST_BUILD_UID=331)) -id_available(){ - dscl . list /Users UniqueID | grep -E '\b'"$1"'\b' >/dev/null +nix_user_n() { + printf "_nixbld%d" "$1" } -change_nixbld_names_and_ids(){ - local name uid next_id +id_unavailable(){ + # treat UID as unavailable if a non-nixbld user is using it + # - list all users + UIDs + # - filter out all _nixbld\d+ users + # - check against remaining + dscl . list /Users UniqueID | grep -vE '\b_nixbld[0-9]+\b' | grep -E '\b'"$1"'\b' >/dev/null +} + +any_nixbld(){ + dscl . list /Users UniqueID | grep -E '\b_nixbld' >/dev/null +} + +re_create_nixbld_user(){ + local name uid + + name="$1" + uid="$2" + + sudo /usr/bin/dscl . -create "/Users/$name" UniqueID "$uid" + sudo /usr/bin/dscl . -create "/Users/$name" "IsHidden" "1" + sudo /usr/bin/dscl . -create "/Users/$name" "NFSHomeDirectory" "/var/empty" + sudo /usr/bin/dscl . -create "/Users/$name" "RealName" "Nix build user $uid" + sudo /usr/bin/dscl . -create "/Users/$name" "UserShell" "/sbin/nologin" + sudo /usr/bin/dscl . -create "/Users/$name" "PrimaryGroupID" "$NEW_NIX_FIRST_BUILD_UID" +} + +hit_id_cap(){ + echo "We've hit UID 400 without placing all of your users :(" + echo "You should use the commands in this script as a starting" + echo "point to review your UID-space and manually move the" + echo "remaining users (or delete them, if you don't need them)." +} + +change_nixbld_uids(){ + local name next_id user_n + ((next_id=NEW_NIX_FIRST_BUILD_UID)) + ((user_n=1)) + name="$(nix_user_n "$user_n")" + echo "Attempting to migrate _nixbld users." + + echo "Migrating nixbld group to GID $NEW_NIX_FIRST_BUILD_UID" + sudo dscl . -create "/Groups/nixbld" PrimaryGroupID "$NEW_NIX_FIRST_BUILD_UID" + + # we know that we have *some* nixbld users, but macOS may have + # already clobbered the first few users if this system has been + # upgraded + + echo "Checking first for missing early users." + + until dscl . read "/Users/$name" &>/dev/null; do + # iterate for a clean ID + while id_unavailable "$next_id"; do + ((next_id++)) + if ((next_id >= 400)); then + hit_id_cap + exit 1 + fi + done + + re_create_nixbld_user "$name" "$next_id" + echo " $name was missing; created with uid: $next_id" + + ((user_n++)) + name="$(nix_user_n "$user_n")" + done + echo "Each _nixbld# user should have its UID moved to $next_id+" - while read -r name uid; do - echo " Checking $name (uid: $uid)" + + # start at _nixbld1 and increment until _nixbld doesn't exist + while dscl . read "/Users/$name" &>/dev/null; do # iterate for a clean ID - while id_available "$next_id"; do + while id_unavailable "$next_id"; do ((next_id++)) if ((next_id >= 400)); then - echo "We've hit UID 400 without placing all of your users :(" - echo "You should use the commands in this script as a starting" - echo "point to review your UID-space and manually move the" - echo "remaining users (or delete them, if you don't need them)." + hit_id_cap exit 1 fi done - # first 2 are cleanup, it's OK if they aren't here - sudo dscl . delete "/Users/$name" dsAttrTypeNative:_writers_passwd &>/dev/null || true - sudo dscl . change "/Users/$name" NFSHomeDirectory "/private/var/empty 1" "/var/empty" &>/dev/null || true - sudo dscl . change "/Users/$name" UniqueID "$uid" "$next_id" + sudo dscl . -create "/Users/$name" UniqueID "$next_id" echo " $name migrated to uid: $next_id" - done < <(dscl . list /Users UniqueID | grep _nixbld | sort -n -k2) + + ((user_n++)) + name="$(nix_user_n "$user_n")" + done + + if ((user_n == 1)); then + echo "Didn't find _nixbld1. Perhaps you have single-user Nix?" + exit 1 + else + echo "Migrated $((user_n - 1)) users. If you want to double-check, try:" + echo "dscl . list /Users UniqueID | grep _nixbld | sort -n -k2" + fi } -change_nixbld_names_and_ids +if any_nixbld; then + change_nixbld_uids +else + echo "Didn't find any _nixbld users. Perhaps you have single-user Nix?" + exit 1 +fi