sh
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"
"sed"
"sort"
"getent"
"mktemp"
"rm"
"chmod"
"uname"
"groupadd"
"groupdel"
"useradd"
"userdel"
"tail"
"tr"
"xz"
)
SYSV_INIT_REQUIRE=(
"daemonize"
)
SYSTEMD_REQUIRE=(
"newgidmap"
)
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://ftpmirror.gnu.org/gnu/guix/"
declare -A GPG_SIGNING_KEYS
GPG_SIGNING_KEYS["civodul"]=3CE464558A84FDC69DB40CFB090B11993D9AEBB5 GPG_SIGNING_KEYS["apteryx"]=27D586A4F8900854329FF09F1260E46482E63562 GPG_SIGNING_KEYS["efraim"]=A28BF40C3E551372662D14F741AAE7DCCA3D8351 PUBLIC_KEYSERVERS="keys.openpgp.org pgpkeys.eu keyserver.ubuntu.com"
_err()
{ printf "[%s]: ${ERR}%s\n" "$(date +%s.%3N)" "$1"
}
_msg()
{ printf "[%s]: %s\n" "$(date +%s.%3N)" "$1"
}
_msg_pass()
{
_msg "$PAS$1"
}
_msg_warn()
{
_msg "$WAR$1"
}
_msg_info()
{
_msg "$INF$1"
}
_debug()
{
if [ "${DEBUG}" = '1' ]; then
printf "[%s]: %s\n" "$(date +%s.%3N)" "$1"
fi
}
die()
{
_err "$*"
exit 1
}
prompt_yes_no() {
local -l yn
read -rp "$1 [Y/n]" yn
[[ ! $yn || $yn = y || $yn = yes ]] || return 1
}
chk_require()
{ 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_pass "verification of required commands completed"
}
add_init_sys_require()
{
local init_require=${INIT_SYS^^}_REQUIRE[@]
init_require=${init_require//-/_}
if [[ -n "$init_require" ]]; then
for r in "${!init_require}"; do
REQUIRE+=("$r")
done
fi
}
chk_gpg_keyring()
{ _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]}
codeberg_username=$user_id
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
if wget "https://codeberg.org/$codeberg_username.gpg" \
--tries=1 --timeout=30 --no-verbose -O- | gpg --import -; then
continue
fi
key_obtained=false
for key_server in $PUBLIC_KEYSERVERS; do
if gpg --keyserver $key_server --recv-key $gpg_key_id; then
key_obtained=true
break
fi
done
if $key_obtained; then
continue
fi
fi
_err "Missing OpenPGP public key ($gpg_key_id).
Fetch it with codeberg username:
wget \"https://codeberg.org/$codeberg_username.gpg\" -O - | \
sudo -i gpg --import -
If this fails, try to fetch it via a keyserver:
for key_server in $PUBLIC_KEYSERVERS; do
if sudo -i gpg --keyserver $key_server --recv-key $gpg_key_id; then
break
fi
done"
exit_flag=yes
done
if [ "$exit_flag" = yes ]; then
exit 1
fi
}
chk_term()
{ if [ -t 2 ]; then
if [ "${TERM+set}" = 'set' ]; then
case "$TERM" in
xterm*|rxvt*|urxvt*|linux*|vt*|eterm*|screen*)
;;
*)
ERR="[ FAIL ] "
PAS="[ PASS ] "
WAR="[ WARN ] "
;;
esac
fi
fi
}
chk_init_sys()
{ if [[ $(/sbin/init --version 2>/dev/null) =~ upstart ]]; then
_msg_info "init system is: upstart"
INIT_SYS="upstart"
return 0
elif [[ $(systemctl 2>/dev/null) =~ -\.mount ]]; then
_msg_info "init system is: systemd"
INIT_SYS="systemd"
return 0
elif [[ -f /etc/init.d/cron && ! -h /etc/init.d/cron ]]; then
_msg_info "init system is: sysv-init"
INIT_SYS="sysv-init"
return 0
elif [[ $(openrc --version 2>/dev/null) =~ \(OpenRC ]]; then
_msg_info "init system is: OpenRC"
INIT_SYS="openrc"
return 0
else
INIT_SYS="NA"
_err "Init system could not be detected."
fi
}
chk_sys_arch()
{ local os
local arch
os="$(uname -s)"
arch="$(uname -m)"
case "$arch" in
i386 | i486 | i686 | i786 | x86)
local arch=i686
;;
x86_64 | x86-64 | x64 | amd64)
local arch=x86_64
;;
aarch64)
local arch=aarch64
;;
armv7l)
local arch=armhf
;;
ppc64le | powerpc64le)
local arch=powerpc64le
;;
riscv64)
local arch=riscv64
;;
*)
die "Unsupported CPU type: ${arch}"
esac
case "$os" in
Linux | linux)
local os=linux
;;
*)
die "Your operation system (${os}) is not supported."
esac
ARCH_OS="${arch}-${os}"
}
chk_sys_nscd()
{ if [ "$(type -P pidof)" ]; then
if [ ! "$(pidof nscd)" ]; then
_msg_warn "We recommend installing and/or starting your distribution 'nscd' service"
_msg_warn "Please read 'info guix \"Application Setup\"' about \"Name Service Switch\""
fi
else
_msg_info "We cannot determine if your distribution 'nscd' service is running"
_msg_info "Please read 'info guix \"Application Setup\"' about \"Name Service Switch\""
fi
}
chk_existing()
{ _debug "--- [ ${FUNCNAME[0]} ] ---"
if [[ -e /var/guix && -e /gnu ]]; then
if [ -n "$GUIX_ALLOW_OVERWRITE" ]; then
_msg_warn "Overwriting existing installation!"
else
die "A previous Guix installation was found. Refusing to overwrite."
fi
fi
}
configure_substitute_discovery() {
if grep -q -- '--discover=no' "$1" && \
prompt_yes_no "Would you like the Guix daemon to automatically \
discover substitute servers on the local network?"; then
sed -i 's/--discover=no/--discover=yes/' "$1"
fi
}
guix_get_bin_list()
{ local gnu_url="$1"
local -a bin_ver_ls
local latest_ver
local default_ver
_debug "--- [ ${FUNCNAME[0]} ] ---"
bin_ver_ls=("$(wget "$gnu_url" --no-verbose -O- \
| sed -n -e 's/.*guix-binary-\([0-9.]*[a-z0-9]*\)\..*.tar.xz.*/\1/p' \
| sort -Vu)")
latest_ver="$(echo "${bin_ver_ls[0]}" \
| grep -oE "([0-9]{1,2}\.){2}[0-9]{1,2}[a-z0-9]*" \
| tail -n1)"
default_ver="guix-binary-${latest_ver}.${ARCH_OS}"
if [[ "${#bin_ver_ls}" -ne "0" ]]; then
_msg_pass "Release for your system: ${default_ver}"
else
die "Could not obtain list of Guix releases."
fi
BIN_VER="${default_ver}"
}
guix_get_bin()
{ local url="$1"
local bin_ver="$2"
local dl_path="$3"
local wget_args=()
_debug "--- [ ${FUNCNAME[0]} ] ---"
_msg_info "Downloading Guix release archive"
wget --help | grep -q '\--show-progress' \
&& wget_args=("--no-verbose" "--show-progress")
if wget "${wget_args[@]}" -P "$dl_path" \
"${url}/${bin_ver}.tar.xz" "${url}/${bin_ver}.tar.xz.sig"; then
_msg_pass "download completed."
else
die "could not download ${url}/${bin_ver}.tar.xz."
fi
pushd "${dl_path}" >/dev/null
if gpg --verify "${bin_ver}.tar.xz.sig" >/dev/null 2>&1; then
_msg_pass "Signature is valid."
popd >/dev/null
else
die "could not verify the signature."
fi
}
sys_create_store()
{ local pkg="$1"
local tmp_path="$2"
cd "$tmp_path"
_msg_info "Installing /var/guix and /gnu..."
tar --extract --strip-components=1 --file "$pkg" -C /
_msg_info "Linking the root user's profile"
mkdir -p ~root/.config/guix
ln -sf /var/guix/profiles/per-user/root/current-guix \
~root/.config/guix/current
GUIX_PROFILE=~root/.config/guix/current
source "${GUIX_PROFILE}/etc/profile"
_msg_pass "activated root profile at ${GUIX_PROFILE}"
}
sys_delete_store()
{
_msg_info "removing /var/guix"
rm -rf /var/guix
_msg_info "removing /gnu"
rm -rf /gnu
_msg_info "removing ~root/.config/guix"
rm -rf ~root/.config/guix
}
create_account()
{
local user="$1"
local group="$2"
local supplementary_groups="$3"
local comment="$4"
if id "$user" &>/dev/null; then
_msg_info "user '$user' is already in the system, reset"
usermod -g "$group" -G "$supplementary_groups" \
-d /var/empty -s "$(command -v nologin)" \
-c "$comment" "$user"
else
useradd -g "$group" -G "$supplementary_groups" \
-d /var/empty -s "$(command -v nologin)" \
-c "$comment" --system "$user"
_msg_pass "user added <$user>"
fi
}
install_unprivileged_daemon()
{ [ "$INIT_SYS" = systemd ] && \
grep -q "User=guix-daemon" \
~root/.config/guix/current/lib/systemd/system/guix-daemon.service
}
sys_create_build_user()
{
_debug "--- [ ${FUNCNAME[0]} ] ---"
if getent group kvm > /dev/null; then
_msg_info "group kvm exists and build users will be added to it"
local KVMGROUP=,kvm
fi
if install_unprivileged_daemon
then
_msg_info "installing guix-daemon to run as an unprivileged user"
if [ -f /proc/sys/kernel/unprivileged_userns_clone ] \
&& [ "$(cat /proc/sys/kernel/unprivileged_userns_clone)" -ne 1 ]
then
echo 1 > /proc/sys/kernel/unprivileged_userns_clone || \
_err "failed to enable unprivileged user namespaces"
_msg_warn "Unprivileged user namespaces were disabled and have been enabled now."
_msg_warn "This Linux feature is required by guix-daemon. To enable it permanently, run:"
_msg_warn ' echo 1 > /proc/sys/kernel/unprivileged_userns_clone'
_msg_warn "from the relevant startup script."
fi
if getent group guix-daemon > /dev/null; then
_msg_info "group guix-daemon exists"
else
groupadd --system guix-daemon
_msg_pass "group guix-daemon created"
fi
create_account guix-daemon guix-daemon \
guix-daemon"$KVMGROUP" \
"Unprivileged Guix Daemon User"
if getent group kvm > /dev/null; then
local kvmgid="$(getent group kvm | cut -f3 -d:)"
_msg_info "allowing kvm mapping (GID $kvmgid) for unprivileged guix-daemon"
echo "guix-daemon:$kvmgid:1" >> /etc/subgid
fi
chown -R guix-daemon:guix-daemon /gnu /var/guix
chown -R root:root /var/guix/profiles/per-user/root
mkdir -p /var/log/guix
chown guix-daemon:guix-daemon /var/log/guix
chmod 755 /var/log/guix
else
if getent group guixbuild > /dev/null; then
_msg_info "group guixbuild exists"
else
groupadd --system guixbuild
_msg_pass "group <guixbuild> created"
fi
for i in $(seq -w 1 10); do
create_account "guixbuilder${i}" "guixbuild" \
"guixbuild${KVMGROUP}" \
"Guix build user $i"
done
fi
}
sys_delete_build_user()
{
for i in $(seq -w 1 10); do
if id -u "guixbuilder${i}" &>/dev/null; then
userdel -f guixbuilder"$i"
fi
done
_msg_info "delete group guixbuild"
if getent group guixbuild &>/dev/null; then
groupdel -f guixbuild
fi
_msg_info "remove guix-daemon user"
if id guix-daemon &>/dev/null; then
userdel -f guix-daemon
fi
if getent group guix-daemon &>/dev/null; then
groupdel -f guix-daemon
fi
}
sys_enable_guix_daemon()
{
local info_path
local local_bin
local var_guix
_debug "--- [ ${FUNCNAME[0]} ] ---"
info_path="/usr/local/share/info"
local_bin="/usr/local/bin"
var_guix="/var/guix/profiles/per-user/root/current-guix"
case "$INIT_SYS" in
upstart)
{ initctl reload-configuration;
cp ~root/.config/guix/current/lib/upstart/system/guix-daemon.conf \
/etc/init/ &&
configure_substitute_discovery /etc/init/guix-daemon.conf &&
start guix-daemon; } &&
_msg_pass "enabled Guix daemon via upstart"
;;
systemd)
{ install_unit()
{
local dest="/etc/systemd/system/$1"
rm -f "$dest"
cp ~root/.config/guix/current/lib/systemd/system/"$1" "$dest"
chmod 664 "$dest"
systemctl daemon-reload
systemctl enable "$1"
}
install_unit guix-daemon.service
configure_substitute_discovery \
/etc/systemd/system/guix-daemon.service
install_unit gnu-store.mount
if [ -n "$GUIX_STORE_BIND_MOUNTED_FROM" ]; then
if [ ! -d "$GUIX_STORE_BIND_MOUNTED_FROM" ]; then
die "GUIX_STORE_BIND_MOUNTED_FROM set to nonexistent \
directory"
fi
mkdir -p /etc/systemd/system/gnu-store.mount.d
cat > /etc/systemd/system/gnu-store.mount.d/override.conf <<EOF
[Mount]
What=$GUIX_STORE_BIND_MOUNTED_FROM
EOF
fi
systemctl daemon-reload &&
systemctl start guix-daemon &&
systemctl start gnu-store.mount; } &&
_msg_pass "enabled Guix daemon via systemd"
;;
sysv-init)
{ mkdir -p /etc/init.d;
cp ~root/.config/guix/current/etc/init.d/guix-daemon \
/etc/init.d/guix-daemon;
chmod 775 /etc/init.d/guix-daemon;
configure_substitute_discovery /etc/init.d/guix-daemon
update-rc.d guix-daemon defaults &&
update-rc.d guix-daemon enable &&
service guix-daemon start; } &&
_msg_pass "enabled Guix daemon via sysv"
;;
openrc)
{ mkdir -p /etc/init.d;
cp ~root/.config/guix/current/etc/openrc/guix-daemon \
/etc/init.d/guix-daemon;
chmod 775 /etc/init.d/guix-daemon;
configure_substitute_discovery /etc/init.d/guix-daemon
rc-update add guix-daemon default &&
rc-service guix-daemon start; } &&
_msg_pass "enabled Guix daemon via OpenRC"
;;
NA|*)
_err "unsupported init system; run the daemon manually:"
echo " ~root/.config/guix/current/bin/guix-daemon --build-users-group=guixbuild"
;;
esac
_msg_info "making the guix command available to other users"
[ -e "$local_bin" ] || mkdir -p "$local_bin"
ln -sf "${var_guix}/bin/guix" "$local_bin"
[ -e "$info_path" ] || mkdir -p "$info_path"
for i in "${var_guix}"/share/info/*; do
ln -sf "$i" "$info_path"
done
}
sys_delete_guix_daemon()
{
local info_path
local local_bin
local var_guix
_debug "--- [ ${FUNCNAME[0]} ] ---"
info_path="/usr/local/share/info"
local_bin="/usr/local/bin"
case "$INIT_SYS" in
upstart)
_msg_info "stopping guix-daemon"
stop guix-daemon
_msg_info "removing guix-daemon"
rm /etc/init/guix-daemon.conf
;;
systemd)
if [ -f /etc/systemd/system/guix-daemon.service ]; then
_msg_info "disabling guix-daemon"
systemctl disable guix-daemon
_msg_info "stopping guix-daemon"
systemctl stop guix-daemon
_msg_info "removing guix-daemon"
rm -f /etc/systemd/system/guix-daemon.service
fi
if [ -f /etc/systemd/system/gnu-store.mount ]; then
_msg_info "disabling gnu-store.mount"
systemctl disable gnu-store.mount
_msg_info "stopping gnu-store.mount"
systemctl stop gnu-store.mount
_msg_info "removing gnu-store.mount"
rm -f /etc/systemd/system/gnu-store.mount
fi
systemctl daemon-reload
;;
sysv-init)
update-rc.d guix-daemon disable
service guix-daemon stop
rm -rf /etc/init.d/guix-daemon
;;
NA|*)
_err "unsupported init system; disable, stop and remove the daemon manually:"
echo " ~root/.config/guix/current/bin/guix-daemon --build-users-group=guixbuild"
;;
esac
_msg_info "removing $local_bin/guix"
rm -f "$local_bin"/guix
_msg_info "removing $info_path/guix*"
rm -f "$info_path"/guix*
}
sys_authorize_build_farms()
{ local hosts=(
bordeaux.guix.gnu.org
ci.guix.gnu.org
)
if prompt_yes_no "Permit downloading pre-built package binaries from the \
project's build farms?"; then
for host in "${hosts[@]}"; do
local key=~root/.config/guix/current/share/guix/$host.pub
[ -f "$key" ] \
&& guix archive --authorize < "$key" \
&& _msg_pass "Authorized public key for $host"
done
if id guix-daemon &>/dev/null; then
chown -R guix-daemon:guix-daemon /etc/guix
fi
else
_msg_info "Skipped authorizing build farm public keys"
fi
}
sys_create_init_profile()
{ [ -d "/etc/profile.d" ] || mkdir /etc/profile.d cat <<"EOF" > /etc/profile.d/zzz-guix.sh
# Explicitly initialize XDG base directory variables to ease compatibility
# with Guix System: see <https://issues.guix.gnu.org/56050#3>.
export XCURSOR_PATH="${XCURSOR_PATH:-$HOME/.local/share/icons:$HOME/.icons:/usr/local/share/icons:/usr/share/icons}"
export XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}"
export XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
export XDG_STATE_HOME="${XDG_STATE_HOME:-$HOME/.local/state}"
export XDG_DATA_DIRS="${XDG_DATA_DIRS:-/usr/local/share/:/usr/share/}"
export XDG_CONFIG_DIRS="${XDG_CONFIG_DIRS:-/etc/xdg}"
export XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/.cache}"
# no default for XDG_RUNTIME_DIR (depends on foreign distro for semantics)
# `guix pull` profile
GUIX_PROFILE="$HOME/.config/guix/current"
export PATH="$GUIX_PROFILE/bin${PATH:+:}$PATH"
# Add to INFOPATH and MANPATH so the latest Guix documentation is available to
# info and man readers. When INFOPATH is unset, add a trailing colon so Emacs
# searches 'Info-default-directory-list'. When MANPATH is unset, add a
# trailing colon so the system default search path is used.
export INFOPATH="$GUIX_PROFILE/share/info:${INFOPATH:-}"
export MANPATH="$GUIX_PROFILE/share/man:${MANPATH:-}"
# Expose the latest Guix modules to Guile so guix shell and repls spawned by
# e.g. Geiser work out of the box.
export GUILE_LOAD_PATH="$GUIX_PROFILE/share/guile/site/3.0${GUILE_LOAD_PATH:+:$GUILE_LOAD_PATH}"
export GUILE_LOAD_COMPILED_PATH="$GUIX_PROFILE/lib/guile/3.0/site-ccache${GUILE_LOAD_COMPILED_PATH:+:$GUILE_LOAD_COMPILED_PATH}"
# User's default profile, if it exists
GUIX_PROFILE="$HOME/.guix-profile"
if [ -f "$GUIX_PROFILE/etc/profile" ]; then
. "$GUIX_PROFILE/etc/profile"
# see info '(guix) Application Setup'
export GUIX_LOCPATH="$GUIX_PROFILE/lib/locale${GUIX_LOCPATH:+:}$GUIX_LOCPATH"
# Documentation search paths may be handled by $GUIX_PROFILE/etc/profile if
# the user installs info and man readers via Guix. If the user doesn’t,
# explicitly add to them so documentation for software from ‘guix install’
# is available to the system info and man readers.
case $INFOPATH in
*$GUIX_PROFILE/share/info*) ;;
*) export INFOPATH="$GUIX_PROFILE/share/info:$INFOPATH" ;;
esac
case $MANPATH in
*$GUIX_PROFILE/share/man*) ;;
*) export MANPATH="$GUIX_PROFILE/share/man:$MANPATH"
esac
case $XDG_DATA_DIRS in
*$GUIX_PROFILE/share*) ;;
*) export XDG_DATA_DIRS="$GUIX_PROFILE/share:$XDG_DATA_DIRS"
esac
fi
# NOTE: Guix Home handles its own profile initialization in ~/.profile. See
# info '(guix) Configuring the Shell'.
# Clean up after ourselves.
unset GUIX_PROFILE
EOF
}
sys_create_shell_completion()
{
var_guix=/var/guix/profiles/per-user/root/current-guix
bash_completion=/etc/bash_completion.d
zsh_completion=/usr/share/zsh/site-functions
fish_completion=/usr/share/fish/vendor_completions.d
{ for dir_shell in $bash_completion $zsh_completion $fish_completion; do
[ -d "$dir_shell" ] || mkdir -p "$dir_shell"
done;
ln -sf ${var_guix}/etc/bash_completion.d/guix "$bash_completion";
ln -sf ${var_guix}/etc/bash_completion.d/guix-daemon "$bash_completion";
ln -sf ${var_guix}/share/zsh/site-functions/_guix "$zsh_completion";
ln -sf ${var_guix}/share/fish/vendor_completions.d/guix.fish "$fish_completion"; } &&
_msg_pass "installed shell completion"
}
sys_delete_shell_completion()
{
var_guix=/var/guix/profiles/per-user/root/current-guix
bash_completion=/etc/bash_completion.d
zsh_completion=/usr/share/zsh/site-functions
fish_completion=/usr/share/fish/vendor_completions.d
_msg_info "removing shell completion"
rm -f "$bash_completion"/guix;
rm -f "$bash_completion"/guix-daemon;
rm -f "$zsh_completion"/_guix;
rm -f "$fish_completion"/guix.fish;
}
sys_customize_bashrc()
{
prompt_yes_no "Customize users Bash shell prompt for Guix?" || return 0
for bashrc in /home/*/.bashrc /root/.bashrc; do
test -f "$bashrc" || continue
grep -Fq '$GUIX_ENVIRONMENT' "$bashrc" && continue
cp "${bashrc}" "${bashrc}.bak"
echo '
# Automatically added by the Guix install script.
if [ -n "$GUIX_ENVIRONMENT" ]; then
if [[ $PS1 =~ (.*)"\\$" ]]; then
PS1="${BASH_REMATCH[1]} [env]\\\$ "
fi
fi
' >> "$bashrc"
done
_msg_pass "Bash shell prompt successfully customized for Guix"
}
sys_maybe_setup_selinux()
{
if ! [ -f /sys/fs/selinux/policy ]
then
return
fi
local c
for c in semodule restorecon
do
if ! command -v "$c" &>/dev/null
then
return
fi
done
prompt_yes_no "Install SELinux policy that might be required to run guix-daemon?" \
|| return 0
local var_guix=/var/guix/profiles/per-user/root/current-guix
semodule -i "${var_guix}/share/selinux/guix-daemon.cil"
restorecon -R /gnu /var/guix
}
sys_maybe_setup_apparmor()
{
if ! [ -f /sys/module/apparmor/parameters/enabled ]
then
return
fi
if ! command -v apparmor_parser &> /dev/null
then
return
fi
prompt_yes_no "Install AppArmor profile that might be required to run guix-daemon?" \
|| return 0
local var_guix=/var/guix/profiles/per-user/root/current-guix
local apparmor_sources="${var_guix}/etc/apparmor.d/"
if ! [ -d "$apparmor_sources" ]
then
_err "This version of Guix doesn’t contain AppArmor profiles."
return
fi
cp -f -t /etc/apparmor.d/tunables "$apparmor_sources/tunables/guix"
cp -f -t /etc/apparmor.d "$apparmor_sources/guix-daemon"
cp -f -t /etc/apparmor.d "$apparmor_sources/guix"
apparmor_parser --warn=all -r /etc/apparmor.d/guix-daemon
apparmor_parser --warn=all -r /etc/apparmor.d/guix
_msg_pass "apparmor profiles installed and loaded"
}
sys_delete_apparmor_profiles()
{
if [ -f "/etc/apparmor.d/guix" ]
then
_msg_info "removing /etc/apparmor.d/guix"
apparmor_parser -R /etc/apparmor.d/guix || true
rm -f "/etc/apparmor.d/guix"
fi
if [ -f "/etc/apparmor.d/guix-daemon" ]
then
_msg_info "removing /etc/apparmor.d/guix-daemon"
apparmor_parser -R /etc/apparmor.d/guix-daemon || true
rm -f "/etc/apparmor.d/guix-daemon"
fi
if [ -f "/etc/apparmor.d/tunables/guix" ]
then
_msg_info "removing /etc/apparmor.d/tunables/guix"
rm -f "/etc/apparmor.d/tunables/guix"
fi
}
sys_delete_init_profile()
{
_msg_info "removing /etc/profile.d/zzz-guix.sh"
rm -f /etc/profile.d/zzz-guix.sh
}
sys_delete_user_profiles()
{
_msg_info "removing ~root/.guix-profile"
rm -f ~root/.guix-profile
rm -rf ~root/.cache/guix
_msg_info "removing .guix-profile, .cache/guix and .config/guix of all /home users"
rm -rf /home/*/{.guix-profile,{.cache,.config}/guix}
}
welcome()
{
local uninstall_flag="$1"
local char
cat<<"EOF"
░░░ ░░░
░░▒▒░░░░░░░░░ ░░░░░░░░░▒▒░░
░░▒▒▒▒▒░░░░░░░ ░░░░░░░▒▒▒▒▒░
░▒▒▒░░▒▒▒▒▒ ░░░░░░░▒▒░
░▒▒▒▒░ ░░░░░░
▒▒▒▒▒ ░░░░░░
▒▒▒▒▒ ░░░░░
░▒▒▒▒▒ ░░░░░
▒▒▒▒▒ ░░░░░
▒▒▒▒▒ ░░░░░
░▒▒▒▒▒░░░░░
▒▒▒▒▒▒░░░
▒▒▒▒▒▒░
_____ _ _ _ _ _____ _
/ ____| \ | | | | | / ____| (_)
| | __| \| | | | | | | __ _ _ ___ __
| | |_ | . ' | | | | | | |_ | | | | \ \/ /
| |__| | |\ | |__| | | |__| | |_| | |> <
\_____|_| \_|\____/ \_____|\__,_|_/_/\_\
https://www.gnu.org/software/guix/
EOF
if [ '--uninstall' = "$uninstall_flag" ]; then
echo "${WARN}This script will uninstall GNU Guix from your system"
echo "To install, run this script with no parameters."
else
echo "This script installs GNU Guix on your system"
echo "To uninstall, pass in the '--uninstall' parameter."
fi
echo -n "Press return to continue..."$'\r'
if ! read -r char; then
echo
die "Can't read standard input. Hint: don't pipe scripts into a shell."
fi
if [ "$char" ]; then
echo
echo "...that ($char) was not a return!"
_msg_warn "Use newlines to automate installation, e.g.: yes '' | ${0##*/}"
_msg_warn "Any other method is unsupported and likely to break in future."
fi
}
main_install()
{
local tmp_path
welcome
_msg "Starting installation ($(date))"
chk_term
chk_init_sys
add_init_sys_require
chk_require "${REQUIRE[@]}"
chk_sys_arch
chk_sys_nscd
chk_existing
_msg_info "system is ${ARCH_OS}"
umask 0022
tmp_path="$(mktemp -t -d guix.XXXXXX)"
if [ -z "${GUIX_BINARY_FILE_NAME}" ]; then
chk_gpg_keyring
guix_get_bin_list "${GNU_URL}"
guix_get_bin "${GNU_URL}" "${BIN_VER}" "$tmp_path"
GUIX_BINARY_FILE_NAME=${BIN_VER}.tar.xz
else
if ! [[ $GUIX_BINARY_FILE_NAME =~ $ARCH_OS ]]; then
_err "$ARCH_OS not in ${GUIX_BINARY_FILE_NAME}; aborting"
fi
_msg_info "Using manually provided binary ${GUIX_BINARY_FILE_NAME}"
GUIX_BINARY_FILE_NAME=$(realpath "$GUIX_BINARY_FILE_NAME")
fi
sys_create_store "${GUIX_BINARY_FILE_NAME}" "${tmp_path}"
sys_create_build_user
sys_maybe_setup_selinux
sys_maybe_setup_apparmor
sys_enable_guix_daemon
sys_authorize_build_farms
sys_create_init_profile
sys_create_shell_completion
sys_customize_bashrc
_msg_info "cleaning up ${tmp_path}"
rm -r "${tmp_path}"
_msg_pass "Guix has successfully been installed!"
_msg_info "Run 'info guix' to read the manual."
_msg_info "Please log out and back in to complete the installation."
}
main_uninstall()
{
welcome --uninstall
_msg "Starting uninstall process ($(date))"
chk_term
chk_require "${REQUIRE[@]}"
chk_init_sys
chk_sys_arch
_msg_info "system is ${ARCH_OS}"
sys_delete_guix_daemon
sys_delete_user_profiles
sys_delete_apparmor_profiles
sys_delete_store
sys_delete_init_profile
sys_delete_build_user
sys_delete_shell_completion
_msg_info "removing /etc/guix"
rm -rf /etc/guix
_msg_info "removing /var/log/guix"
rm -rf /var/log/guix
_msg_pass "Guix has successfully been uninstalled!"
}
main()
{
if [ 0 -eq $# ]; then
main_install
else
local uninstall_flag="$1"
if [ '--uninstall' = "${uninstall_flag}" ]; then
main_uninstall
else
echo "unsupported parameters: $*"
exit 1
fi
fi
}
main "$@"