diff --git a/packaging/binary-tarball.nix b/packaging/binary-tarball.nix index 2050384b0..86aae0ac5 100644 --- a/packaging/binary-tarball.nix +++ b/packaging/binary-tarball.nix @@ -37,6 +37,9 @@ runCommand "nix-binary-tarball-${version}" env '' substitute ${../scripts/install-systemd-multi-user.sh} $TMPDIR/install-systemd-multi-user.sh \ --subst-var-by nix ${nix} \ --subst-var-by cacert ${cacert} + substitute ${../scripts/install-freebsd-multi-user.sh} $TMPDIR/install-freebsd-multi-user.sh \ + --subst-var-by nix ${nix} \ + --subst-var-by cacert ${cacert} substitute ${../scripts/install-multi-user.sh} $TMPDIR/install-multi-user \ --subst-var-by nix ${nix} \ --subst-var-by cacert ${cacert} @@ -48,6 +51,7 @@ runCommand "nix-binary-tarball-${version}" env '' shellcheck $TMPDIR/create-darwin-volume.sh shellcheck $TMPDIR/install-darwin-multi-user.sh shellcheck $TMPDIR/install-systemd-multi-user.sh + shellcheck $TMPDIR/install-freebsd-multi-user.sh # SC1091: Don't panic about not being able to source # /etc/profile @@ -64,6 +68,7 @@ runCommand "nix-binary-tarball-${version}" env '' chmod +x $TMPDIR/create-darwin-volume.sh chmod +x $TMPDIR/install-darwin-multi-user.sh chmod +x $TMPDIR/install-systemd-multi-user.sh + chmod +x $TMPDIR/install-freebsd-multi-user.sh chmod +x $TMPDIR/install-multi-user dir=nix-${version}-${system} fn=$out/$dir.tar.xz @@ -82,6 +87,7 @@ runCommand "nix-binary-tarball-${version}" env '' $TMPDIR/create-darwin-volume.sh \ $TMPDIR/install-darwin-multi-user.sh \ $TMPDIR/install-systemd-multi-user.sh \ + $TMPDIR/install-freebsd-multi-user.sh \ $TMPDIR/install-multi-user \ $TMPDIR/reginfo \ $(cat ${installerClosureInfo}/store-paths) diff --git a/scripts/install-freebsd-multi-user.sh b/scripts/install-freebsd-multi-user.sh new file mode 100644 index 000000000..0d8b85ec4 --- /dev/null +++ b/scripts/install-freebsd-multi-user.sh @@ -0,0 +1,173 @@ +#!/usr/bin/env bash + +set -eu +set -o pipefail + +# System specific settings +# FreeBSD typically uses UIDs from 1001+ for regular users, +# so we'll use a range that's unlikely to conflict +export NIX_FIRST_BUILD_UID="${NIX_FIRST_BUILD_UID:-30001}" +export NIX_BUILD_GROUP_ID="${NIX_BUILD_GROUP_ID:-30000}" +export NIX_BUILD_USER_NAME_TEMPLATE="nixbld%d" + +# FreeBSD service paths +readonly SERVICE_SRC=/etc/rc.d/nix-daemon +readonly SERVICE_DEST=/usr/local/etc/rc.d/nix-daemon + +poly_cure_artifacts() { + : +} + +poly_service_installed_check() { + if [ -f "$SERVICE_DEST" ]; then + return 0 + else + return 1 + fi +} + +poly_service_uninstall_directions() { + cat < /dev/null 2>&1 +} + +poly_group_id_get() { + pw group show "$1" | cut -d: -f3 +} + +poly_create_build_group() { + _sudo "Create the Nix build group, $NIX_BUILD_GROUP_NAME" \ + pw groupadd -n "$NIX_BUILD_GROUP_NAME" -g "$NIX_BUILD_GROUP_ID" >&2 +} + +poly_user_exists() { + pw user show "$1" > /dev/null 2>&1 +} + +poly_user_id_get() { + pw user show "$1" | cut -d: -f3 +} + +poly_user_hidden_get() { + # FreeBSD doesn't have a concept of hidden users like macOS + echo "0" +} + +poly_user_hidden_set() { + # No-op on FreeBSD + true +} + +poly_user_home_get() { + pw user show "$1" | cut -d: -f9 +} + +poly_user_home_set() { + _sudo "in order to give $1 a safe home directory" \ + pw usermod -n "$1" -d "$2" +} + +poly_user_note_get() { + pw user show "$1" | cut -d: -f8 +} + +poly_user_note_set() { + _sudo "in order to give $1 a useful comment" \ + pw usermod -n "$1" -c "$2" +} + +poly_user_shell_get() { + pw user show "$1" | cut -d: -f10 +} + +poly_user_shell_set() { + _sudo "in order to prevent $1 from logging in" \ + pw usermod -n "$1" -s "$2" +} + +poly_user_in_group_check() { + groups "$1" 2>/dev/null | grep -q "\<$2\>" +} + +poly_user_in_group_set() { + _sudo "Add $1 to the $2 group" \ + pw groupmod -n "$2" -m "$1" +} + +poly_user_primary_group_get() { + pw user show "$1" | cut -d: -f4 +} + +poly_user_primary_group_set() { + _sudo "to let the nix daemon use this user for builds" \ + pw usermod -n "$1" -g "$2" +} + +poly_create_build_user() { + username=$1 + uid=$2 + builder_num=$3 + + _sudo "Creating the Nix build user, $username" \ + pw useradd \ + -n "$username" \ + -u "$uid" \ + -g "$NIX_BUILD_GROUP_NAME" \ + -G "$NIX_BUILD_GROUP_NAME" \ + -d /var/empty \ + -s /sbin/nologin \ + -c "Nix build user $builder_num" +} + +poly_prepare_to_install() { + # FreeBSD-specific preparation steps + : +} + +poly_configure_default_profile_targets() { + # FreeBSD-specific profile locations + # FreeBSD uses /usr/local/etc for third-party shell configurations + # Include both profile (for login shells) and bashrc (for interactive shells) + echo "/usr/local/etc/profile /usr/local/etc/bashrc /usr/local/etc/profile.d/nix.sh /usr/local/etc/zshrc" +} diff --git a/scripts/install-multi-user.sh b/scripts/install-multi-user.sh index e9ddfc014..477eb1fd6 100644 --- a/scripts/install-multi-user.sh +++ b/scripts/install-multi-user.sh @@ -33,7 +33,8 @@ readonly NIX_BUILD_GROUP_NAME="nixbld" readonly NIX_ROOT="/nix" readonly NIX_EXTRA_CONF=${NIX_EXTRA_CONF:-} -readonly PROFILE_TARGETS=("/etc/bashrc" "/etc/profile.d/nix.sh" "/etc/zshrc" "/etc/bash.bashrc" "/etc/zsh/zshrc") +# PROFILE_TARGETS will be set later after OS-specific scripts are loaded +PROFILE_TARGETS=() readonly PROFILE_BACKUP_SUFFIX=".backup-before-nix" readonly PROFILE_NIX_FILE="$NIX_ROOT/var/nix/profiles/default/etc/profile.d/nix-daemon.sh" @@ -99,6 +100,14 @@ is_os_darwin() { fi } +is_os_freebsd() { + if [ "$(uname -s)" = "FreeBSD" ]; then + return 0 + else + return 1 + fi +} + contact_us() { echo "You can open an issue at" echo "https://github.com/NixOS/nix/issues/new?labels=installer&template=installer.md" @@ -498,6 +507,10 @@ You have aborted the installation. EOF fi fi + + if is_os_freebsd; then + ok "Detected FreeBSD, will set up rc.d service for nix-daemon" + fi } setup_report() { @@ -834,7 +847,7 @@ install_from_extracted_nix() { ( cd "$EXTRACTED_NIX_PATH" - if is_os_darwin; then + if is_os_darwin || is_os_freebsd; then _sudo "to copy the basic Nix files to the new store at $NIX_ROOT/store" \ cp -RPp ./store/* "$NIX_ROOT/store/" else @@ -989,11 +1002,22 @@ main() { # shellcheck source=./install-systemd-multi-user.sh . "$EXTRACTED_NIX_PATH/install-systemd-multi-user.sh" # most of this works on non-systemd distros also check_required_system_specific_settings "install-systemd-multi-user.sh" + elif is_os_freebsd; then + # shellcheck source=./install-freebsd-multi-user.sh + . "$EXTRACTED_NIX_PATH/install-freebsd-multi-user.sh" + check_required_system_specific_settings "install-freebsd-multi-user.sh" else failure "Sorry, I don't know what to do on $(uname)" fi + # Set profile targets after OS-specific scripts are loaded + if command -v poly_configure_default_profile_targets > /dev/null 2>&1; then + PROFILE_TARGETS=($(poly_configure_default_profile_targets)) + else + PROFILE_TARGETS=("/etc/bashrc" "/etc/profile.d/nix.sh" "/etc/zshrc" "/etc/bash.bashrc" "/etc/zsh/zshrc") + fi + welcome_to_nix if ! is_root; then diff --git a/scripts/install-nix-from-tarball.sh b/scripts/install-nix-from-tarball.sh index 70fd4897a..fd00460ec 100644 --- a/scripts/install-nix-from-tarball.sh +++ b/scripts/install-nix-from-tarball.sh @@ -41,7 +41,7 @@ EOF fi # Determine if we could use the multi-user installer or not -if [ "$OS" = "Linux" ]; then +if [ "$OS" = "Linux" ] || [ "$OS" = "FreeBSD" ]; then echo "Note: a multi-user installation is possible. See https://nix.dev/manual/nix/stable/installation/installing-binary.html#multi-user-installation" >&2 fi @@ -125,6 +125,13 @@ while [ $# -gt 0 ]; do done if [ "$INSTALL_MODE" = "daemon" ]; then + # Check for bash on systems that don't have it by default + if [ "$OS" = "FreeBSD" ] && ! command -v bash >/dev/null 2>&1; then + printf '\e[1;31mError: bash is required for multi-user installation but was not found.\e[0m\n' >&2 + printf 'Please install bash first:\n' >&2 + printf ' pkg install bash\n' >&2 + exit 1 + fi printf '\e[1;31mSwitching to the Multi-user Installer\e[0m\n' exec "$self/install-multi-user" $ACTION exit 0