loongbedrocklinux-userlandd/src/slash-bedrock/libexec/brl-apply

449 lines
12 KiB
Plaintext
Executable File

#!/bedrock/libexec/busybox sh
#
# brl apply
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# version 2 as published by the Free Software Foundation.
#
# Copyright (c) 2018-2020 Daniel Thau <danthau@bedrocklinux.org>
#
# (re)loads configuration
. /bedrock/share/common-code
# Remove typical runtime sanity checks, as leaving a system half-configured is
# worse than aborting mid-configure.
set +eu
trap '' EXIT
print_help() {
printf "Usage: ${color_cmd}brl apply ${color_sub}[options]${color_norm}
Apply ${color_file}/bedrock/etc/bedrock.conf${color_norm} configuration changes. Requires root.
Options:
${color_cmd}-h${color_norm}, ${color_cmd}--help${color_norm} print this message
Example:
${color_cmd}$ brl which startx
${color_strat}debian
${color_rcmd}# vim /bedrock/etc/bedrock.conf
${color_sub}<pin startx to arch>
${color_cmd}$ brl which startx
${color_strat}debian
${color_rcmd}# brl apply
${color_cmd}$ brl which startx
${color_strat}arch
${color_norm}"
}
handle_help "${@:-}"
require_root
if [ "${1:-}" != "--skip-repair" ]; then
# Repair strata to apply stratum-status changing configuration
/bedrock/libexec/brl-repair --skip-crossfs "bedrock"
/bedrock/libexec/brl-repair --skip-crossfs "init"
for stratum in $(list_strata); do
is_bedrock "${stratum}" && continue
is_init "${stratum}" && continue
is_enabled "${stratum}" || continue
/bedrock/libexec/brl-repair --skip-crossfs "${stratum}"
done
fi
# lock after brl-repair above, as it locks
lock
# Various fields below manage the timezone. Timezone information should not be
# read from /usr/share/zoneinfo because:
# - It is a local file and different strata could have differing values, which
# would result in subtle time issues which would be difficult for users to
# detect or debug. Using /bedrock/cross ensures a consistent timezone value
# across all strata.
# - Some strata may not have a locale zoneinfo database, which means they must
# look into /bedrock/cross.
#
# We cannot use TZ=:/etc/localtime or TZ=:/bedrock/cross/zoneinfo/<timezone>
# because of a bug in chromium and the many programs which build off of
# chromium:
# https://bugs.chromium.org/p/chromium/issues/detail?id=811403
# https://github.com/signalapp/Signal-Desktop/issues/3085
# https://github.com/ValveSoftware/steam-for-linux/issues/5612
# https://chromium-review.googlesource.com/c/chromium/deps/icu/+/1006219/
#
# By ensuring TZ is unset, all tested software including chromium, glibc, and
# musl, fall back to /etc/localtime, which is symlinked (eventually) to
# /bedrock/cross.
# Set up /etc/localtime
ln -fns "/bedrock/cross/zoneinfo/$(cfg_value "locale" "timezone")" /bedrock/run/localtime
# special case fpath
envvars="$(cfg_keys "env-vars" | sed 's/^[^:]*://g' | grep -v "^fpath$" | sort | uniq)"
cfg_envvar() {
# Retain backwards compatibility with non-prefix/infix/suffix config
# system.
whole="$(cfg_value "env-vars" "${1}")"
if [ -n "${whole}" ]; then
echo "${whole}"
return
fi
prefix="$(cfg_value "env-vars" "PREFIX:${1}")"
infix="$(cfg_value "env-vars" "INFIX:${1}")"
suffix="$(cfg_value "env-vars" "SUFFIX:${1}")"
echo "${prefix}:${infix}:${suffix}"
}
# Setup /etc/environment
cat <<EOF >/bedrock/run/environment
LANG=$(cfg_value "locale" "LANG")
$(
for envvar in ${envvars}; do
echo "${envvar}=$(cfg_envvar "${envvar}")"
done
)
EOF
# Setup /etc/profile
cat <<EOF >/bedrock/run/profile
#!/bin/sh
[ -n "\${BEDROCK_RESTRICT:-}" ] && return
br_dedup_envvar() {
envvar=""
prefix="\${1}"
suffix="\${2}"
IFS=":"
[ -n "\${ZSH_VERSION:-}" ] && setopt sh_word_split
for i in \${prefix}; do
case ":\${envvar}:\${suffix}:" in
*":\${i}:"*) ;;
*) envvar="\${envvar}:\${i}" ;;
esac
done
for i in \${suffix}; do
case ":\${envvar}:" in
*":\${i}:"*) ;;
*) envvar="\${envvar}:\${i}" ;;
esac
done
echo "\${envvar}" | sed -e 's/::*/:/g' -e 's/^://' -e 's/:$//'
}
for line in \$(
cd /
for s in \$(/bedrock/bin/brl list); do
[ -r "/bedrock/strata/\${s}/etc/profile" ] || continue
/bedrock/bin/strat -r "\${s}" /bin/sh -c '
. /etc/profile;
$(
for envvar in ${envvars}; do
printf "\t\techo \"%s=\${%s}\";\n" "${envvar}" "${envvar}"
done
) ' &
done
wait
); do
case "\${line}" in
$(
for envvar in ${envvars}; do
printf "\t\"%s=\"*) %s=\"\${%s}:\${line#*=}\";;\n" "${envvar}" "${envvar}" "${envvar}"
done
)
esac
done
unset line
unset TZ
export LANG="$(cfg_value "locale" LANG)"
$(
# shellcheck disable=SC2030
for envvar in ${envvars}; do
printf "export %s=\"\$(br_dedup_envvar \"%s:\${%s}\" \"%s\")\"\n" \
"${envvar}" \
"$(cfg_value "env-vars" "PREFIX:${envvar}"):$(cfg_value "env-vars" "${envvar}"):$(cfg_value "env-vars" "INFIX:${envvar}")" \
"${envvar}" \
"$(cfg_value "env-vars" "SUFFIX:${envvar}")"
done
)
unset -f br_dedup_envvar
EOF
# Setup /etc/zsh/zprofile, /etc/zprofile
cat <<EOF >/bedrock/run/zprofile
#!/usr/bin/env zsh
[ -n "\${BEDROCK_RESTRICT:-}" ] && return
# zsh does not read /etc/profile by default. Some distros configure it to,
# some do not.
. /bedrock/run/profile
br_dedup_envvar() {
envvar=""
prefix="\${1}"
suffix="\${2}"
IFS=":"
for i in \${prefix}; do
case ":\${envvar}:\${suffix}:" in
*":\${i}:"*) ;;
*) envvar="\${envvar}:\${i}" ;;
esac
done
for i in \${suffix}; do
case ":\${envvar}:" in
*":\${i}:"*) ;;
*) envvar="\${envvar}:\${i}" ;;
esac
done
echo "\${envvar}" | sed -e 's/::*/:/g' -e 's/^://' -e 's/:$//'
}
$(
printf "export fpath=(\$(br_dedup_envvar \"%s:\${fpath}\" \"%s\" | sed 's/:/ /g'))\n" \
"$(cfg_value "env-vars" "PREFIX:fpath"):$(cfg_value "env-vars" "fpath"):$(cfg_value "env-vars" "INFIX:fpath")" \
"$(cfg_value "env-vars" "SUFFIX:fpath")"
)
EOF
# Setup /etc/fish/conf.d/ configuration
cat <<EOF >/bedrock/run/fprofile
[ -n "\$BEDROCK_RESTRICT" ]; and exit 0
function br_dedup_envvar
set -l envvar
set -l prefix \$argv[1]
set -l suffix \$argv[2]
for i in (string split ":" \$prefix)
if not contains \$i \$envvar; and not contains \$i \$suffix; and [ -n "\$i" ]
set -a envvar \$i
end
end
for i in (string split ":" \$suffix)
if not contains \$i \$envvar; and [ -n "\$i" ]
set -a envvar \$i
end
end
echo -s :\$envvar | sed -e 's/::*/:/g' -e 's/^://' -e 's/:$//'
end
set -e TZ
set -x LANG $(cfg_value "locale" "LANG")
$(
for envvar in ${envvars}; do
printf "set -x %s (br_dedup_envvar \"%s:\$%s\" \"%s\")\n" \
"${envvar}" \
"$(cfg_value "env-vars" "PREFIX:${envvar}"):$(cfg_value "env-vars" "${envvar}"):$(cfg_value "env-vars" "INFIX:${envvar}")" \
"${envvar}" \
"$(cfg_value "env-vars" "SUFFIX:${envvar}")"
done
)
functions -e br_dedup_envvar
EOF
# Setup /etc/sudoers configuration
cat <<EOF >/bedrock/run/sudoers
Defaults secure_path="$(cfg_envvar "PATH")"
Defaults env_keep+="BEDROCK_RESTRICT"
EOF
# Configure crossfs. Items below reference crossfs, and so this should be done
# early. However, not too early; it requires /bedrock/run/profile.
cfg_crossfs "/proc/1/root/bedrock/strata/bedrock/bedrock/cross"
# configure etcfs
for stratum in $(/bedrock/bin/brl list -ei); do
root="$(stratum_root "${stratum}")"
cfg_etcfs "/proc/1/root${root}/etc"
done
# Configure cross firmware.
if [ -w /sys/module/firmware_class/parameters/path ] && [ -d /bedrock/cross/firmware ]; then
printf "/bedrock/cross/firmware" >/sys/module/firmware_class/parameters/path
fi
# Specify commands which should automatically be restricted in an easily parsed
# format for strat.
mkdir -p /bedrock/run/restricted_cmds/
for cmd in $(cfg_values "restriction" "restrict"); do
touch "/bedrock/run/restricted_cmds/${cmd}"
done
if echo /bedrock/run/restricted_cmds/* >/dev/null 2>&1; then
for file in /bedrock/run/restricted_cmds/*; do
found=false
for cmd in $(cfg_values "restriction" "restrict"); do
if [ "$(basename "${file}")" = "${cmd}" ]; then
found=true
break
fi
done
if ! "${found}"; then
rm "${file}"
fi
done
fi
# Setup xorg.conf configuration
if [ -d /bedrock/cross/fonts ]; then
(
echo "Section \"Files\""
find /bedrock/cross/fonts -mindepth 1 -type d -exec echo " FontPath \"{}\"" \;
echo "EndSection"
) >/bedrock/run/xorg-fonts
fi
# Configure /etc/login.defs
if [ -r /etc/login.defs ] && awk -F'=' -v"path=$(cfg_value "env-vars" "PATH")" '
# Ensure login.defs uses Bedrock $PATH.
#
/^[ \t]*ENV_SUPATH[ \t][ \t]*/ && $2 == path {s=1}
/^[ \t]*ENV_PATH[ \t][ \t]*/ && $2 == path {n=1}
END {exit (s+n==2)}' /etc/login.defs; then
awk -F'=' -v"path=$(cfg_envvar "PATH")" '
/^[ \t]*ENV_SUPATH[ \t][ \t]*/ {
print "ENV_SUPATH\t"path
s=1
next
}
/^[ \t]*ENV_PATH[ \t][ \t]*/ {
print "ENV_PATH\t"path
n=1
next
}
1
END {
if(s == 0) {
print "ENV_SUPATH\t"path
}
if(n == 0) {
print "ENV_PATH\t"path
}
}
' /etc/login.defs >/etc/login.defs-new
mv /etc/login.defs-new /etc/login.defs
fi
# Configure /etc/fstab
if [ -r /etc/fstab ] && awk '$1$2$3$4$5$6 !~ "#" && $6 != "" && $6 != 0 {x=1} END {exit !x}' /etc/fstab; then
# Bedrock creates bind mounts referencing the root directory which
# confuse various init systems attempts to fsck the root directory.
# Thus, disable configuration indicating the root directory should be
# fscked.
awk '
$1$2$3$4$5$6 !~ "#" && $6 != "" && $6 != 0 {
$6 = "0"
}
{
print
}
' /etc/fstab >/etc/fstab-new && mv /etc/fstab-new /etc/fstab
fi
# Disable SELinux
for stratum in $(/bedrock/bin/brl list -ei); do
root="$(stratum_root --empty "${stratum}")"
seconfig="/proc/1/root${root}/etc/selinux/config"
if grep -q '^SELINUX=enforcing' "${seconfig}" 2>/dev/null || grep -q '^SELINUX=permissive' "${seconfig}" 2>/dev/null; then
sed 's/^SELINUX=/SELINUX=disabled/' "${seconfig}" >"${seconfig}-"
mv "${seconfig}-" "${seconfig}"
fi
done
# Force login shells to use cross path to ensure they are available to all
# programs which may call them. This is particularly important to allow users
# to login when the login software comes from a stratum which does not directly
# provide the user's configured shell.
need_shell_change=false
while read -r line; do
shell="$(echo "${line}" | awk -F":" '{print$7}')"
subline="$(echo "${line}" | awk -F":" -vOFS=":" '{$7="";print}')"
name="$(basename "${shell}")"
crosspath="/bedrock/cross/bin/$(basename "${shell}")"
if echo "${shell}" | grep -q '^/bedrock/cross/'; then
true
elif ! [ -x "${crosspath}" ]; then
true
else
need_shell_change=true
break
fi
done </etc/passwd
if "${need_shell_change}"; then
cp -a /etc/passwd /etc/passwd-
while read -r line; do
shell="$(echo "${line}" | awk -F":" '{print$7}')"
subline="$(echo "${line}" | awk -F":" -vOFS=":" '{$7="";print}')"
name="$(basename "${shell}")"
crosspath="/bedrock/cross/bin/$(basename "${shell}")"
if echo "${shell}" | grep -q '^/bedrock/cross/'; then
echo "${line}"
elif ! [ -x "${crosspath}" ]; then
echo "${line}"
else
echo "${subline}/bedrock/cross/bin/${name}"
fi
done </etc/passwd >/etc/passwd-
if [ "$(cat /etc/passwd)" != "$(cat /etc/passwd-)" ] &&
[ "$(wc -l /etc/passwd | cut -d' ' -f1)" = "$(wc -l /etc/passwd- | cut -d' ' -f1)" ]; then
mv /etc/passwd- /etc/passwd
enforce_shells
else
rm /etc/passwd-
fi
fi
# Setup pmm front-end.
pmm_ui="$(cfg_value pmm user-interface)"
if [ "${pmm_ui}" = "" ]; then
notice "Set [pmm]/user-interface in bedrock.conf and run \`brl apply\` to update pmm front-end(s)"
else
pmm_ui_files="$(/bedrock/libexec/pmm "${pmm_ui}" pmm --list-pmm-ui-files 2>/dev/null)"
# Create front-end files
for file in ${pmm_ui_files}; do
tgt_contents="#!/bedrock/libexec/busybox sh
exec /bedrock/libexec/pmm ${pmm_ui} ${file} \"\${@}\""
tgt_path="/bedrock/bin/${file}"
if ! echo "${file}" | grep -q "^pmm"; then
echo "ERROR: pmm requests non-pmm front-end \"${file}\""
continue
elif [ -x "${tgt_path}" ] && [ "$(cat "${tgt_path}")" = "${tgt}" ]; then
continue
else
echo "${tgt_contents}" >"${tgt_path}"
chmod a+rx "${tgt_path}"
fi
done
# Remove outdated front-end files
cd /bedrock/bin/
if ls pmm* >/dev/null 2>&1; then
for file in pmm*; do
if echo "${pmm_ui_files}" | awk -vf="${file}" '$1 == f {exit 1}'; then
rm "${file}"
fi
done
fi
fi
# Patch s6 init to skip unmounting /run, as this breaks Bedrock's pre-init setup of /run
for stratum in $(/bedrock/bin/brl list -ei); do
init="$(realpath "/bedrock/strata/${stratum}/sbin/init")"
if ! grep -q "^s6-linux-init" "${init}" 2>/dev/null; then
continue
fi
if grep -q "^s6-linux-init -N " "${init}" 2>/dev/null; then
continue
fi
cp "${init}" "${init}-bedrock-patch"
sed 's/s6-linux-init /s6-linux-init -N /' "${init}" > "${init}-bedrock-patch"
mv "${init}-bedrock-patch" "${init}"
done
exit_success