summary refs log tree commit diff
path: root/nixos/modules/installer/tools/nixos-install.sh
blob: e7cf52f5e32bd0ad0dc975f87bf2167335b33a79 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
#! @runtimeShell@
# shellcheck shell=bash

set -e
shopt -s nullglob

export PATH=@path@:$PATH

# Ensure a consistent umask.
umask 0022

# Parse the command line for the -I flag
extraBuildFlags=()
flakeFlags=()

mountPoint=/mnt
channelPath=
system=
verbosity=()

while [ "$#" -gt 0 ]; do
    i="$1"; shift 1
    case "$i" in
        --max-jobs|-j|--cores|-I|--substituters)
            j="$1"; shift 1
            extraBuildFlags+=("$i" "$j")
            ;;
        --option)
            j="$1"; shift 1
            k="$1"; shift 1
            extraBuildFlags+=("$i" "$j" "$k")
            ;;
        --root)
            mountPoint="$1"; shift 1
            ;;
        --system|--closure)
            system="$1"; shift 1
            ;;
        --flake)
          flake="$1"
          flakeFlags=(--experimental-features 'nix-command flakes')
          shift 1
          ;;
        --recreate-lock-file|--no-update-lock-file|--no-write-lock-file|--no-registries|--commit-lock-file)
          lockFlags+=("$i")
          ;;
        --update-input)
          j="$1"; shift 1
          lockFlags+=("$i" "$j")
          ;;
        --override-input)
          j="$1"; shift 1
          k="$1"; shift 1
          lockFlags+=("$i" "$j" "$k")
          ;;
        --channel)
            channelPath="$1"; shift 1
            ;;
        --no-channel-copy)
            noChannelCopy=1
            ;;
        --no-root-password|--no-root-passwd)
            noRootPasswd=1
            ;;
        --no-bootloader)
            noBootLoader=1
            ;;
        --show-trace|--impure|--keep-going)
            extraBuildFlags+=("$i")
            ;;
        --help)
            exec man nixos-install
            exit 1
            ;;
        --debug)
            set -x
            ;;
        -v*|--verbose)
            verbosity+=("$i")
            ;;
        *)
            echo "$0: unknown option \`$i'"
            exit 1
            ;;
    esac
done

if ! test -e "$mountPoint"; then
    echo "mount point $mountPoint doesn't exist"
    exit 1
fi

# Verify permissions are okay-enough
checkPath="$(realpath "$mountPoint")"
while [[ "$checkPath" != "/" ]]; do
    mode="$(stat -c '%a' "$checkPath")"
    if [[ "${mode: -1}" -lt "5" ]]; then
        echo "path $checkPath should have permissions 755, but had permissions $mode. Consider running 'chmod o+rx $checkPath'."
        exit 1
    fi
    checkPath="$(dirname "$checkPath")"
done

# Get the path of the NixOS configuration file.
if [[ -z $NIXOS_CONFIG ]]; then
    NIXOS_CONFIG=$mountPoint/etc/nixos/configuration.nix
fi

if [[ ${NIXOS_CONFIG:0:1} != / ]]; then
    echo "$0: \$NIXOS_CONFIG is not an absolute path"
    exit 1
fi

if [[ -n $flake ]]; then
    if [[ $flake =~ ^(.*)\#([^\#\"]*)$ ]]; then
       flake="${BASH_REMATCH[1]}"
       flakeAttr="${BASH_REMATCH[2]}"
    fi
    if [[ -z "$flakeAttr" ]]; then
        echo "Please specify the name of the NixOS configuration to be installed, as a URI fragment in the flake-uri."
        echo "For example, to use the output nixosConfigurations.foo from the flake.nix, append \"#foo\" to the flake-uri."
        exit 1
    fi
    flakeAttr="nixosConfigurations.\"$flakeAttr\""
fi

# Resolve the flake.
if [[ -n $flake ]]; then
    flake=$(nix "${flakeFlags[@]}" flake metadata --json "${extraBuildFlags[@]}" "${lockFlags[@]}" -- "$flake" | jq -r .url)
fi

if [[ ! -e $NIXOS_CONFIG && -z $system && -z $flake ]]; then
    echo "configuration file $NIXOS_CONFIG doesn't exist"
    exit 1
fi

# A place to drop temporary stuff.
tmpdir="$(mktemp -d -p "$mountPoint")"
trap 'rm -rf $tmpdir' EXIT

# store temporary files on target filesystem by default
export TMPDIR=${TMPDIR:-$tmpdir}

sub="auto?trusted=1"

# Copy the NixOS/Nixpkgs sources to the target as the initial contents
# of the NixOS channel.
if [[ -z $noChannelCopy ]]; then
    if [[ -z $channelPath ]]; then
        channelPath="$(nix-env -p /nix/var/nix/profiles/per-user/root/channels -q nixos --no-name --out-path 2>/dev/null || echo -n "")"
    fi
    if [[ -n $channelPath ]]; then
        echo "copying channel..."
        mkdir -p "$mountPoint"/nix/var/nix/profiles/per-user/root
        nix-env --store "$mountPoint" "${extraBuildFlags[@]}" --extra-substituters "$sub" \
                -p "$mountPoint"/nix/var/nix/profiles/per-user/root/channels --set "$channelPath" --quiet \
                "${verbosity[@]}"
        install -m 0700 -d "$mountPoint"/root/.nix-defexpr
        ln -sfn /nix/var/nix/profiles/per-user/root/channels "$mountPoint"/root/.nix-defexpr/channels
    fi
fi

# Build the system configuration in the target filesystem.
if [[ -z $system ]]; then
    outLink="$tmpdir/system"
    if [[ -z $flake ]]; then
        echo "building the configuration in $NIXOS_CONFIG..."
        nix-build --out-link "$outLink" --store "$mountPoint" "${extraBuildFlags[@]}" \
            --extra-substituters "$sub" \
            '<nixpkgs/nixos>' -A system -I "nixos-config=$NIXOS_CONFIG" "${verbosity[@]}"
    else
        echo "building the flake in $flake..."
        nix "${flakeFlags[@]}" build "$flake#$flakeAttr.config.system.build.toplevel" \
            --store "$mountPoint" --extra-substituters "$sub" "${verbosity[@]}" \
            "${extraBuildFlags[@]}" "${lockFlags[@]}" --out-link "$outLink"
    fi
    system=$(readlink -f "$outLink")
fi

# Set the system profile to point to the configuration. TODO: combine
# this with the previous step once we have a nix-env replacement with
# a progress bar.
nix-env --store "$mountPoint" "${extraBuildFlags[@]}" \
        --extra-substituters "$sub" \
        -p "$mountPoint"/nix/var/nix/profiles/system --set "$system" "${verbosity[@]}"

# Mark the target as a NixOS installation, otherwise switch-to-configuration will chicken out.
mkdir -m 0755 -p "$mountPoint/etc"
touch "$mountPoint/etc/NIXOS"

# Switch to the new system configuration.  This will install Grub with
# a menu default pointing at the kernel/initrd/etc of the new
# configuration.
if [[ -z $noBootLoader ]]; then
    echo "installing the boot loader..."
    # Grub needs an mtab.
    ln -sfn /proc/mounts "$mountPoint"/etc/mtab
    NIXOS_INSTALL_BOOTLOADER=1 nixos-enter --root "$mountPoint" -- /run/current-system/bin/switch-to-configuration boot
fi

# Ask the user to set a root password, but only if the passwd command
# exists (i.e. when mutable user accounts are enabled).
if [[ -z $noRootPasswd ]] && [ -t 0 ]; then
    if nixos-enter --root "$mountPoint" -c 'test -e /nix/var/nix/profiles/system/sw/bin/passwd'; then
        set +e
        nixos-enter --root "$mountPoint" -c 'echo "setting root password..." && /nix/var/nix/profiles/system/sw/bin/passwd'
        exit_code=$?
        set -e

        if [[ $exit_code != 0 ]]; then
            echo "Setting a root password failed with the above printed error."
            echo "You can set the root password manually by executing \`nixos-enter --root ${mountPoint@Q}\` and then running \`passwd\` in the shell of the new system."
            exit $exit_code
        fi
    fi
fi

echo "installation finished!"