385 lines
9.5 KiB
Bash
385 lines
9.5 KiB
Bash
#!/usr/bin/env bash
|
|
# Recompile OpenSSL 1.1.1w on RHEL9+ and install old Rubies
|
|
# Mateusz Gruszczyński @linuxiarz.pl
|
|
|
|
set -eo pipefail
|
|
|
|
OPENSSL_VERSION="1.1.1w"
|
|
OPENSSL_PREFIX="/opt/openssl111"
|
|
SRC_DIR="/usr/local/src"
|
|
|
|
FORCE_OPENSSL=0
|
|
WEB_PROXY=""
|
|
TARGET_RUBY_VERSION=""
|
|
|
|
usage() {
|
|
cat <<EOF
|
|
Usage:
|
|
$0 --version 2.7.X [--force-openssl] [--webproxy http://proxy:port]
|
|
|
|
Options:
|
|
--version VER Ruby version to install, e.g. 2.7.8
|
|
--force-openssl Force rebuild of OpenSSL ${OPENSSL_VERSION}
|
|
--webproxy URL Proxy URL used for downloads and RVM, e.g. http://proxy.example:8080
|
|
-h, --help Show this help
|
|
|
|
Examples:
|
|
$0 --version 2.7.8
|
|
$0 --version 2.7.8 --force-openssl
|
|
$0 --version 2.7.8 --webproxy http://proxy.local:8080
|
|
|
|
Backward compatibility:
|
|
$0 2.7.8
|
|
EOF
|
|
}
|
|
|
|
die() {
|
|
echo "ERROR: $*" >&2
|
|
exit 1
|
|
}
|
|
|
|
log() {
|
|
echo "$*"
|
|
}
|
|
|
|
command_exists() {
|
|
command -v "$1" >/dev/null 2>&1
|
|
}
|
|
|
|
package_installed() {
|
|
local pkg="$1"
|
|
|
|
rpm -q "${pkg}" >/dev/null 2>&1 && return 0
|
|
rpm -q --whatprovides "${pkg}" >/dev/null 2>&1 && return 0
|
|
|
|
return 1
|
|
}
|
|
|
|
parse_args() {
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
--version)
|
|
shift
|
|
[ $# -gt 0 ] || die "--version requires a value"
|
|
[ -z "${TARGET_RUBY_VERSION}" ] || die "Ruby version already provided: ${TARGET_RUBY_VERSION}"
|
|
TARGET_RUBY_VERSION="$1"
|
|
;;
|
|
--force-openssl)
|
|
FORCE_OPENSSL=1
|
|
;;
|
|
--webproxy)
|
|
shift
|
|
[ $# -gt 0 ] || die "--webproxy requires a value"
|
|
WEB_PROXY="$1"
|
|
;;
|
|
-h|--help)
|
|
usage
|
|
exit 0
|
|
;;
|
|
-*)
|
|
die "unknown option: $1"
|
|
;;
|
|
*)
|
|
[ -z "${TARGET_RUBY_VERSION}" ] || die "Ruby version already provided: ${TARGET_RUBY_VERSION}"
|
|
TARGET_RUBY_VERSION="$1"
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
[ -n "${TARGET_RUBY_VERSION}" ] || die "missing Ruby version, use --version 2.7.X"
|
|
|
|
if [[ ! "${TARGET_RUBY_VERSION}" =~ ^2\.7\.[0-9]+$ ]]; then
|
|
die "only Ruby 2.7.X is allowed, e.g. 2.7.9"
|
|
fi
|
|
}
|
|
|
|
apply_proxy_env() {
|
|
if [ -n "${WEB_PROXY}" ]; then
|
|
export http_proxy="${WEB_PROXY}"
|
|
export https_proxy="${WEB_PROXY}"
|
|
export ftp_proxy="${WEB_PROXY}"
|
|
export all_proxy="${WEB_PROXY}"
|
|
|
|
export HTTP_PROXY="${WEB_PROXY}"
|
|
export HTTPS_PROXY="${WEB_PROXY}"
|
|
export FTP_PROXY="${WEB_PROXY}"
|
|
export ALL_PROXY="${WEB_PROXY}"
|
|
|
|
log "Using web proxy: ${WEB_PROXY}"
|
|
fi
|
|
}
|
|
|
|
load_rvm() {
|
|
export rvm_silence_path_mismatch_check_flag=1
|
|
|
|
if [ -s /etc/profile.d/rvm.sh ]; then
|
|
. /etc/profile.d/rvm.sh
|
|
elif [ -s /usr/local/rvm/scripts/rvm ]; then
|
|
. /usr/local/rvm/scripts/rvm
|
|
elif [ -s /root/.rvm/scripts/rvm ]; then
|
|
. /root/.rvm/scripts/rvm
|
|
else
|
|
die "RVM was not found"
|
|
fi
|
|
|
|
if ! command -v rvm >/dev/null 2>&1; then
|
|
die "RVM is not available in this shell"
|
|
fi
|
|
}
|
|
|
|
download_file() {
|
|
local url="$1"
|
|
local output="$2"
|
|
|
|
if command_exists wget; then
|
|
if [ -n "${WEB_PROXY}" ]; then
|
|
wget \
|
|
-e use_proxy=yes \
|
|
-e "http_proxy=${WEB_PROXY}" \
|
|
-e "https_proxy=${WEB_PROXY}" \
|
|
-O "${output}" \
|
|
"${url}"
|
|
else
|
|
wget -O "${output}" "${url}"
|
|
fi
|
|
return
|
|
fi
|
|
|
|
if command_exists curl; then
|
|
if [ -n "${WEB_PROXY}" ]; then
|
|
curl --proxy "${WEB_PROXY}" -fL -o "${output}" "${url}"
|
|
else
|
|
curl -fL -o "${output}" "${url}"
|
|
fi
|
|
return
|
|
fi
|
|
|
|
die "neither wget nor curl is available"
|
|
}
|
|
|
|
openssl_installation_ok() {
|
|
local openssl_bin="${OPENSSL_PREFIX}/bin/openssl"
|
|
local version_output
|
|
|
|
[ -x "${openssl_bin}" ] || return 1
|
|
[ -d "${OPENSSL_PREFIX}/include/openssl" ] || return 1
|
|
[ -f "${OPENSSL_PREFIX}/lib/libssl.so" ] || [ -f "${OPENSSL_PREFIX}/lib64/libssl.so" ] || return 1
|
|
[ -f "${OPENSSL_PREFIX}/lib/libcrypto.so" ] || [ -f "${OPENSSL_PREFIX}/lib64/libcrypto.so" ] || return 1
|
|
|
|
version_output="$(
|
|
LD_LIBRARY_PATH="${OPENSSL_PREFIX}/lib:${OPENSSL_PREFIX}/lib64:${LD_LIBRARY_PATH:-}" \
|
|
"${openssl_bin}" version 2>/dev/null || true
|
|
)"
|
|
|
|
[[ "${version_output}" == OpenSSL\ ${OPENSSL_VERSION}* ]]
|
|
}
|
|
|
|
ruby_in_path_ok() {
|
|
local ruby_version openssl_version
|
|
|
|
command_exists ruby || return 1
|
|
|
|
ruby_version="$(ruby -e 'print RUBY_VERSION' 2>/dev/null || true)"
|
|
[ "${ruby_version}" = "${TARGET_RUBY_VERSION}" ] || return 1
|
|
|
|
openssl_version="$(ruby -ropenssl -e 'print OpenSSL::OPENSSL_VERSION' 2>/dev/null || true)"
|
|
[[ "${openssl_version}" == OpenSSL\ ${OPENSSL_VERSION}* ]]
|
|
}
|
|
|
|
ruby_in_rvm_present() {
|
|
rvm list strings | grep -Fxq "ruby-${TARGET_RUBY_VERSION}"
|
|
}
|
|
|
|
ruby_in_rvm_ok() {
|
|
local ruby_version openssl_version
|
|
|
|
ruby_in_rvm_present || return 1
|
|
|
|
ruby_version="$(rvm "ruby-${TARGET_RUBY_VERSION}" do ruby -e 'print RUBY_VERSION' 2>/dev/null || true)"
|
|
[ "${ruby_version}" = "${TARGET_RUBY_VERSION}" ] || return 1
|
|
|
|
openssl_version="$(rvm "ruby-${TARGET_RUBY_VERSION}" do ruby -ropenssl -e 'print OpenSSL::OPENSSL_VERSION' 2>/dev/null || true)"
|
|
[[ "${openssl_version}" == OpenSSL\ ${OPENSSL_VERSION}* ]]
|
|
}
|
|
|
|
ruby_already_installed() {
|
|
if ruby_in_rvm_ok; then
|
|
log "Ruby ${TARGET_RUBY_VERSION} is already installed in RVM and linked with OpenSSL ${OPENSSL_VERSION}"
|
|
return 0
|
|
fi
|
|
|
|
if ruby_in_path_ok; then
|
|
log "Ruby ${TARGET_RUBY_VERSION} is already available in PATH and linked with OpenSSL ${OPENSSL_VERSION}"
|
|
return 0
|
|
fi
|
|
|
|
return 1
|
|
}
|
|
|
|
install_build_dependencies() {
|
|
log "[1/6] Checking build dependencies"
|
|
|
|
local missing_packages=()
|
|
local packages=(
|
|
curl
|
|
wget
|
|
tar
|
|
xz
|
|
bzip2
|
|
git
|
|
perl-core
|
|
pkgconfig
|
|
zlib-devel
|
|
readline-devel
|
|
libyaml-devel
|
|
libffi-devel
|
|
gdbm-devel
|
|
ncurses-devel
|
|
gmp-devel
|
|
autoconf
|
|
automake
|
|
libtool
|
|
bison
|
|
)
|
|
|
|
local pkg
|
|
for pkg in "${packages[@]}"; do
|
|
if ! package_installed "${pkg}"; then
|
|
missing_packages+=("${pkg}")
|
|
fi
|
|
done
|
|
|
|
local need_devtools=0
|
|
if ! command_exists gcc || ! command_exists g++ || ! command_exists make; then
|
|
need_devtools=1
|
|
fi
|
|
|
|
if [ "${need_devtools}" -eq 0 ] && [ "${#missing_packages[@]}" -eq 0 ]; then
|
|
log "All required build dependencies are already installed"
|
|
return 0
|
|
fi
|
|
|
|
if [ "${need_devtools}" -eq 1 ]; then
|
|
log "Installing missing group: Development Tools"
|
|
dnf groupinstall -y "Development Tools"
|
|
fi
|
|
|
|
if [ "${#missing_packages[@]}" -gt 0 ]; then
|
|
log "Installing missing packages: ${missing_packages[*]}"
|
|
dnf install -y "${missing_packages[@]}"
|
|
fi
|
|
}
|
|
|
|
install_openssl() {
|
|
local tarball="openssl-${OPENSSL_VERSION}.tar.gz"
|
|
local srcdir="openssl-${OPENSSL_VERSION}"
|
|
local url="https://www.openssl.org/source/old/1.1.1/${tarball}"
|
|
|
|
if [ "${FORCE_OPENSSL}" -eq 0 ] && openssl_installation_ok; then
|
|
log "[2/6] OpenSSL ${OPENSSL_VERSION} already exists and works in ${OPENSSL_PREFIX}, skipping"
|
|
return 0
|
|
fi
|
|
|
|
log "[2/6] Preparing OpenSSL ${OPENSSL_VERSION}"
|
|
mkdir -p "${SRC_DIR}"
|
|
mkdir -p "${OPENSSL_PREFIX}"
|
|
cd "${SRC_DIR}"
|
|
|
|
if [ ! -f "${tarball}" ] || [ "${FORCE_OPENSSL}" -eq 1 ]; then
|
|
rm -f "${tarball}"
|
|
download_file "${url}" "${tarball}"
|
|
else
|
|
log "Using existing source archive: ${SRC_DIR}/${tarball}"
|
|
fi
|
|
|
|
rm -rf "${srcdir}"
|
|
tar xf "${tarball}"
|
|
cd "${srcdir}"
|
|
|
|
log "[3/6] Building OpenSSL into ${OPENSSL_PREFIX}"
|
|
./config \
|
|
--prefix="${OPENSSL_PREFIX}" \
|
|
--openssldir="${OPENSSL_PREFIX}" \
|
|
shared zlib
|
|
|
|
make -j"$(nproc)"
|
|
rm -rf "${OPENSSL_PREFIX:?}/"*
|
|
make install_sw
|
|
|
|
openssl_installation_ok || die "OpenSSL ${OPENSSL_VERSION} verification failed after build"
|
|
}
|
|
|
|
install_ruby_with_rvm() {
|
|
local -a rvm_args
|
|
local action="install"
|
|
|
|
log "[4/6] Configuring RVM build environment"
|
|
rvm autolibs disable
|
|
|
|
export CPPFLAGS="-I${OPENSSL_PREFIX}/include"
|
|
export CFLAGS="-I${OPENSSL_PREFIX}/include"
|
|
export LDFLAGS="-L${OPENSSL_PREFIX}/lib -L${OPENSSL_PREFIX}/lib64 -Wl,-rpath,${OPENSSL_PREFIX}/lib -Wl,-rpath,${OPENSSL_PREFIX}/lib64"
|
|
export PKG_CONFIG_PATH="${OPENSSL_PREFIX}/lib/pkgconfig:${OPENSSL_PREFIX}/lib64/pkgconfig"
|
|
export RUBY_CONFIGURE_OPTS="--with-openssl-dir=${OPENSSL_PREFIX}"
|
|
|
|
if ruby_in_rvm_present; then
|
|
action="reinstall"
|
|
fi
|
|
|
|
rvm_args=("${action}" "${TARGET_RUBY_VERSION}" "--with-openssl-dir=${OPENSSL_PREFIX}")
|
|
|
|
if [ -n "${WEB_PROXY}" ]; then
|
|
rvm_args+=("--proxy" "${WEB_PROXY}")
|
|
fi
|
|
|
|
log "[5/6] ${action^}ing Ruby ${TARGET_RUBY_VERSION} with RVM"
|
|
rvm "${rvm_args[@]}"
|
|
}
|
|
|
|
verify_installation() {
|
|
log "[6/6] Verifying installation"
|
|
|
|
local installed_ruby_version installed_openssl_version
|
|
|
|
if ruby_in_rvm_ok; then
|
|
installed_ruby_version="$(rvm "ruby-${TARGET_RUBY_VERSION}" do ruby -e 'print RUBY_VERSION')"
|
|
installed_openssl_version="$(rvm "ruby-${TARGET_RUBY_VERSION}" do ruby -ropenssl -e 'print OpenSSL::OPENSSL_VERSION')"
|
|
elif ruby_in_path_ok; then
|
|
installed_ruby_version="$(ruby -e 'print RUBY_VERSION')"
|
|
installed_openssl_version="$(ruby -ropenssl -e 'print OpenSSL::OPENSSL_VERSION')"
|
|
else
|
|
die "Ruby ${TARGET_RUBY_VERSION} verification failed"
|
|
fi
|
|
|
|
log "Installed Ruby version: ${installed_ruby_version}"
|
|
log "Linked OpenSSL version: ${installed_openssl_version}"
|
|
}
|
|
|
|
main() {
|
|
[ "${EUID}" -eq 0 ] || die "run this script as root"
|
|
|
|
parse_args "$@"
|
|
log "Requested Ruby version: ${TARGET_RUBY_VERSION}"
|
|
apply_proxy_env
|
|
load_rvm
|
|
|
|
if ruby_already_installed; then
|
|
log "Nothing to do"
|
|
exit 0
|
|
fi
|
|
|
|
install_build_dependencies
|
|
install_openssl
|
|
|
|
if ruby_already_installed; then
|
|
log "Ruby is already installed after OpenSSL verification/build, skipping RVM build"
|
|
verify_installation
|
|
exit 0
|
|
fi
|
|
|
|
install_ruby_with_rvm
|
|
verify_installation
|
|
}
|
|
|
|
main "$@" |