#!/bin/bash ################################################################################ # step: # # 1. get all progs in rootfs, and get libraries on which these progs depend. # # 2. get libraries on which these libraries(from 1st step) depend. # # 3. get soft-link libraries if exist. # # 4. remove libraries that have not been used. # ################################################################################ SH_NAME=$0 OP_FLAG=$1 ROOT_DIR=${2%/} # remove '/' at the end of of a directory path if it has. PROGS=$ROOT_DIR/.progs.list LIBS=$ROOT_DIR/.libs.list PARSED_FILES=$ROOT_DIR/.parsed-files.list DEP_LIBS_REAL=$ROOT_DIR/.depend-libs-real.list DEP_LIBS_REAL_TMP=$ROOT_DIR/.depend-libs-real-tmp.list WARNING_FILES=$ROOT_DIR/.warning_files.list SPECIAL_LIBS=$ROOT_DIR/.special_libs.list MINIGUI_RES=$ROOT_DIR/.minigui_res.list help_info() { # get the basename of this scripts local shell_name=`basename $SH_NAME` echo -e "v1.1\n" echo -e "Downsize the rootfs or check the downsizing result!\n" echo -e "\033[32mUsage:\n\t./$shell_name \033[0m\n" echo -e "\t: operation." echo -e "\t\t d - downsize rootfs" echo -e "\t\t c - check the downsizing result" echo -e "\t: the relative directory of your rootfs.\n" } ################################################################################ # # # LOG FUNCTIONS # # # ################################################################################ function pr_error() { echo -e "\033[47;31mERROR: $*\033[0m" } function pr_warn() { # echo -e "\033[47;34mWARN: $*\033[0m" echo -e "\033[33mWARNING \033[0m $*" } function pr_info() { # echo -e "\033[47;30mINFO: $*\033[0m" echo -e "\033[32mINFO \033[0m $*" } get_lib_readelf() { readelf -d $1 | grep NEEDED | sed -r 's/.*\[(.*)\].*/\1/' } get_lib_strings() { strings -a $1 | grep -e "\.so\." -e "\.so$" \ | sed 's/ /\n/g' | sed -r 's/.*\/(.*)/\1/' | grep '\.so' } ################################################################################ # # # GET LIBRARIES # # # ################################################################################ # get_libs: get the library dependency of source file # $1 the source file. get_libs() { grep $1$ $PARSED_FILES > /dev/null if [ $? -eq 0 ]; then return fi echo "$1" >> $PARSED_FILES # readelf -s $ROOT_DIR/$prog_name | grep "\" > /dev/null 2>&1 grep -e dlopen -e LD_PRELOAD $1 > /dev/null if [ $? -eq 0 ]; then grep $1$ $SPECIAL_LIBS > /dev/null if [ $? -eq 0 ]; then local fdep_libs=$(get_lib_readelf $1) else local fdep_libs_readelf=$(get_lib_readelf $1) local fdep_libs=$(get_lib_strings $1) fi else local fdep_libs=$(get_lib_readelf $1) fi for ol in $fdep_libs do grep $ol$ $DEP_LIBS_REAL > /dev/null if [ $? -eq 0 ]; then continue fi local ol_real=`grep $ol$ $LIBS` if [ -z "$ol_real" ]; then if [ "x$OP_FLAG" == "xd" ]; then echo " "$fdep_libs_readelf" " | grep " $ol " > /dev/null if [ $? -eq 0 ]; then pr_error "file: $1, missing lib: $ol in $ROOT_DIR" rm -f $ROOT_DIR/.*.list exit else grep "^$1 $ol$" $WARNING_FILES> /dev/null if [ $? -ne 0 ]; then echo "$1 $ol" >> $WARNING_FILES pr_info "file: $1,MAY missing dlopen/preload lib: $ol" fi fi fi else echo "$ol_real" >> $DEP_LIBS_REAL # case: $ol -> $dst_lib, add the $dst_lib library. local dst_lib=`readlink $ol_real` if [ -n "$dst_lib" ]; then echo $ol_real | sed "s/$ol/$dst_lib/g" >> $DEP_LIBS_REAL fi # case: $link_lib -> $ol, add the $link_lib library. local link_lib=`ls -l ${ol_real%/*} | grep "^l.*$ol$" | \ awk -F '->' '{print $1}' | awk '{print $NF}'` if [ -n "$link_lib" ]; then echo $ol_real | sed "s/$ol/$link_lib/g" >> $DEP_LIBS_REAL fi fi done } # get_progs_depend_libs: get libraries on which all programs depends get_progs_depend_libs() { file -F '' `find $ROOT_DIR` | \ awk '/dynamically linked/ {print $1}' | grep -v '\.so' > $PROGS find $ROOT_DIR -name "*.so*" -o -name "*.a"> $LIBS while read prog_name do get_libs $prog_name done < $PROGS } ################################################################################ # # # FOR SPECIFIC LIBRARIES # # # ################################################################################ # get_used_libcedarx: get used cedarx libraries get_used_libcedarx() { if [ -f $ROOT_DIR/etc/cedarx.conf ]; then local used_libcedarx=`grep "^l.*.so$" \ $ROOT_DIR/etc/cedarx.conf | awk '{print $3}'` for libcedarx_name in $used_libcedarx do local libcedarx_name_real=`grep $libcedarx_name$ $LIBS` if [ ! -f "$libcedarx_name_real" ]; then pr_warn "can't find $libcedarx_name (in cedarx.conf) in rootfs." else echo "$libcedarx_name_real" >> $DEP_LIBS_REAL fi done fi if [ -f $ROOT_DIR/etc/xdg/gstomx.conf ]; then find $ROOT_DIR/usr/lib -maxdepth 1 -name "libOmx*.so" >> $DEP_LIBS_REAL fi } # get_used_tslib: get used tslib get_used_tslib() { if [ -f $ROOT_DIR/etc/tslib-env.sh ]; then local used_tslib_path=$ROOT_DIR/`grep TSLIB_PLUGINDIR \ $ROOT_DIR/etc/tslib-env.sh | awk -F = '{print $2}' | sed 's#/$##g'` local used_tslib=`ls -1 $used_tslib_path ` if [ -n "$used_tslib" ]; then echo "$used_tslib" | \ sed "s#^#$used_tslib_path/#g" >> $DEP_LIBS_REAL echo `grep libts.so.0 $LIBS` | sed 's/ /\n/g' >> $SPECIAL_LIBS fi fi } # get_used_alsa_lib: get used alsa-lib plugins get_used_alsa_lib() { if [ -f $ROOT_DIR/usr/lib/libasound.so.2 \ -a -d $ROOT_DIR/usr/lib/alsa-lib ]; then local used_alsa_lib=`ls $ROOT_DIR/usr/lib/alsa-lib` if [ -n "$used_alsa_lib" ]; then echo "$used_alsa_lib" | \ sed "s#^#$ROOT_DIR/usr/lib/alsa-lib/#g" >> $DEP_LIBS_REAL echo `grep usr/lib/libasound.so.2 $LIBS` | \ sed 's/ /\n/g' >> $SPECIAL_LIBS fi fi } # get_used_directfb_lib: get used directfb libs get_used_directfb_lib() { if [ -f $ROOT_DIR/usr/lib/libdirectfb.so \ -a -d $ROOT_DIR/usr/lib/directfb* ]; then local used_directfb_lib=`find $ROOT_DIR/usr/lib/directfb* -name "*.so*"` if [ -n "$used_directfb_lib" ]; then echo `grep usr/lib/libdirectfb $LIBS` | \ sed 's/ /\n/g' >> $DEP_LIBS_REAL echo "$used_directfb_lib" >> $DEP_LIBS_REAL echo `grep usr/lib/libdirectfb $LIBS` | \ sed 's/ /\n/g' >> $SPECIAL_LIBS fi fi } # get_used_tinatest_lib: get used tinatest libs get_used_tinatest_lib() { if [ -f $ROOT_DIR/usr/bin/tinatest -a -d $ROOT_DIR/usr/lib/tt-module ]; then local used_tinatest_lib=`find $ROOT_DIR/usr/lib/tt-module -name "*.so*"` if [ -n "$used_tinatest_lib" ]; then echo "$used_tinatest_lib" >> $DEP_LIBS_REAL fi fi } # get_used_gstreamer_lib: get used gstreamer libs get_used_gstreamer_lib() { find $ROOT_DIR/usr/lib -maxdepth 1 -name libgst* >> $DEP_LIBS_REAL if [ -d $ROOT_DIR/usr/lib/gstreamer-1.0 ]; then local used_gstreamer_lib=`ls $ROOT_DIR/usr/lib/gstreamer-1.0` if [ -n "$used_gstreamer_lib" ]; then echo "$used_gstreamer_lib" | \ sed "s#^#$ROOT_DIR/usr/lib/gstreamer-1.0/#g" >> $DEP_LIBS_REAL fi fi } # get_used_eyesee_mpp_lib: get used eyesee_mpp libs get_used_eyesee_mpp_lib() { if [ -d $ROOT_DIR/usr/lib/eyesee-mpp ]; then if [ -f $ROOT_DIR/usr/lib/libglog.so ]; then find $ROOT_DIR/usr/lib -maxdepth 1 -name "libglog*" >> $DEP_LIBS_REAL fi if [ -f $ROOT_DIR/usr/lib/libasound.so.2 ]; then find $ROOT_DIR/usr/lib -maxdepth 1 -name "libasound*" >> $DEP_LIBS_REAL fi if [ -d $ROOT_DIR/usr/lib/alsa-lib ]; then find $ROOT_DIR/usr/lib/alsa-lib -maxdepth 1 -name "*.so" >> $DEP_LIBS_REAL fi if [ -f $ROOT_DIR/usr/lib/libVIPlite.so ]; then find $ROOT_DIR/usr/lib -maxdepth 1 -name "libVIPlite*" >> $DEP_LIBS_REAL fi if [ -f $ROOT_DIR/usr/lib/libVIPuser.so ]; then find $ROOT_DIR/usr/lib -maxdepth 1 -name "libVIPuser*" >> $DEP_LIBS_REAL fi if [ -f $ROOT_DIR/usr/lib/libawnn.so ]; then find $ROOT_DIR/usr/lib -maxdepth 1 -name "libawnn*" >> $DEP_LIBS_REAL fi if [ -f $ROOT_DIR/usr/lib/libawnn_full.so ]; then find $ROOT_DIR/usr/lib -maxdepth 1 -name "libawnn_full*" >> $DEP_LIBS_REAL fi if [ -f $ROOT_DIR/usr/lib/libawaiisp.so ]; then find $ROOT_DIR/usr/lib -maxdepth 1 -name "libawaiisp*" >> $DEP_LIBS_REAL fi if [ -f $ROOT_DIR/usr/lib/libexpat.so.1 ]; then find $ROOT_DIR/usr/lib -maxdepth 1 -name "libexpat*" >> $DEP_LIBS_REAL fi fi } # get_specific_used_libs: get the specific used libs get_specific_used_libs() { # for glibc, add /lib/libnss_* and libresolv*. # refer to https://sourceware.org/ml/libc-help/2009-05/msg00046.html find $ROOT_DIR/lib -maxdepth 1 -name libnss_* \ -o -name libresolv* >> $DEP_LIBS_REAL get_used_libcedarx get_used_tslib get_used_alsa_lib get_used_directfb_lib get_used_tinatest_lib get_used_gstreamer_lib get_used_eyesee_mpp_lib } ################################################################################ # # # RECURSIVE TO GET ALL NEEDED LIBRARIES # # # ################################################################################ # get_lib_depend_libs: get the library dependency of librires. get_lib_depend_libs() { #keep every library only once sort -u $DEP_LIBS_REAL -o $DEP_LIBS_REAL #get lib based lib while true do cp -f $DEP_LIBS_REAL $DEP_LIBS_REAL_TMP while read ol do get_libs $ol done < $DEP_LIBS_REAL_TMP sort -u $DEP_LIBS_REAL -o $DEP_LIBS_REAL diff $DEP_LIBS_REAL $DEP_LIBS_REAL_TMP > /dev/null if [ $? -eq 0 ]; then break fi done } ################################################################################ # # # REMOVE FUNCTIONS # # # ################################################################################ downsize_prepare() { rm -rf $ROOT_DIR/.*.list touch $PROGS $LIBS $PARSED_FILES $DEP_LIBS_REAL \ $DEP_LIBS_REAL_TMP $WARNING_FILES $SPECIAL_LIBS $MINIGUI_RES } # remove_unused_libs: remove unused libs in /lib and /usr/lib remove_unused_libs() { find $ROOT_DIR/lib -maxdepth 1 -name "*.so*" -o -name "*.a" > $LIBS find $ROOT_DIR/usr/lib -maxdepth 1 -name "*.so*" -o -name "*.a" >> $LIBS if [ "x$OP_FLAG" == "xd" ]; then rm -rf `grep -F -v -f $DEP_LIBS_REAL $LIBS | sort | uniq -u` fi if [ "x$OP_FLAG" == "xc" ]; then # for case $OP_FLAG is equal to 'c' local diff_lib=`grep -F -v -f $DEP_LIBS_REAL $LIBS | sort | uniq -u` if [ -n "$diff_lib" ]; then pr_error "following libraries have not been used:" echo -e "$diff_lib" else echo -e "Check result: \033[32m==RIGHT==\033[0m" fi fi } # remove_all_unused_libs: remove all unused libs in rootfs remove_all_unused_libs() { if [ "x$OP_FLAG" == "xd" ]; then rm -rf `cat $DEP_LIBS_REAL $LIBS | sort | uniq -u` fi if [ "x$OP_FLAG" == "xc" ]; then # for case $OP_FLAG is equal to 'c' local diff_lib=`cat $DEP_LIBS_REAL $LIBS | sort | uniq -u` if [ -n "$diff_lib" ]; then pr_error "following libraries have not been used:" echo -e "$diff_lib" else echo -e "Check result: \033[32m==RIGHT==\033[0m" fi fi } # remove_unused_res: remove unused resources remove_unused_res() { # rm unused minigui res if [ -f "$ROOT_DIR/usr/local/etc/MiniGUI.cfg" ]; then find $ROOT_DIR/usr/share/local/minigui -type f > $MINIGUI_RES local minigui_used_res=`cat $ROOT_DIR/usr/local/etc/MiniGUI.cfg | \ grep -E '\.bmp|\.gif|\.cur|\.bin|\.ico|\.upf|\.vbf|\.name' | \ grep -v '^#' | sed -r 's/.*=(.*)/\1/' | sed -r 's/.*\/(.*)/\1/'` for res_name in $minigui_used_res do sed -i "/.*\/${res_name}/d" $MINIGUI_RES done if [ "x$OP_FLAG" == "xd" ]; then rm -rf `cat $MINIGUI_RES` fi if [ "x$OP_FLAG" == "xc" ]; then if [ ! -s "$MINIGUI_RES" ]; then echo -e "MiniGUI Check result: \033[32m==RIGHT==\033[0m" fi fi fi } # downsize_rootfs: remove unused libraries and resources downsize_rootfs() { # remove_unused_all_libs remove_unused_libs remove_unused_res rm -rf $ROOT_DIR/.*.list } ################################################################################ # # # MAIN # # # ################################################################################ if [ $# -ne 2 ]; then help_info exit fi if [ "x$OP_FLAG" != "xd" ]; then if [ "x$OP_FLAG" != "xc" ]; then help_info pr_error " : '$OP_FLAG' should be 'd' or 'c'" exit fi fi if [ ! -d "$ROOT_DIR" ]; then help_info pr_error " : '$ROOT_DIR' does not exist!" exit fi if [ "x$OP_FLAG" == "xd" ]; then if [ -d "${ROOT_DIR}-tmp" ]; then echo "Directory ${ROOT_DIR}-tmp is exist!" cp -rf $ROOT_DIR/. ${ROOT_DIR}-tmp else echo "Directory ${ROOT_DIR}-tmp is not exist, back it up!" cp -narf $ROOT_DIR ${ROOT_DIR}-tmp fi fi downsize_prepare get_progs_depend_libs get_specific_used_libs get_lib_depend_libs downsize_rootfs