#! /bin/bash # Copyright 2017-present: Intoli, LLC # Source: https://intoli.com/blog/installing-google-chrome-on-centos/ # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # What this script does is explained in detail in a blog post located at: # https://intoli.com/blog/installing-google-chrome-on-centos/ # If you're trying to figure out how things work, then you should visit that! # Require that this runs as root. [ "$UID" -eq 0 ] || exec sudo "$0" "$@" # Define some global variables. working_directory="/tmp/google-chrome-installation" repo_file="/etc/yum.repos.d/google-chrome.repo" # Work in our working directory. echo "Working in ${working_directory}" mkdir -p ${working_directory} rm -rf ${working_directory}/* pushd ${working_directory} # Add the official Google Chrome Centos 7 repo. echo "Configuring the Google Chrome repo in ${repo_file}" echo "[google-chrome]" > $repo_file echo "name=google-chrome" >> $repo_file echo "baseurl=http://dl.google.com/linux/chrome/rpm/stable/\$basearch" >> $repo_file echo "enabled=1" >> $repo_file echo "gpgcheck=1" >> $repo_file echo "gpgkey=https://dl-ssl.google.com/linux/linux_signing_key.pub" >> $repo_file # Install the Google Chrome signing key. yum install -y wget wget https://dl.google.com/linux/linux_signing_key.pub rpm --import linux_signing_key.pub # A helper to make sure that Chrome is linked correctly function installation_status() { google-chrome-stable --version > /dev/null 2>&1 [ $? -eq 0 ] } # Try it the old fashioned way, should work on RHEL 7.X. echo "Attempting a direction installation with yum." yum install -y google-chrome-stable if [ $? -eq 0 ] then if installation_status; then # Print out the success message. echo "Successfully installed Google Chrome!" rm -rf ${working_directory} popd > /dev/null exit 0 fi fi # Uninstall any existing/partially installed versions. yum --setopt=tsflags=noscripts -y remove google-chrome-stable # Install yumdownloader/repoquery and download the latest RPM. echo "Downloading the Google Chrome RPM file." yum install -y yum-utils # There have been issues in the past with the Chrome repository, so we fall back to downloading # the latest RPM directly if the package isn't available there. For further details: # https://productforums.google.com/forum/#!topic/chrome/xNtfk_wAUC4;context-place=forum/chrome yumdownloader google-chrome-stable || \ wget https://dl.google.com/linux/direct/google-chrome-stable_current_x86_64.rpm rpm_file=$(echo *.rpm) echo "Downloaded ${rpm_file}" # Install the RPM in a broken state. rpm -ih --nodeps ${rpm_file} rm ${rpm_file} # Install font dependencies, see: https://bugs.chromium.org/p/chromium/issues/detail?id=782161 echo "Installing the required font dependencies." yum install -y \ fontconfig \ fontpackages-filesystem \ ipa-gothic-fonts \ xorg-x11-fonts-100dpi \ xorg-x11-fonts-75dpi \ xorg-x11-fonts-misc \ xorg-x11-fonts-Type1 \ xorg-x11-utils # Helper function to install packages in the chroot by name (as an argument). function install_package() { # We'll leave the RPMs around to avoid redownloading things. if [ -f "$1.rpm" ]; then return 0 fi # Find the URL for the package. url=$(repoquery --repofrompath=centos7,http://mirror.centos.org/centos/7/os/`arch` \ --repoid=centos7 -q --qf="%{location}" "$1" | \ sed s/x86_64.rpm$/`arch`.rpm/ | \ sed s/i686.rpm$/`arch`.rpm/g | \ sort -u ) # Download the RPM. wget "${url}" -O "$1.rpm" # Extract it. echo "Extracting $1..." rpm2cpio $1.rpm | cpio -idmv > /dev/null 2>&1 } # Install glibc/ld-linux from CentOS 7. install_package glibc # Make the library directory and copy over glibc/ld-linux. lib_directory=/opt/google/chrome/lib mkdir -p $lib_directory cp ./lib/* $lib_directory/ 2> /dev/null cp ./lib64/* $lib_directory/ 2> /dev/null # Install `mount` and its mandatory dependencies from CentOS 7. for package in "glibc" "util-linux" "libmount" "libblkid" "libuuid" "libselinux" "pcre"; do install_package "${package}" done # Create an `ldd.sh` script to mimic the behavior of `ldd` within the namespace (without bash, etc. dependencies). echo '#!/bin/bash' > ldd.sh echo '' >> ldd.sh echo '# Usage: ldd.sh LIBRARY_PATH EXECUTABLE' >> ldd.sh echo 'mount --make-rprivate /' >> ldd.sh echo 'unshare -m bash -c "`tail -n +7 $0`" "$0" "$@"' >> ldd.sh echo 'exit $?' >> ldd.sh echo '' >> ldd.sh echo 'LD=$({ ls -1 ${1}/ld-linux* | head -n1 ; } 2> /dev/null)' >> ldd.sh echo 'mount --make-private -o remount /' >> ldd.sh echo 'mount --bind ${1} $(dirname "$({ ls -1 /lib/ld-linux* /lib64/ld-linux* | head -n1 ; } 2> /dev/null)")' >> ldd.sh echo 'for directory in lib lib64 usr/lib usr/lib64; do' >> ldd.sh echo ' PATH=./:./bin:./usr/bin LD_LIBRARY_PATH=${1}:./lib64:./usr/lib64:./lib:./usr/lib mount --bind ${1} /${directory} 2> /dev/null' >> ldd.sh echo 'done' >> ldd.sh echo 'echo -n "$(LD_TRACE_LOADED_OBJECTS=1 LD_LIBRARY_PATH="${1}" "${LD}" "${2}")"' >> ldd.sh chmod a+x ldd.sh # Takes the executable as an argument and recursively installs all missing dependencies. function install_missing_dependencies() { executable="${1}" # Loop through and install missing dependencies. while true do finished=true # Loop through each of the missing libraries for this round. while read -r line do # Parse the various library listing formats. if [[ $line == *"/"* ]]; then # Extract the filename when a path is present (e.g. /lib64/). file=`echo $line | sed 's>.*/\([^/:]*\):.*>\1>'` else # Extract the filename for missing libraries without a path. file=`echo $line | awk '{print $1;}'` fi if [ -z $file ]; then continue fi # We'll require an empty round before completing. finished=false echo "Finding dependency for ${file}" # Find the package name for this library. package=$(repoquery --repofrompath=centos7,http://mirror.centos.org/centos/7/os/`arch` \ --repoid=centos7 -q --qf="%{name}" --whatprovides "$file" | head -n1) install_package "${package}" # Copy it over to our library directory. find . | grep /${file} | xargs -n1 -I{} cp {} ${lib_directory}/ done <<< "$(./ldd.sh "${lib_directory}" "${executable}" 2>&1 | grep -e "no version information" -e "not found")" # Break once no new files have been copied in a loop. if [ "$finished" = true ]; then break fi done } # Install the missing dependencies for Chrome. install_missing_dependencies /opt/google/chrome/chrome if ! installation_status; then # Time for the big guns, we'll try to patch the executables to use our lib directory. yum install -y gcc gcc-c++ make autoconf automake echo "Linking issues were encountered, attempting to patch the `chrome` executable." wget https://github.com/NixOS/patchelf/archive/0.9.tar.gz -O 0.9.tar.gz tar zxf 0.9.tar.gz pushd patchelf-0.9 ./bootstrap.sh ./configure make LD="$({ ls -1 ${lib_directory}/ld-linux* | head -n1 ; } 2> /dev/null)" ./src/patchelf --set-interpreter "${LD}" --set-rpath "${lib_directory}" /opt/google/chrome/chrome ./src/patchelf --set-interpreter "${LD}" --set-rpath "${lib_directory}" /opt/google/chrome/chrome-sandbox sed -i 's/\(.*exec cat.*\)/LD_LIBRARY_PATH="" \1/g' /opt/google/chrome/google-chrome popd > /dev/null echo "Attempted experimental patching of Chrome to use a relocated glibc version." fi # Clean up the directory stack. rm -rf ${working_directory} popd > /dev/null # Print out the success status message and exit. version="$(google-chrome-stable --version)" if [ $? -eq 0 ]; then echo "Successfully installed google-chrome-stable, ${version}." exit 0 else echo "Installation has failed." echo "Please email contact@intoli.com with the details of your operating system." echo "If you're using using AWS, please include the AMI identifier for the instance." exit 1 fi