SmartAudio/scripts/reduce-rootfs-size.sh

327 lines
10 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
###############################################################
# step:
# 1. get all apps in bin/, sbin/, usr/bin, usr/sbin, and get
# libraries these apps depend on.
# 2. get libraries these libraries(from 1st step) depend on.
# 3. get soft-link libraries if exist.
# 4. remove libraries that have not been used.
###############################################################
SH_NAME=$0
OP_FLAG=$1
ROOT_DIR=${2%/} # rm '/' at the end of of a directory path if it has.
help_info()
{
# get the basename of this scripts
local shell_name=`basename $SH_NAME`
echo -e "v1.1\n"
echo -e "This script will downsize the rootfs or check the downsizing result!\n"
echo -e "\033[32mUsage:\n\t./$shell_name <op_flag> <root_dir>\033[0m\n"
echo -e "\t<op_flag>: operation.\n\t\t d - downsize rootfs\n\t\t c - check the downsizing result"
echo -e "\t<root_dir>: the relative directory of your rootfs.\n"
}
################################################################################
# function: get the library dependency of source file
# $1: the source file.
# $2: the library dependency of source file.
# $3: the dlopen library dependency of source file.
################################################################################
get_libs()
{
#readelf -s $ROOT_DIR/$app_name | grep "\<UND dlopen\>" > /dev/null 2>&1
strings -a $1 | grep dlopen > /dev/null
if [ $? -ne 0 ]; then
local file_based_libs=`readelf -d $1 | grep NEEDED | sed -r 's/.*\[(.*)\].*/\1/'`
else
local file_based_libs_readelf=`readelf -d $1 | grep NEEDED | sed -r 's/.*\[(.*)\].*/\1/'`
local file_based_libs=`strings -a $1 | grep -e "\.so\." -e "\.so$" | sed -r 's/.*\/(.*)/\1/'`
for lib_name in $file_based_libs
do
echo $file_based_libs_readelf | grep $lib_name > /dev/null
if [ $? -ne 0 ]; then
echo "$lib_name" >> $3
fi
done
fi
echo "$file_based_libs" >> $2
# check the existence of source-file's based libs.
if [ "x$OP_FLAG" == "xd" ]; then
for lib_name in $file_based_libs
do
if [ ! -f "$ROOT_DIR/lib/$lib_name" ]; then
if [ ! -f "$ROOT_DIR/usr/lib/$lib_name" ]; then
if [ -f "$3" ]; then
grep $lib_name $3 > /dev/null
if [ $? -eq 0 ]; then
if [ ! -f "$ROOT_DIR/warning_file.txt" -a ! -f "$ROOT_DIR/warning_lib.txt" ]; then
echo -e "\033[33m==WARNING==\033[0m file: $1missing dlopen lib: $lib_name"
echo "$1" >> $ROOT_DIR/warning_file.txt
echo "$lib_name" >> $ROOT_DIR/warning_lib.txt
else
grep $1 $ROOT_DIR/warning_file.txt > /dev/null && grep $lib_name $ROOT_DIR/warning_lib.txt > /dev/null
if [ $? -ne 0 ]; then
echo -e "\033[33m==WARNING==\033[0m file: $1missing dlopen lib: $lib_name"
echo "$1" >> $ROOT_DIR/warning_file.txt
echo "$lib_name" >> $ROOT_DIR/warning_lib.txt
fi
fi
else
echo -e "\033[31m==ERROR==\033[0m file: $1missing lib: $lib_name"
rm -f $ROOT_DIR/*.txt
exit
fi
else
echo -e "\033[31m==ERROR==\033[0m file: $1missing lib: $lib_name"
rm -f $ROOT_DIR/*.txt
exit
fi
fi
fi
done
fi
}
################################################################################
# function: get the library dependency of librires.
# $1: the file contains librires' name.
# $2: the library dependency of all librires in $1.
# $3: the dlopen library dependency of all librires in $1.
################################################################################
get_libs_extend()
{
while read lib_name
do
if [ -f "$ROOT_DIR/lib/$lib_name" ]; then
get_libs $ROOT_DIR/lib/$lib_name $2 $3
else
if [ -f "$ROOT_DIR/usr/lib/$lib_name" ]; then
get_libs $ROOT_DIR/usr/lib/$lib_name $2 $3
fi
fi
done < $1
#keep every library only once
sort -u $2 -o $2
if [ -f "$3" ]; then
sort -u $3 -o $3
fi
}
get_app_based_libs()
{
#get all executable files.
if [ -z "$2" ]; then
local regular_file=`find $ROOT_DIR/$1 -maxdepth 1 -type f`
else
local regular_file=`find $ROOT_DIR/$1/$2 -maxdepth 1 -type f`
fi
for app_name in $regular_file
do
file $app_name | grep ELF | grep "executable" | grep "dynamically linked" > /dev/null
if [ $? -eq 0 ]; then
get_libs $app_name $ROOT_DIR/app-based-libs.txt $ROOT_DIR/dlopen-libs.txt
fi
done
}
# get used libcedarx function
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
if [ ! -f "$ROOT_DIR/lib/$libcedarx_name" ]; then
if [ ! -f "$ROOT_DIR/usr/lib/$libcedarx_name" ]; then
echo -e "\033[31m==ERROR==\033[0m can't find $libcedarx_name (refer to $ROOT_DIR/etc/cedarx.conf) in rootfs."
rm -f $ROOT_DIR/*.txt
exit
fi
fi
done
echo "$used_libcedarx" >> $ROOT_DIR/app-based-libs.txt
fi
}
get_lib_based_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* | sed -r 's/.*\/(.*)/\1/' >> $ROOT_DIR/app-based-libs.txt
#keep every library only once
sort -u $ROOT_DIR/app-based-libs.txt -o $ROOT_DIR/app-based-libs.txt
cp $ROOT_DIR/app-based-libs.txt $ROOT_DIR/all-based-libs-tmp.txt
#get lib based lib
while true
do
cp -f $ROOT_DIR/all-based-libs-tmp.txt $ROOT_DIR/all-based-libs-tmp-diff.txt
if [ -f "$ROOT_DIR/dlopen-libs.txt" ]; then
cp -f $ROOT_DIR/dlopen-libs.txt $ROOT_DIR/dlopen-libs-diff.txt
fi
cp -f $ROOT_DIR/all-based-libs-tmp.txt $ROOT_DIR/app-based-libs.txt
get_libs_extend $ROOT_DIR/app-based-libs.txt $ROOT_DIR/all-based-libs-tmp.txt $ROOT_DIR/dlopen-libs.txt
diff $ROOT_DIR/all-based-libs-tmp.txt $ROOT_DIR/all-based-libs-tmp-diff.txt > /dev/null
if [ $? -eq 0 ]; then
[ ! -f $ROOT_DIR/dlopen-libs.txt ] && break
[ ! -f $ROOT_DIR/dlopen-libs-diff.txt ] && break
diff $ROOT_DIR/dlopen-libs.txt $ROOT_DIR/dlopen-libs-diff.txt > /dev/null
if [ $? -eq 0 ]; then
rm -f $ROOT_DIR/all-based-libs-tmp-diff.txt $ROOT_DIR/dlopen-libs-diff.txt
break
fi
fi
done
while read ol
do
if [ -f "$ROOT_DIR/lib/$ol" ]; then
echo "lib/$ol" >> $ROOT_DIR/lib-based-libs.txt
# for case: $ol -> $target_lib, get the $target_lib
local target_lib=` readlink $ROOT_DIR/lib/$ol `
# if $ol is a soft-link library, add the $target_lib library.
if [ -n "$target_lib" ]; then
echo "lib/$target_lib" >> $ROOT_DIR/lib-based-libs.txt
fi
# for case: $link_lib -> $ol, get the $link_lib (only the same dir)
local link_lib=`ls -l $ROOT_DIR/lib | grep "^l.*$ol$" | awk -F'->' '{print $1}' | awk '{print $NF}'`
# if $link_lib links to $ol, add the $link_lib library.
if [ -n "$link_lib" ]; then
echo "lib/$link_lib" >> $ROOT_DIR/lib-based-libs.txt
fi
else
if [ -f "$ROOT_DIR/usr/lib/$ol" ]; then
echo "usr/lib/$ol" >> $ROOT_DIR/lib-based-libs.txt
# for case: $ol -> $target_lib, get the $target_lib
local target_lib=` readlink $ROOT_DIR/usr/lib/$ol `
# if $ol is a soft-link library, add the $target_lib library.
if [ -n "$target_lib" ]; then
echo "usr/lib/$target_lib" >> $ROOT_DIR/lib-based-libs.txt
fi
# for case: $link_lib -> $ol, get the $link_lib (only the same dir)
local link_lib=`ls -l $ROOT_DIR/usr/lib | grep "^l.*$ol$" | awk -F'->' '{print $1}' | awk '{print $NF}'`
# if $link_lib links to $ol, add the $link_lib library.
if [ -n "$link_lib" ]; then
echo "usr/lib/$link_lib" >> $ROOT_DIR/lib-based-libs.txt
fi
fi
fi
done < $ROOT_DIR/all-based-libs-tmp.txt
# sort -u $ROOT_DIR/lib-based-libs.txt
}
downsize_rootfs()
{
find $ROOT_DIR/lib -maxdepth 1 -type f -o -type l | sed -r 's/.*\/(.*)/\1/' | grep -e "^ld" -e "^lib" | sed "s/^/lib\//g" | sort >> $ROOT_DIR/libs.txt
find $ROOT_DIR/usr/lib -maxdepth 1 -type f -o -type l | sed -r 's/.*\/(.*)/\1/' | grep -e "^ld" -e "^lib" | sed "s/^/usr\/lib\//g" | sort >> $ROOT_DIR/libs.txt
# another way
# find lib -maxdepth 1 -type f -printf '%f\n' -o -type l -printf '%f\n' | grep -e "^ld" -e "^lib" | sed "s/^/lib\//g" | sort >> $ROOT_DIR/libs.txt
if [ "x$OP_FLAG" == "xd" ]; then
rm -rf `cat $ROOT_DIR/lib-based-libs.txt $ROOT_DIR/libs.txt | sort | uniq -u | sed "s#^#$ROOT_DIR/#g"`
fi
if [ "x$OP_FLAG" == "xc" ]; then
# for case $OP_FLAG is equal to 'c'
local diff_lib=`cat $ROOT_DIR/lib-based-libs.txt $ROOT_DIR/libs.txt | sort | uniq -u`
if [ -n "$diff_lib" ]; then
echo -e "Check result:\033[31m==ERROR==\033[0m following libraries have not been used:\n$diff_lib"
else
echo -e "Check result:\033[32m==RIGHT==\033[0m"
fi
fi
# rm unused minigui res
if [ -f "$ROOT_DIR/usr/local/etc/MiniGUI.cfg" ]; then
find $ROOT_DIR/usr/share/local/minigui -type f > $ROOT_DIR/minigui_res.txt
grep -E '\.bmp|\.gif|\.cur|\.bin|\.ico|\.upf|\.vbf|\.name' $ROOT_DIR//usr/local/etc/MiniGUI.cfg | grep -v '^#' | sed -r 's/.*=(.*)/\1/' | sed -r 's/.*\/(.*)/\1/' > $ROOT_DIR/minigui_used_res.txt
while read res_name
do
sed -i "/$res_name/d" $ROOT_DIR/minigui_res.txt
done < $ROOT_DIR/minigui_used_res.txt
if [ "x$OP_FLAG" == "xd" ]; then
rm -rf `cat $ROOT_DIR/minigui_res.txt`
fi
if [ "x$OP_FLAG" == "xc" ]; then
if [ ! -s "$ROOT_DIR/minigui_res.txt" ]; then
echo -e "MiniGUI Check result:\033[32m==RIGHT==\033[0m"
fi
fi
fi
rm -f $ROOT_DIR/*.txt
}
###############################################################################
if [ $# -ne 2 ]; then
help_info
exit
fi
if [ "x$OP_FLAG" != "xd" ]; then
if [ "x$OP_FLAG" != "xc" ]; then
help_info
echo -e "\t\033[31m==ERROR==\033[0m <op_flag>: '$OP_FLAG' should be 'd' or 'c'"
exit
fi
fi
if [ ! -d "$ROOT_DIR" ]; then
help_info
echo -e "\t\033[31m==ERROR==\033[0m <root_dir>: '$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
get_app_based_libs bin
get_app_based_libs sbin
get_app_based_libs usr bin
get_app_based_libs usr sbin
get_used_libcedarx
get_lib_based_libs
downsize_rootfs