From de7b485928c3fb95b0c83b81620f5274e79926c6 Mon Sep 17 00:00:00 2001 From: "Travis A. Everett" Date: Thu, 18 Jul 2024 09:56:57 -0500 Subject: [PATCH] add script to migrate macOS 15 Sequoia nixbld UIDs While we don't have any easy way to forcibly notify everyone about the impending breakage (or forcibly migrate the users on their system), this script enables those who do hear about the problem to migrate their systems before they take the macOS update. It should also enable people who only discover it after the update when a build fails to ~fix their installs without a full reinstall. --- scripts/sequoia-nixbld-user-migration.sh | 109 +++++++++++++++++++---- 1 file changed, 92 insertions(+), 17 deletions(-) mode change 100644 => 100755 scripts/sequoia-nixbld-user-migration.sh 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