#!/bin/bash
#The MIT License
#
#Copyright (c) 2007 Cappy

#Permission is hereby granted, free of charge, to any person obtaining a copy
#of this software and associated documentation files (the "Software"), to deal
#in the Software without restriction, including without limitation the rights
#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
#copies of the Software, and to permit persons to whom the Software is
#furnished to do so, subject to the following conditions:
#
#The above copyright notice and this permission notice shall be included in
#all copies or substantial portions of the Software.
#
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
#THE SOFTWARE.
#---
#Author: Cappy of ubuntuforums.org
#Website: http://ubuntuforums.org/showthread.php?t=474790
#Version: 2.06
#Purpose: Download and install native and non-native libraries
#---

print_usage()
{
echo "\
Usage: getlibs /path/to/binary
       getlibs -l i386librarytoinstall.so
       getlibs -p i386packagename
       getlibs -w www.website.com/i386package.deb
       getlibs -i /home/$USER/i386package.deb
       See 'man getlibs' for more commands"
    clean_up_err
}

clean_up()
{
    rm -rf $tempdir #Normal exit without errors
}

clean_up_err()
{
    rm -rf $tempdir
    exit 1 #Exit code 1
}

wget_fail()
{
echo "\
The mirrors do not have the requested file or there is no internet connection"
    #clean_up_err
}

#Trap exits
trap clean_up_err 1 2 3 13 15 #Script error or interrupt
trap clean_up 0 #Normal exit
PATH="/usr/bin:/bin:/sbin:/usr/sbin:$PATH"; export PATH

version="Getlibs version 2.06 - March 1st 2008"
architecture=`uname -m`
targetarch="x86" #Set 64-bit machines to download 32-bit if no options are set
if [ "$architecture" != "x86_64" ] && [ "$architecture" != "ia64" ]; then
    architecture="x86"
else
    architecture="x86_64"
fi
tempdir=`mktemp -d /tmp/getlibs.XXXXXXXXXX || echo "Unable to create temp directory in /tmp"; clean_up_err`
shopt -s xpg_echo
#Get distro and release
distro=`lsb_release -i | cut -f2`
if [ "$distro" = "Ubuntu" ]; then
    release=`lsb_release -c | cut -f2` #dapper, edgy, gutsy, etc.
else
    if [ "$architecture" = "x86_64" ]; then
        if [ -d /emul/ia32-linux ]; then
            distro="Debian"
        else
            distro="Ubuntu"; release="gutsy";
        fi
    else
        distro="Debian"
    fi
fi

#If 64-bit ubuntu and ia32-libs is not installed
if [ "$architecture" = "x86_64" ] && [ "$distro" = "Ubuntu" ] && [ ! -e "/usr/lib32/libGLU.so.1" ]; then
    sudo apt-get install ia32-libs
elif [ "$architecture" = "x86_64" ] && [ "$distro" = "Debian" ] && [ ! -d "/emul/ia32-linux" ]; then
    sudo apt-get install ia32-libs
fi

if [ $# -lt 1 ]; then
    print_usage
fi


set -- `getopt -u -a --longoptions="32: 64: binary: library: package: distro: release: file: link: mirror: ldconfig remove: help update version yes verbose apt-file extract build savebuild" "b: l: p: d: r: i: w: m: c r: u v h" "$@"`
while [ $# -gt 0 ]; do
    case "$1" in
        --32)        targetarch="x86";;
        --64)        targetarch="x86_64";;
	--binary)    binarypath="$2"; shift;;
        -b)          binarypath="$2"; shift;;
        --library)   library="true"; parameters="$parameters $2"; shift;;
        -l)          library="true"; parameters="$parameters $2"; shift;;
	--package)   package="true"; parameters="$parameters $2"; shift;;
        -p)          package="true"; parameters="$parameters $2"; shift;;
	--distro)    distro="$2"; shift;;
        -d)          distro="$2"; shift;;
	--release)   release="$2"; shift;;
        -r)          release="$2"; shift;;
	--file)      file="true"; parameters="$parameters $2"; shift;;
        -i)          file="true"; parameters="$parameters $2"; shift;;
	--link)      download="true"; parameters="$parameters $2"; shift;;
        -w)          download="true"; parameters="$parameters $2"; shift;;
	--mirror)    mirror2="$2"; parameters="$parameters $2"; shift;;
        -m)          mirror2="$2"; parameters="$parameters $2"; shift;;
	--ldconfig)  ldconfig="true";;
        -c)          ldconfig="true";;
	--remove)    remove="true"; parameters="$parameters $2"; shift;;
        -r)          remove="true"; parameters="$parameters $2"; shift;;
	--update)    update="true";;
        -u)          update="true";;
        --version)   echo "$version";;
        -v)          echo "$version";;
        --yes)       prompt="yes";;
        --verbose)   verbose="true";;
        --apt-file)  aptfile="true";;
        --extract)   extract="true";;
        --build)     build="true";;
        --savebuild) savebuild="true";;
        --help)      print_usage;;
        -h)          print_usage;;
        --)          shift; break;;
        -*)          print_usage; exit;;
        *)           break;;
    esac
    shift
done

#If no parameters decide if it is a binary or a library
if [ -n "$1" ] && [ -z "$library" ] && [ -z "$binarypath" ] && [ -z "$download" ] && [ -z "$package" ] && [ -z "$file" ]; then
    if [ -n "`echo "$1" | grep "\.so"`" ]; then
        library="true";
    else
        #if [ -f "$1" ]; then
            binarypath="$1"
        #else
            #echo "$1 is not an existing file. Assuming this is a package name.\n"
            #package="true"
        #fi
    fi
fi

while [ $# -gt 0 ]; do
    if [ "$1" != "--" ]; then
        parameters="$parameters $1"
    fi
    shift
done

not_an_executable()
{
echo "\
Cannot determine the dependencies required by this program, it may be a script:
If this program needs a 32-bit library use:
getlibs -l i386librarytoinstall.so
If this program needs a 64-bit library use:
getlibs -64l amd64librarytoinstall.so"
	clean_up_err
}

#Find missing dependencies for a binary
if [ -n "$binarypath" ]; then
    if [ ! -f "$binarypath" ]; then
        echo "The file \"$binarypath\" does not exist"
        print_usage
    elif [ ! -r "$binarypath" ]; then
        echo "The file \"$binarypath\" does not have read permissions"
        clean_up_err
    elif [ -z "`file "$binarypath" | grep ELF`" ]; then
        not_an_executable
    fi

    if [ -n "`file "$binarypath" | grep "32-bit"`" ]; then
        targetarch="x86"
    elif [ -n "`file "$binarypath" | grep "64-bit"`" ]; then
        targetarch="x86_64"
    else
        echo "Not a 32-bit or 64-bit binary"; echo `file "$binarypath"`; clean_up_err;
    fi

    cd `dirname "$binarypath" || echo "cd $binarypath failed"; clean_up_err` #Change to the program's directory
    binarypath=`basename "$binarypath"`
    dependencylist=`ldd "$binarypath" | grep "not found" | awk '{print $1}'`

    neededlocallibraries=`echo "$dependencylist" | grep "\./"`
    if [ -n "$neededlocallibraries" ]; then
        neededlocallibraries=`echo ${neededlocallibraries//\.\//}`
        echo "You need to be copy the following libraries to the same directory as the binary:"
        echo "$neededlocallibraries"
        dependencylist=`echo "$dependencylist" | grep -v "\./"`
    fi
    if [ -z "`echo "$dependencylist" | grep "[[:alpha:]]"`" ]; then
        echo "This application isn't missing any dependencies"
        exit
    fi
    parameters="$dependencylist"
    library="true"
    binarypath="`pwd`/`basename "$binarypath"`"
fi

#Determine how to install library
if [ "$architecture" = "$targetarch" ]; then
    installtype="native" #apt-get
elif [ "$architecture" = "x86" ]; then
    echo "Cannot install 64-bit libraries on a 32-bit system"; clean_up_err;
else
    installtype="nonnative" #32-bit on 64-bit system
fi

while true; do #Loop for incase there are new dependencies created for binary

returned=""
stored_list()
{
    stored="
libXss.so.1 libxss1
libdbus-1.so.2 libdbus-1.so.3 libdbus-1-3
libQtCore.so.4 libQtNetwork.so.4 libQtDBus.so.4 libqt4-core
libQtGui.so.4 libqt4-gui
libsigc-2.0.so.0 libsigc++-2.0-0c2a
libasound_module_pcm_pulse.so libasound2-plugins
libglitz-glx.so.1 libglitz-glx1
libglitz.so.1 libglitz1
librsvg-2.so.2 librsvg2-2
libcroco-0.6.so.3 libcroco3
libgsf-1.so.114 libgsf-1-114
libqt-mt.so.3 libqt3-mt
libgtk-1.2.so.0 libgtk1.2
libgmodule-1.2.so.0 libglib1.2
libSDL-1.2.so.0 libsdl1.2debian-all
libXxf86vm.so.1 libxxf86vm1
libXxf86dga.so.1 libxxf86dga1
libcurl.so.3 libcurl3
"
found=`echo "$stored" | grep -m 1 "$1" | grep -o "[^ ]*$"`
if [ -n "$found" ]; then
    echo "$found"
fi
}

use_web_interface()
{
PACKAGE=`echo $1 | sed s/\+/%2B/g`
if [ "$distro" = "Ubuntu" ]; then
    searchaddress="http://packages.ubuntu.com/search?searchon=contents&keywords=$PACKAGE&mode=exactfilename&suite=$release&arch=i386"
else
    searchaddress="http://packages.ubuntu.com/search?searchon=contents&keywords=$PACKAGE&mode=exactfilename&suite=gutsy&arch=i386"
fi
packagenames=`wget --user-agent="getlibs" -q -O- "$searchaddress"`
if [ -z "$packagenames" ]; then
    echo 'Not able to connect to http://packages.ubuntu.com to find the package name'
fi
packagenames=`echo "$packagenames" | sed -n '/<td class=\"file\">/,/<\/td>/p' | grep -v '"keyword"' | grep -v "\(/debug/\|-dbg\)" | sed 's/<[^>]*>,*//g' | grep -m1 '[[:alnum:]]' | sed 's/[[:space:]]//g'`
if [ -n "$packagenames" ]; then
    echo "$packagenames"
fi
}

apt_file()
{
    returned=`apt-file search $1 | grep -m 1 -v "\(debug\|dbg\)" | cut -f1 -d ' '`
    if [ -n "$returned" ]; then
        echo ${returned/:/}
    fi
}

video_drivers() #Attempts to link libGL.so.1 to a driver if libGL.so.1 does not exist
{
    if [ "$installtype" = "native" ]; then
        videopath="/usr/lib"
    else
        videopath="/usr/lib32"
    fi

    if [ -z "`ls $videopath/libGL.so.* 2> /dev/null`" ]; then
        echo "libGL is installed from video drivers, please install or reinstall your video drivers"
    elif [ -f "$videopath/libGL.so.1" ]; then
        echo "libGL is installed from video drivers, please install or reinstall your video drivers"
    else
        videodriver=`ls $videopath/libGL.so.* | grep -o -m 1 '[^ ]*'`
        ln -s "$videodriver" "$videopath/libGL.so.1"
        echo "Created symbolic link from $videodriver to $videopath/libGL.so.1"
    fi
}

#Find the package name using the library filename
if [ -n "$library" ]; then
    packagelist=""
    for lib in $parameters; do
        lib=`basename $lib`
        returned=`stored_list "$lib"`
        if [ -n "`echo "$lib" | grep "libGL.so."`" ]; then
            video_drivers
        elif [ -n "$aptfile" ]; then
            returned=`apt_file "$lib"`
            if [ -n "$returned" ]; then
                packagelist="$packagelist$returned
"
            else
                echo "Apt-file returned no results for $lib"
            fi
        elif [ -n "$returned" ]; then
            echo "$lib: $returned"
            packagelist="$packagelist$returned
"
        else
            returned=`use_web_interface "$lib"`
            if [ -n "$returned" ]; then
                echo "$lib: $returned"
                packagelist="$packagelist$returned
"
            else
                echo "No match for $lib"
            fi
        fi
    done

    parameters="$packagelist"
    package="true"
fi

#If it is native it can apt-get and stop here
if [ "$installtype" = "native" ]; then
    if [ "`echo "$parameters" | grep "[[:alpha:]]"`" ]; then
        sudo apt-get install $parameters
    fi
    package=""
    parameters=""
    exit
fi

if [ -n "$package" ] && [ "`echo "$parameters" | grep "[[:alpha:]]"`" ]; then #If there are packages to download
    #Sort list of names and download links
    parameters=`echo "$parameters" | sort -u`
    echo -n "The following i386 packages will be installed:"
    echo "$parameters"
    if [ -z "$prompt" ]; then
        echo -n "Continue [Y/n]? "
        read prompt
    fi
        case $prompt in
            [nN]) clean_up_err;;
            [nN][oO]) clean_up_err;;
            [yY]) ;;
            [yY][eE][sS]) ;;
            "") ;;
            *) echo "Not understood. Aborting."; clean_up_err;; #Default to no
        esac
else
    if [ -n "$verbose" ]; then
        echo "No packages to download"
    fi
fi

#Find the download link using the name of the package
if [ -n "$package" ]; then
    links=""
    mirrorlist=""
    for pack in $parameters; do
        templink=`apt-cache --no-all-versions show $pack | grep -o -m 1 '[^ ]*\.deb$'`
        if [ -n "$templink" ]; then
            linkmirror="`apt-cache policy $pack | grep -m 1 -i -o '\(http:\|www.\|ftp:\|https:\)[^ ]*'`"
            if [ -n "$linkmirror" ]; then
                if [ -f "/etc/apt/sources.list" ]; then
                    linkmirror=`grep -o -m 1 "$linkmirror[^ ]*" /etc/apt/sources.list`
                elif [ -f "/etc/apt/sources.lst" ]; then
                    linkmirror=`grep -o -m 1 "$linkmirror[^ ]*" /etc/apt/sources.lst`
                else
                    echo "/etc/apt/sources.list not found"
                fi
                if [ -n "$linkmirror" ]; then
                    if [ -z "`echo $linkmirror | grep '/$'`" ]; then
                        linkmirror="$linkmirror/"
                    fi
                    mirrorlist="$mirrorlist$linkmirror "
                    templink="$linkmirror$templink"
                fi
            fi
            if [ -n "$verbose" ]; then
                echo "queue: $templink"
                echo "mirror: $linkmirror"
            fi
            links="$links $templink"
        else
            echo "$pack was not found in your repositories"
            echo "Make sure you have all repositories enabled and updated"
        fi
    done
    links=`echo ${links//amd64\.deb/i386\.deb}`
    mirrorlist=`echo "$mirrorlist" | sort -u`
    parameters="$links"
    link="true"
fi

if [ -z "$mirror" ]; then
    if [ "$distro" = "Ubuntu" ]; then
        mirror2='http://mirrors.kernel.org/ubuntu/'
    else
        mirror2='http://mirrors.kernel.org/debian/'
    fi
fi

#Create the links to the packages
if [ -n "$link" ]; then
    fulllinks=""
    for eachlink in $parameters; do
        if [ -z "`echo "$eachlink" | grep -i '\(http:\|www.\|ftp:\|https:\)'`" ]; then
            if [ -n "$verbose" ]; then
                echo "$mirror2 is the new mirror for $eachlink"
            fi
            fulllinks="$fulllinks $mirror2$eachlink"
        else
            fulllinks="$fulllinks $eachlink"
        fi
    done

    parameters="$fulllinks"
    download="true"
fi

#Local file(s) to install
if [ -n "$file" ]; then
    if [ "$architecture" = "x86" ]; then
        sudo dpkg -i $parameters; exit
    fi
    for eachfile in $parameters; do
        cp $eachfile $tempdir
    done
    parameters=""
    #build="true"
fi

copy_fail()
{
echo "Copying files failed - run getlibs with \"sudo getlibs\" or as root"
	clean_up_err
}

#Download and install
if [ -n "$download" ] && [ -n "`echo "$parameters" | grep "[[:alpha:]]"`" ]; then
    echo "Downloading ..."
    for eachlink in $parameters; do
        if [ -n "$verbose" ]; then
            echo "Downloading $eachlink"
        fi
        wget -q "--directory-prefix=$tempdir" "$eachlink"
        if [ $? -ne 0 ]; then
            echo "Failed to download file $eachlink"
            for eachmirror in $mirrorlist; do
                eachlink=`echo ${eachlink//$eachmirror/$mirror2}`
            done
            wget -q "--directory-prefix=$tempdir" "$eachlink"
            if [ $? -ne 0 ]; then
                wget_fail
            else
                echo "$eachlink downloaded successfully from $mirror2"
            fi
        fi
    done
    #build="true"
fi


dpkg_repack() {
    eachdeb="$1"
    debdir="`echo $eachdeb | sed 's/.deb//'`"
    debbase=`basename $debdir`

    dpkg --extract "$eachdeb" "$debdir-tmp"
    dpkg --control "$eachdeb" "$debdir-tmp/DEBIAN"
    mkdir -p "$debdir/DEBIAN"
    cd "$debdir-tmp"

    if [ -d "$debdir-tmp/lib" ]; then
        mv "lib" "lib32"
        cp -R "lib32/" "$debdir"
    fi
    if [ -d "$debdir-tmp/usr/lib" ]; then
        mkdir -p "$debdir/usr/"
        mv "usr/lib" "usr/lib32"
        cp -R "usr/lib32/" "$debdir/usr"
    fi
    
    if [ -f "DEBIAN/md5sums" ]; then
        grep ' \(usr/lib/\|lib/\)' DEBIAN/md5sums | sed 's+ lib/+ lib32/+g' | sed 's+ usr/lib/+ usr/lib32/+g' > "$debdir/DEBIAN/md5sums"
    fi

    debarch=`grep 'Architecture:' DEBIAN/control`
    debpackage=`grep 'Package:' DEBIAN/control`
    if [ -n "`echo $debpackage | grep lib`" ]; then
        newdebpackage=`echo ${debpackage/lib/lib32}`
    else
        newdebpackage="$debpackage-i386"
    fi
    sed "s/$debarch/Architecture: all/g" DEBIAN/control | sed "s/$debpackage/$newdebpackage/" | grep -v 'Depends:' | grep -v 'Conflicts:' | grep -v 'Replaces:' > "$debdir/DEBIAN/control"

    if [ -f "DEBIAN/postinst" ]; then
        cp "DEBIAN/postinst" "$debdir/DEBIAN"
    fi
    if [ -f "DEBIAN/postrm" ]; then
        cp "DEBIAN/postrm" "$debdir/DEBIAN"
    fi

    cd "$tempdir/build"
    dpkg --build "$debdir" "$debbase.deb"
    echo "Installing new $newdebpackage"
    sudo dpkg -i "$debbase.deb"
    if [ -n "$savebuild" ]; then
         echo "Moving new package $debbase.deb to /home/$USER/"
         cp $debbase.deb "/home/$USER/"
    fi
}

if [ -z "`ls $tempdir/*.deb 2> /dev/null`" ]; then
    echo "No packages to install"
    exit
fi

if [ -n "$build" ]; then #future default option
    mkdir "$tempdir/build"
    for eachdeb in `ls $tempdir/*.deb 2> /dev/null`; do
        if [ -n "$verbose" ]; then
            echo "extracting: $eachdeb"
        fi
        output=`dpkg_repack "$eachdeb"`
    done
else # --extract
    for eachdeb in `ls $tempdir/*.deb`; do
        if [ -n "$verbose" ]; then
            echo "extracting: $eachdeb"
        fi
        dpkg -x "$eachdeb" "$tempdir/extracted"
    done

    echo "Installing libraries ..."
    ldconfigparam=""
    if [ "$distro" = "Ubuntu" ]; then
        if [ -d $tempdir/extracted/usr/lib/ ]; then #If dir exists (and thus files to move)
            sudo cp -R $tempdir/extracted/usr/lib/* /usr/lib32/ || copy_fail
            ldconfigparam="$ldconfigparam/usr/lib32/ "
        fi
        if [ -d $tempdir/extracted/lib/ ]; then #If dir exists (and thus files to move)
            sudo cp -R $tempdir/extracted/lib/* /lib32/ || copy_fail
            ldconfigparam="$ldconfigparam/lib32/ "
        fi
    elif [ "$distro" = "Debian" ]; then
        sudo cp -R $tempdir/extracted/* /emul/ia32-linux/ || copy_fail
        ldconfigparam="$ldconfigparam/emul/ia32-linux/ "
    fi
fi

# --ldconfig
if [ -n "$ldconfig" ]; then
    sudo ldconfig -n $ldconfigparam
fi

#Check binary for new dependencies
if [ -n "$binarypath" ]; then
    runningdependencylist="$runningdependencylist
$dependencylist"
    dependencylist=`ldd "$binarypath" | grep "not found" | awk '{print $1}' | grep -v "\./"`
    if [ -z "$dependencylist" ]; then
        exit #All dependencies satisfied
    fi

    for eachdependency in $runningdependencylist; do 
        dependencylist=`echo ${dependencylist//$eachdependency/}`    
    done
    dependencylist=`echo "$dependencylist" | grep "[[:alnum:]]"`
    if [ -n "$dependencylist" ]; then
        rm -rf $tempdir/*
        echo "New depedencies have been detected"
        parameters="$dependencylist"
    else
        exit #No new dependencies
    fi
else
    exit
fi
done