#!/bin/sh # GNU Guix --- Functional package management for GNU # Copyright © 2017 sharlatan # Copyright © 2018 Ricardo Wurmus # Copyright © 2018 Efraim Flashner # Copyright © 2019–2020, 2022 Tobias Geerinckx-Rice # Copyright © 2020 Morgan Smith # Copyright © 2020 Simon Tournier # Copyright © 2020 Daniel Brooks # Copyright © 2021 Jakub Kądziołka # Copyright © 2021 Chris Marusich # Copyright © 2021, 2022, 2023 Maxim Cournoyer # Copyright © 2022 Prafulla Giri # Copyright © 2023 Andrew Tropin # # This file is part of GNU Guix. # # GNU Guix is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or (at # your option) any later version. # # GNU Guix is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU Guix. If not, see . # We require Bash but for portability we'd rather not use /bin/bash or # /usr/bin/env in the shebang, hence this hack. # Environment variables # # GUIX_BINARY_FILE_NAME # # Can be used to override the automatic download mechanism and point # to a local Guix binary archive filename like # "/tmp/guix-binary-1.4.0rc2.armhf-linux.tar.xz" # # GUIX_ALLOW_OVERWRITE # # Instead of aborting to avoid overwriting a previous installations, # allow copying over /var/guix or /gnu. This can be useful when the # installation required the user to extract Guix packs under /gnu to # satisfy its dependencies. if [ "x$BASH_VERSION" = "x" ] then exec bash "$0" "$@" fi set -eo pipefail [ "$UID" -eq 0 ] || { echo "This script must be run as root."; exit 1; } REQUIRE=( "dirname" "readlink" "wget" "gpg" "grep" "which" "sed" "sort" "getent" "mktemp" "rm" "chmod" "uname" "groupadd" "useradd" "tail" "tr" "xz" ) PAS=$'[ \033[32;1mPASS\033[0m ] ' ERR=$'[ \033[31;1mFAIL\033[0m ] ' WAR=$'[ \033[33;1mWARN\033[0m ] ' INF="[ INFO ] " DEBUG=0 GNU_URL="https://ftp.gnu.org/gnu/guix/" #GNU_URL="https://alpha.gnu.org/gnu/guix/" # The following associative array holds set of GPG keys used to sign the # releases, keyed by their corresponding Savannah user ID. declare -A GPG_SIGNING_KEYS GPG_SIGNING_KEYS[15145]=3CE464558A84FDC69DB40CFB090B11993D9AEBB5 # ludo GPG_SIGNING_KEYS[127547]=27D586A4F8900854329FF09F1260E46482E63562 # maxim # ------------------------------------------------------------------------------ #+UTILITIES _err() { # All errors go to stderr. printf "[%s]: %s\n" "$(date +%s.%3N)" "$1" } _msg() { # Default message to stdout. printf "[%s]: %s\n" "$(date +%s.%3N)" "$1" } _debug() { if [ "${DEBUG}" = '1' ]; then printf "[%s]: %s\n" "$(date +%s.%3N)" "$1" fi } die() { _err "${ERR}$*" exit 1 } # Return true if user answered yes, false otherwise. The prompt is # yes-biased, that is, when the user simply enter newline, it is equivalent to # answering "yes". # $1: The prompt question. prompt_yes_no() { local -l yn read -rp "$1 [Y/n]" yn [[ ! $yn || $yn = y || $yn = yes ]] || return 1 } chk_require() { # Check that every required command is available. declare -a warn local c _debug "--- [ ${FUNCNAME[0]} ] ---" for c in "$@"; do command -v "$c" &>/dev/null || warn+=("$c") done [ "${#warn}" -ne 0 ] && die "Missing commands: ${warn[*]}." _msg "${PAS}verification of required commands completed" } chk_gpg_keyring() { # Check whether the Guix release signing public key is present. _debug "--- [ ${FUNCNAME[0]} ] ---" local user_id local gpg_key_id local exit_flag for user_id in "${!GPG_SIGNING_KEYS[@]}"; do gpg_key_id=${GPG_SIGNING_KEYS[$user_id]} # Without --dry-run this command will create a ~/.gnupg owned by root on # systems where gpg has never been used, causing errors and confusion. if gpg --dry-run --list-keys "$gpg_key_id" >/dev/null 2>&1; then continue fi if prompt_yes_no "${INF}The following OpenPGP public key is \ required to verify the Guix binary signature: $gpg_key_id. Would you like me to fetch it for you?"; then # Use a reasonable time-out here so users don't report silent # ‘freezes’ when Savannah goes out to lunch, as has happened. if wget "https://sv.gnu.org/people/viewgpg.php?user_id=$user_id" \ --timeout=30 --no-verbose -O- | gpg --import -; then continue fi fi # If we reach this point, th