1
0
mirror of https://github.com/nix-community/home-manager synced 2024-06-25 07:58:31 +02:00
home-manager/modules/lib-bash/activation-init.sh
Robert Helgesson 6a19225683
home-manager: verify username and home directory
The generation activation script should be run by the user specified
in `home.username` and `home.homeDirectory`. If some other user runs
the activation script, then files may end up in the wrong place or
with the wrong owner.

This commits adds a check early in the activation script that verifies
that the running user match the user in the configuration.

Fixes #4019
2023-05-27 09:14:05 +02:00

159 lines
5.5 KiB
Bash
Executable File

# Moves the existing profile from /nix or $XDG_STATE_HOME/home-manager to
# $XDG_STATE_HOME/nix to match changed behavior in Nix 2.14. See
# https://github.com/NixOS/nix/pull/5226.
function migrateProfile() {
declare -r stateHome="${XDG_STATE_HOME:-$HOME/.local/state}"
declare -r userNixStateDir="$stateHome/nix"
declare -r hmStateDir="$stateHome/home-manager"
declare -r globalNixStateDir="${NIX_STATE_DIR:-/nix/var/nix}"
declare -r globalProfilesDir="$globalNixStateDir/profiles/per-user/$USER"
if [[ -e $globalProfilesDir/home-manager ]]; then
declare -r oldProfilesDir="$globalProfilesDir"
elif [[ -e $hmStateDir/profiles/home-manager ]]; then
declare -r oldProfilesDir="$hmStateDir/profiles"
fi
declare -r newProfilesDir="$userNixStateDir/profiles"
if [[ -v oldProfilesDir && -e $newProfilesDir ]]; then
if [[ ! -e $newProfilesDir/home-manager ]]; then
_i 'Migrating profile from %s to %s' "$oldProfilesDir" "$newProfilesDir"
for p in "$oldProfilesDir"/home-manager-*; do
declare name="${p##*/}"
nix-store --realise "$p" --add-root "$newProfilesDir/$name" > /dev/null
done
cp -P "$oldProfilesDir/home-manager" "$newProfilesDir"
fi
rm "$oldProfilesDir/home-manager" "$oldProfilesDir"/home-manager-*
fi
}
function setupVars() {
declare -r stateHome="${XDG_STATE_HOME:-$HOME/.local/state}"
declare -r userNixStateDir="$stateHome/nix"
declare -r hmGcrootsDir="$stateHome/home-manager/gcroots"
declare -r globalNixStateDir="${NIX_STATE_DIR:-/nix/var/nix}"
declare -r globalProfilesDir="$globalNixStateDir/profiles/per-user/$USER"
declare -r globalGcrootsDir="$globalNixStateDir/gcroots/per-user/$USER"
# If the user Nix profiles path exists, then place the HM profile there.
# Otherwise, if the global Nix per-user state directory exists then use
# that. If neither exists, then we give up.
#
# shellcheck disable=2174
if [[ -d $userNixStateDir/profiles ]]; then
declare -r profilesDir="$userNixStateDir/profiles"
elif [[ -d $globalProfilesDir ]]; then
declare -r profilesDir="$globalProfilesDir"
else
_iError 'Could not find suitable profile directory, tried %s and %s' \
"$userNixStateDir/profiles" "$globalProfilesDir" >&2
exit 1
fi
declare -gr genProfilePath="$profilesDir/home-manager"
declare -gr newGenPath="@GENERATION_DIR@";
declare -gr newGenGcPath="$hmGcrootsDir/current-home"
declare -gr legacyGenGcPath="$globalGcrootsDir/current-home"
declare greatestGenNum
greatestGenNum=$( \
nix-env --list-generations --profile "$genProfilePath" \
| tail -1 \
| sed -E 's/ *([[:digit:]]+) .*/\1/')
if [[ -n $greatestGenNum ]] ; then
declare -gr oldGenNum=$greatestGenNum
declare -gr newGenNum=$((oldGenNum + 1))
else
declare -gr newGenNum=1
fi
if [[ -e $genProfilePath ]] ; then
declare -g oldGenPath
oldGenPath="$(readlink -e "$genProfilePath")"
fi
$VERBOSE_RUN _i "Sanity checking oldGenNum and oldGenPath"
if [[ -v oldGenNum && ! -v oldGenPath
|| ! -v oldGenNum && -v oldGenPath ]]; then
_i $'The previous generation number and path are in conflict! These\nmust be either both empty or both set but are now set to\n\n \'%s\' and \'%s\'\n\nIf you don\'t mind losing previous profile generations then\nthe easiest solution is probably to run\n\n rm %s/home-manager*\n rm %s/current-home\n\nand trying home-manager switch again. Good luck!' \
"${oldGenNum:-}" "${oldGenPath:-}" \
"$profilesDir" "$hmGcrootsDir"
exit 1
fi
}
function checkUsername() {
local expectedUser="$1"
if [[ "$USER" != "$expectedUser" ]]; then
_iError 'Error: USER is set to "%s" but we expect "%s"' "$USER" "$expectedUser"
exit 1
fi
}
function checkHomeDirectory() {
local expectedHome="$1"
if ! [[ $HOME -ef $expectedHome ]]; then
_iError 'Error: HOME is set to "%s" but we expect "%s"' "$HOME" "$expectedHome"
exit 1
fi
}
if [[ -v VERBOSE ]]; then
export VERBOSE_ECHO=echo
export VERBOSE_ARG="--verbose"
export VERBOSE_RUN=""
else
export VERBOSE_ECHO=true
export VERBOSE_ARG=""
export VERBOSE_RUN=true
fi
_i "Starting Home Manager activation"
# Verify that we can connect to the Nix store and/or daemon. This will
# also create the necessary directories in profiles and gcroots.
$VERBOSE_RUN _i "Sanity checking Nix"
nix-build --expr '{}' --no-out-link
# Also make sure that the Nix profiles path is created.
nix-env -q > /dev/null 2>&1 || true
migrateProfile
setupVars
if [[ -v DRY_RUN ]] ; then
_i "This is a dry run"
export DRY_RUN_CMD=echo
export DRY_RUN_NULL=/dev/stdout
else
$VERBOSE_RUN _i "This is a live run"
export DRY_RUN_CMD=""
export DRY_RUN_NULL=/dev/null
fi
if [[ -v VERBOSE ]]; then
_i 'Using Nix version: %s' "$(nix-env --version)"
fi
$VERBOSE_RUN _i "Activation variables:"
if [[ -v oldGenNum ]] ; then
$VERBOSE_ECHO " oldGenNum=$oldGenNum"
$VERBOSE_ECHO " oldGenPath=$oldGenPath"
else
$VERBOSE_ECHO " oldGenNum undefined (first run?)"
$VERBOSE_ECHO " oldGenPath undefined (first run?)"
fi
$VERBOSE_ECHO " newGenPath=$newGenPath"
$VERBOSE_ECHO " newGenNum=$newGenNum"
$VERBOSE_ECHO " genProfilePath=$genProfilePath"
$VERBOSE_ECHO " newGenGcPath=$newGenGcPath"
$VERBOSE_ECHO " legacyGenGcPath=$legacyGenGcPath"