327 lines
10 KiB
Bash
Executable File
327 lines
10 KiB
Bash
Executable File
#!/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: $1,missing 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: $1,missing 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: $1,missing lib: $lib_name"
|
||
rm -f $ROOT_DIR/*.txt
|
||
exit
|
||
fi
|
||
else
|
||
echo -e "\033[31m==ERROR==\033[0m file: $1,missing 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
|