#!/bin/sh # author polikuo # version 1.7 # June 27 2018 . /etc/init.d/tc-functions useBusybox showhelp() { [ "$C" ] && echo -n ${YELLOW} 1>&2 local BN=$(basename $0) echo "${BN}: A script that seeks dependencies in a given directory" 1>&2 echo "Usage: ${BN} [-option] directory [append your list here ...]" 1>&2 echo 'Available Options (default -ns) -c colorful output -d show only the detected tczs, without custom extensions (blue) -g graph .tcz.tree (magenta) -h show this helpinfo (yellow) -n show dependencies that can not be found (red) -p scan provides.db for dependencies -r show recursively scanned tczs (green) -s show shortened tczs (cyan) -t DIR set tcedir to DIR (default /etc/sysconfig/tcedir)' 1>&2 [ "$C" ] && echo -n ${NORMAL} 1>&2 exit 1 } copy2fs() { local COPY2FS [ "$C" ] && echo -n ${RED} 1>&2 if [ -f "${TCEDIR}/copy2fs.lst" ]; then echo -n "WARNING! copy2fs.lst found in ${TCEDIR}" 1>&2 echo ", please disable it and reboot" 1>&2 COPY2FS="true" fi if [ -f "${TCEDIR}/copy2fs.flg" ]; then echo -n "WARNING! copy2fs.flg found in ${TCEDIR}" 1>&2 echo ", please disable it and reboot" 1>&2 COPY2FS="true" fi [ "$C" ] && echo -n ${NORMAL} 1>&2 [ "$COPY2FS" ] && exit 1 } # additional custom extensions extra() { local EXT SHEBANG for EXT in $@; do EXT=${EXT##*/} EXT=${EXT%.tcz} EXT=${EXT//KERNEL/$KERNELVER} APPEND="${APPEND}${EXT} " done # check script # shebang limit is set to 128, head -n1 is slow with binary files SHEBANG=$(find -type f -exec head -c128 {} + 2> /dev/null | grep '^#!') if [ "$SHEBANG" ]; then case "$SHEBANG" in *bash* ) APPEND="${APPEND}bash " ;; esac case "$SHEBANG" in *perl* ) APPEND="${APPEND}perl5 " ;; esac case "$SHEBANG" in *php* ) echo "${RED}WARNING! php script detected${NORMAL}" 1>&2 ;; esac case "$SHEBANG" in *python* ) echo "${RED}WARNING! python script detected${NORMAL}" 1>&2 ;; esac fi } unique() { local A BUFFER=' ' for A in "$@"; do case "$BUFFER" in *" ${A} "* ) :;; * ) BUFFER="${BUFFER}${A} ";; esac done echo "$BUFFER" } rm_matched_in_list() { local B BUFFER="$1" REMOVE OUT=' ' shift REMOVE=" $(echo $@) " for B in $BUFFER; do case "$REMOVE" in *" ${B} "* ) :;; * ) OUT="${OUT}${B} ";; esac done echo "$OUT" } # check if TCZS existed chkexist() { local FILE QUIT [ "$C" ] && echo -n ${RED} for FILE in $@; do # $KERNELVER already replaced [ -s "${TCEDIR}/optional/${FILE}.tcz" ] || { echo "${FILE}.tcz not found or size is zero" 1>&2 QUIT="1" } done if [ "$QUIT" ]; then echo "Please move the tczs and the dep files into your" 1>&2 echo "${TCEDIR}/optional/${NORMAL}" 1>&2 exit 1 fi [ "$C" ] && echo -n ${NORMAL} } # check for redundant del_redundant() { local LIST RPT REMOVE GRAPH # $KERNELVER already replaced LIST=" $(echo $TCZS) " for RPT in $TCZS; do if [ -s "${TCEDIR}/optional/${RPT}.tcz.dep" ]; then for REMOVE in $(cat "${TCEDIR}/optional/${RPT}.tcz.dep"); do REMOVE=${REMOVE##*/} REMOVE=${REMOVE%.tcz} REMOVE=${REMOVE//KERNEL/$KERNELVER} LIST="${LIST/ ${REMOVE} / }" done fi done LIST=$(echo ${LIST//$KERNELVER/KERNEL} | tr ' ' '\n' | sort) [ "$C" ] && echo -n ${CYAN} [ "$S" ] && echo "$LIST" | sed 's:$:.tcz:g' [ "$S" ] && [ "$G" ] && echo '' if [ "$G" ]; then [ "$C" ] && echo -n ${MAGENTA} # use for loop to prevent early quitting in awk for GRAPH in $LIST; do graph $GRAPH done fi [ "$C" ] && echo -n ${NORMAL} } # recursively scan dependencies rscan() { cd "${TCEDIR}/optional" || exit 1 echo $@ | awk -v KERNELVER="$KERNELVER" ' function awk_scan(name, depfile, line) { gsub(/ /, "", name) if (name) { sub(/\.tcz/, "", name) sub(/KERNEL/, KERNELVER, name) depfile = name ".tcz.dep" print name while (getline line < depfile > 0) awk_scan(line) close(depfile) } } {for(i=1;i<=NF;i++) awk_scan($i)}' cd - &> /dev/null } scandir() { # global DETECTED NOTFOUND local FIND_EXEC LDD_OUT SELF LIBS S NF FIND_EXEC=$(for A in $(find . -not -type d); do [ -x $A ] && echo $A; done) LDD_OUT=$(ldd $FIND_EXEC 2> /dev/null) SELF=$(echo "$FIND_EXEC" | sed 's:.::') LIBS=$( echo "$LDD_OUT" | awk '/=>/ && !/not found$/{U[$3]=1} END{for (var in U) printf var " "}' ) LIBS=$(rm_matched_in_list "$LIBS" $SELF) DETECTED=$(realpath $LIBS 2> /dev/null | grep '^/tmp/tcloop/' | cut -d '/' -f 4) DETECTED=$(unique $DETECTED) if [ "$N" ]; then SELF=$(echo "$FIND_EXEC" | sed 's:.*/::') NF=$( echo "$LDD_OUT" | awk '/not found$/{U[$1]=1} END{for (var in U) printf var " "}' ) NF=$(rm_matched_in_list "$NF " $SELF) NOTFOUND=$(echo $NF | tr ' ' '\n') fi } searchDB() { local NF=$NOTFOUND TARGET PROVIDES ADDED NOTDOWNLOADED CLUSTER NOWHERE for TARGET in $NF; do PROVIDES=$( awk 'BEGIN {FS="\n";RS=""} /\/'${TARGET}'\n/ || /\/'${TARGET}'$/ {print $1}' "${TCEDIR}/${DB}" ) if [ "$PROVIDES" ]; then if [ $(echo "$PROVIDES" | wc -l) -eq 1 ]; then if [ -s "${TCEDIR}/optional/${PROVIDES}" ]; then APPEND="${APPEND}${PROVIDES} " ADDED=$( echo "$ADDED" echo "${PROVIDES} provides ${TARGET}, list appended" ) NOTFOUND=$(echo "$NOTFOUND" | grep -v "^${TARGET}$") else NOTDOWNLOADED=$( echo "$NOTDOWNLOADED" echo "${TARGET} can be found in: ${PROVIDES}" ) fi else CLUSTER=$( echo "$CLUSTER" echo $TARGET can be found in: $PROVIDES ) fi else NOWHERE=$( echo "$NOWHERE" echo "$TARGET" ) fi done if [ "$ADDED" ]; then echo "Note: These dependencies are detected in ${DB}:${ADDED}" 1>&2 echo '' 1>&2 fi if [ "$N" ]; then if [ "$NOWHERE" ]; then echo "These dependencies can not be found anywhere:${NOWHERE}" 1>&2 echo '' 1>&2 fi if [ "$NOTDOWNLOADED" ]; then echo "These dependencies are not presented in ${TCEDIR}/optional" 1>&2 echo "Please download these extensions:${NOTDOWNLOADED}" 1>&2 echo '' 1>&2 fi if [ "$CLUSTER" ]; then echo "Found potential deps in ${DB}, but not proccessed:${CLUSTER}" 1>&2 echo '' 1>&2 fi fi } graph() { cd "${TCEDIR}/optional" echo $1 | awk -v KERNELVER="$KERNELVER" ' BEGIN{layer = 0} function dep_tree(name, depfile, line) { depfile = name ".tcz.dep" layer += 1 while(getline line < depfile > 0) { gsub(/ /, "", line) sub(/\.tcz$/, "", line) sub(/KERNEL/, KERNELVER, line) if(line) { for(i=0;i /dev/null } # Options C='' D='' G='' N='' P='' R='' S='' while getopts cdghnprst: option 2> /dev/null do case "$option" in c ) C="true";; d ) D="true";; g ) G="true";; h ) showhelp;; n ) N="true";; p ) P="true";; r ) R="true";; s ) S="true";; t ) TCEDIR=$(realpath $OPTARG) || echo "Using default directory" 1>&2;; * ) echo "Invalid options"; showhelp;; esac done [ "$C" ] || RED='' GREEN='' YELLOW='' BLUE='' MAGENTA='' CYAN='' NORMAL='' [ "$D" ] || [ "$G" ] || [ "$N" ] || [ "$R" ] || [ "$S" ] || N="true" S="true" shift $((OPTIND-1)) # directory to scan [ "$(echo $1)" ] || ! echo "${RED}Where to search ?${NORMAL}" 1>&2 || showhelp [ -d "$1" ] || ! echo "${RED}'${1}' is not a directory${NORMAL}" 1>&2 || showhelp cd $1 shift # main [ "$TCEDIR" ] || TCEDIR=$(realpath /etc/sysconfig/tcedir) readonly TCEDIR [ -d "$TCEDIR" ] || ! echo "${RED}${TCEDIR} is not a directory${NORMAL}" 1>&2 || exit 1 copy2fs readonly KERNELVER=$(uname -r) APPEND=' ' extra $@ DETECTED='' NOTFOUND='' scandir if [ "$P" ]; then [ "$C" ] && echo -n ${RED} readonly DB="provides.db" getMirror cd "$TCEDIR" if zsync -i "${TCEDIR}/${DB}" -q "${MIRROR}/${DB}.zsync" then rm -f "${DB}.zs-old" else wget -O "${TCEDIR}/${DB}" "${MIRROR}/${DB}" &> /dev/null fi cd - &> /dev/null searchDB [ "$C" ] && echo -n ${NORMAL} fi SCAN="${APPEND}${DETECTED}" if [ "$G" ] || [ "$R" ] || [ "$S" ]; then if [ "$(echo $SCAN)" ]; then TCZS=$(rscan $SCAN) TCZS=$(unique $TCZS) chkexist $TCZS else TCZS='' fi fi # output if [ "$D" ] && [ "$(echo $DETECTED)" ]; then chkexist $DETECTED [ "$C" ] && echo -n ${BLUE} echo ${DETECTED//$KERNELVER/KERNEL} | tr ' ' '\n' | sort | sed 's:$:.tcz:g' [ "$N" ] && [ "$NOTFOUND" ] || [ "$R" ] || [ "$S" ] && echo '' [ "$C" ] && echo -n ${NORMAL} fi if [ "$N" ] && [ "$(echo $NOTFOUND)" ]; then [ "$C" ] && echo -n ${RED} 1>&2 echo 'Missing dependencies:' 1>&2 echo "$NOTFOUND" 1>&2 [ "$R" ] || [ "$S" ] || [ "$G" ] || [ "$(echo $TCZS)" ] && echo '' 1>&2 [ "$C" ] && echo -n ${NORMAL} 1>&2 fi if [ "$R" ] && [ "$(echo $TCZS)" ]; then [ "$C" ] && echo -n ${GREEN} echo ${TCZS//$KERNELVER/KERNEL} | tr ' ' '\n' | sort | sed 's:$:.tcz:g' [ "$S" ] || [ "$G" ] || [ "$(echo $TCZS)" ] && echo '' [ "$C" ] && echo -n ${NORMAL} fi if [ "$(echo $TCZS)" ]; then [ "$S" ] || [ "$G" ] && del_redundant fi exit 0