#!/bin/bash ############ ########## # apt-diag # # v.0.2b # ################################################################################ # author: (C)2009 nofun_AT_laposte_DOT_net ## bug report, suggestion, wishlist # ####################################################### are welcome ############ # GNU General Public License v.3 or later http://www.gnu.org/copyleft/gpl.html # ################################################################################ ######## homepage: http://debian-facile.org/forum/viewtopic.php?id=1285 ######## ################################################################################ # Changelog: # v.0.1 (avril 2009): # version initiale. # v.0.2 (mai 2009): # correction d'un bug dans la mise a jour du cache (f_updatecache): le cache mis # a jour avec la version precedente (0.1) a une forte probabilite de corruption. # fonctionnalite: ajout de la presentation des derniers paquets ajoutes et # supprimes depuis la derniere mise a jour du cache. # v.0.2a (mai 2009): # correction d'un bug dans la mise a jour du cache (f_updatecache): le cache mis # a jour avec la version precedente (0.2) a une probabilite de corruption. # v.0.2b (juin 2009): # correction d'un bug dans la mise a jour du cache (f_updatecache): les paquets # deja installes mais nouveaux dans une source sont maintenant ajoutes au cache # de cette source. Cette version corrige correctement le cache mis a jour avec # la version precedente (0.2a). ################################################################################ # apt-diag: pour que claires les sources demeurent # apt-diag cherche a donner une vue d'ensemble des paquets installes sur un # systeme utilisant apt (Advanced Packaging Tool du projet Debian). # Il aide en particulier a determiner de quelle source peut provenir un paquet, # indique quand c'est le cas la presence d'un meme paquet dans de multiples # sources et dresse la liste des paquets n'appartenant plus a aucune source # (ensemble des paquets obsoletes et des paquets de source inconnue). # C'est un bon complement a 'apt-cache policy nom_du_paquet'. # De plus, apt-diag maintient un cache personnel des paquets par source, ce qui # lui permet d'etablir la liste des paquets obsoletes en provenance de chaque # source, information sinon indisponible. Les sources supprimees sont egalement # archivees. Le degre d'information que fournit apt-diag est donc dependant de # la date d'initialisation du cache, ce qui veut dire que les meilleurs # resultats seront obtenus avec une initialisation du cache suivant directement # l'installation du systeme. # apt-diag n'agit pas sur le systeme de gestion des paquets, il est donc su^r # pour le systeme hote. Le seul appel au systeme de gestion des paquets est du # type 'dpkg -l' ou 'dpkg --get-selections'. De ce fait, apt-diag peut analyser # un systeme autre que le systeme hote si on lui fournit les repertoires # /var/lib/apt/lists/ et /var/lib/dpkg/ d'un syteme alternatif (a copier dans # ~/.apt-diag/_alternate) et fonctionne parfaitement en simple utilisateur. # apt-diag possede une fonctionnalite d'enregistrement des analyses dans un # fichier, ce qui permet de conserver une trace ou de communiquer l'etat du # systeme a un tiers. # Limitations: # tout diagnostic est faillible et sujet a des erreurs d'interpretation. Il # appartient a l'administrateur d'evaluer les informations fournies par apt-diag # en particulier en confrontant les resultats obtenus avec ceux que pourront lui # procurer les outils systeme a sa disposition. La licence GNU GPL sous laquelle # apt-diag est delivre n'offre aucune garantie de bon fonctionnement. # apt-diag n'a pas (encore) ete teste en presence de downgrade ou d'apt-pinning # et plus generalement demande a etre teste davantage. # apt-diag n'est pas integre au systeme de gestion des paquets, de ce fait la # mise a jour du cache n'est pas automatique lors de la mise a jour du systeme. # apt-diag evalue les paquets par leur nom, l'evaluation par numero de version # est embryonnaire et demanderait d'autres techniques de programmation. De ceci # decoule que: # - si un paquet a ete installe depuis une source par la suite supprimee et que # ce paquet apparait toujours dans une autre source avec une version inferieure, # rien de particulier n'est signale au sujet de ce paquet par apt-diag. # - si lors de l'initialisation du cache un paquet installe est obsolete mais # encore present avec une version inferieure dans une autre source, il n'est pas # analyse comme obsolete. # Merci de distribuer apt-diag avec le texte ci-dessus. # Bonne utilisation. ################################################################################ PROGNAME=$(basename $0) f_conv() { #TestCharSet: aéèêîïà¿»×x grep -m 1 "TestCharSet:" $0 > /tmp/testcharset PRGCHARSET=`file -bi /tmp/testcharset|mawk -F "charset=" '{print $2}'|tr [a-z] [A-Z]` SYSCHARSET=$(locale charmap) ! echo $SYSCHARSET|grep -q $PRGCHARSET && echo -e "\n [>] Conversion de $PROGNAME de $PRGCHARSET vers $SYSCHARSET...\c"\ && { iconv -f "$PRGCHARSET" -t "$SYSCHARSET"//TRANSLIT $0 -o /tmp/$PROGNAME && chmod +x /tmp/$PROGNAME\ && grep -m 1 "TestCharSet:" /tmp/$PROGNAME > /tmp/testcharset && PRGCHARSETR=`file -bi /tmp/testcharset|mawk -F "charset=" '{print $2}'`\ && { [ "$PRGCHARSET" = "$(echo $PRGCHARSETR|tr [a-z] [A-Z])" ] && echo " ok" || echo; } && rm -f /tmp/testcharset\ && echo -e " [*] la version $PRGCHARSETR de $PROGNAME est disponible dans /tmp/$PROGNAME\n" && exit\ || { echo -e "\a\n [!] un probleme est survenu pendant la conversion, sortie\n"; exit 1; }; } } [ -d ~/.$PROGNAME ] || { f_conv; [ -d /var/lib/apt/lists/ ] && [[ $(dpkg -l 2>/dev/null) ]]\ || { echo -e "\a\n [!] $PROGNAME n'est pas compatible avec le système hôte, sortie\n"; exit 1; }; } which bc &>/dev/null|| { echo -e "\a\n [>] $PROGNAME\n [!] Ce script nécessite bc pour fonctionner, veuillez l'installer:\n" aptitude show bc; echo -e "\n [*] aptitude -(s)v install bc\n"; exit 1; } [ "$1" = "-c" ] && ECHO=echo || CLEAR=clear ; hash grep mawk grep -q "Ratio $(uname -n):" ~/.$PROGNAME/ratio 2&>/dev/null && RATIO=`grep "Ratio $(uname -n):" ~/.$PROGNAME/ratio|cut -d " " -f3` ################################################################################ f_clearline() { [[ $1 = [br] ]] && [ -n "$3" ] && echo $2$3|grep -qx [0-9]* || return 1 while true do local COUNTER; let COUNTER++ ; echo -ne "\\$1" [ $COUNTER = $2 ] && unset -v COUNTER && break done while true do let COUNTER++ ; echo -ne " " [ $COUNTER = $3 ] && unset -v COUNTER && break done while true do let COUNTER++ ; [ $1 = r ] && COUNTER=$3 echo -ne "\\$1" ; [ $COUNTER = $3 ] && return done } f_exit() { read -s -n 1 -p " [¿] Quitter $PROGNAME ? <O/n>: " EXIT; [ "$EXIT" = n ] && f_clearline r 1 45 && return; echo; echo; exit; } f_init() { for (( s=1; s <= TSOURCES; s++ )); do unset -v RESULTF$s OBSOLETES$s; done unset -v DEL INEWS ISUPR NOPURGEP NOSOURCEDP OBSOLETES OBSOLETEST OBSOLETESTC OBSOLETESTR unset -v RESULTF RESULTFT SINGLE SOURCEDP SOURCESG SOURCESGC SOURCESN SOURCESNG TSOURCES TWIN TWINP echo CACHEDIR=~/.$PROGNAME/$MACHINE/cache ; RECFILE=~/$PROGNAME\_$MACHINE\-$(date +%Y%m%d-%H%M%S).txt [ -d $CACHEDIR ] || { mkdir -p $CACHEDIR/.old/sources/.deleted/ $CACHEDIR/sources/ echo "$MACHINE $(date "+%F %T") initialisation du cache" >> ~/.$PROGNAME/$MACHINE/history.txt; } [ -d ~/.$PROGNAME/_alternate/lists/ -a -d ~/.$PROGNAME/_alternate/dpkg/ ]\ && mv -f ~/.$PROGNAME/_alternate/lists/ ~/.$PROGNAME/_alternate/dpkg/ ~/.$PROGNAME/$MACHINE/ [ "$MACHINE" = "$(uname -n)" ] && SOURCESDIR=/var/lib/apt/lists/ INSTALLDIR=/var/lib/dpkg/\ || SOURCESDIR=~/.$PROGNAME/$MACHINE/lists/ INSTALLDIR=~/.$PROGNAME/$MACHINE/dpkg/ ## extraction de la liste des paquets installes sur le systeme INSTALLED=$(dpkg --admindir=$INSTALLDIR --get-selections |grep -w "install$" |mawk '{print $1}' |sort -d) NINSTALLED=$(echo $INSTALLED | wc -w) ## extraction et nettoyage des sources SOURCES=$(ls $SOURCESDIR |grep -vx lock |grep -vx partial) for a in _source_Sources i18n_Translation .ed$ do SOURCES=$(printf '%b\n' $SOURCES | grep -v $a) done for s in $SOURCES do grep -qm 1 "^Package: " $SOURCESDIR$s || continue SOURCESC="$SOURCESC $s" ; let TSOURCES++ done SOURCES="$SOURCESC"; unset -v SOURCESC echo " [»] Paquets installés: $INSTALLDIR Paquets disponibles: $SOURCESDIR" echo " [»] $NINSTALLED paquets installés sur $MACHINE"; echo } f_progress() { let PROGRESS++ [ $PROGRESS = $ALPHAPROGRESS ] && echo -ne "\b-" && return [ $PROGRESS = $ALPHAPROGRESS2 ] && echo -ne "\b\\" && return [ $PROGRESS = $ALPHAPROGRESS3 ] && echo -ne "\b|" && return [ $PROGRESS = $ALPHAPROGRESS4 ] && echo -ne "\b/" && PROGRESS=0 } f_adv() { trap 'break' SIGUSR1 while true do echo -ne "\b\b\b\b. "; sleep .5; echo -ne "\b\b\b\b.. "; sleep .5 echo -ne "\b\b\b\b... "; sleep .5; echo -ne "\b\b\b\b "; sleep .5 done } f_benchmachine() { local ALPHAPROGRESS ALPHAPROGRESS2 ALPHAPROGRESS3 ALPHAPROGRESS4 BURN COUNTER PROGRESS SAMPLE SAMPLEb TEMPS TEMPS1 TEMPS2 ALPHAPROGRESS=60 SAMPLE="sourceinstalled" # ! la taille du mot est importante ! ne pas modifier ! SAMPLE="sourceinstalled" ALPHAPROGRESS2=$(($ALPHAPROGRESS*2)) ALPHAPROGRESS3=$(($ALPHAPROGRESS*3)) ALPHAPROGRESS4=$(($ALPHAPROGRESS*4)) f_burn() { CLOCKD=$(date +%s%N) while true do let COUNTER++; f_progress while true do let COUNTERb++; f_progress SAMPLEb="$SAMPLEb $(echo "$SAMPLE ")" [ $COUNTERb = 100 ] && break done unset -v COUNTERb echo $SAMPLEb|grep $SAMPLE|wc -w &>/dev/null [ $COUNTER = 10 ] && break done CLOCKF=$(date +%s%N) let BURN++ } [ "$BURN" = "" ] && echo -n " [>] Benchmarking machine... " && f_burn [ "$BURN" = "1" ] && unset -v COUNTER SAMPLEb && f_burn [ "$BURN" = "2" ] && TEMPS1=$(($CLOCKF-$CLOCKD)) && unset -v COUNTER SAMPLEb && f_burn TEMPS2=$(($CLOCKF-$CLOCKD)) TEMPS=$(($TEMPS1+$TEMPS2)) RATIO=$(echo "scale=20;$TEMPS/2/$COUNTER/240000000"|bc|mawk '{printf "%0.1f\n",$1}') ## ($RATIO=1 est obtenu sur mon portable Core2Duo T7250 2GHz 2Go RAM, $RATIO>1 sur une machine plus lente) ## le resultat peut etre faux sur un portable non branche ou si une autre application prend de la ressource echo "Ratio $(uname -n): $RATIO" > ~/.$PROGNAME/ratio f_clearline r 1 35 } f_benchmark() { [ -z "$RATIO" ] && f_benchmachine; echo -n " [>] Benchmarking... "; local RESULTF PROGRESS COUNTER ## ALPHACOUNTER: determine un nombre de boucles proportionnellement inverse au nombre de paquets dans la source pondere par le ratio machine ## destine a adapter le temps de bench en prenant en compte $NPA et la vitesse de la machine PREALPHACOUNT=`echo "scale=20;1/$NPA*150000*1/(1/$NPA*(300+$NPA/2))*1.8"|bc` ALPHACOUNTER=`echo "scale=20;$PREALPHACOUNT/$RATIO"|bc|mawk '{printf "%0.0f\n",$1}'` [ `echo "scale=0; $ALPHACOUNTER<2"|bc` -eq 1 ] && ALPHACOUNTER=2 CLOCKD=$(date +%s%N) for i in $INSTALLED do let COUNTER++; f_progress RESULTF="$RESULTF $(echo "$PRERESULT"|grep -xm 1 $i)" [ $COUNTER -eq $ALPHACOUNTER ] && break done CLOCKF=$(date +%s%N) TEMPS=$(($CLOCKF-$CLOCKD)) BENCHMASS=$(($NPA*$COUNTER)) BENCH=$(echo "scale=10;$TEMPS/$BENCHMASS"|bc) f_clearline r 1 30 } f_estimate() { ESTIMATE=$(echo "scale=10;$BENCH*$COMPUTEMASS"|bc) ESTIMATEHS=$(echo "scale=0;$ESTIMATE/1000000000"|bc) ESTIMATEHSBC=$(echo "scale=3;$ESTIMATE/1000000000"|bc) mn=0 ss=$ESTIMATEHS ms=$(echo "$ESTIMATEHSBC-$ss"|bc|cut -d '.' -f2) [ $ESTIMATEHS -gt 59 ] && mn=$(($ESTIMATEHS/60)) && ss=$(($ss-$mn*60)) [ $ss -lt 10 ] && ss="0$ss" ESTIMATE=$(echo ""$mn"m"$ss"s"$ms"ms") } f_mkcache() { trap 'jobs -p f_adv &>/dev/null && kill $(jobs -p f_adv); echo -e \ "\a\n$PROGNAME > WARNING! The disk cache might be left in an inconsistent state!"; f_exit' 2 3 9 15 ## determine s'il y a des nouvelles sources a traiter: for s in $SOURCES; do [ -f $CACHEDIR/sources/$s ] && continue; SOURCESNEWS="$SOURCESNEWS $s"; let TSOURCESM++; done ## determine si des sources ont ete desactivees, dans ce cas les archive: ## NB: les depots designes par les noms de code des versions (ex. lenny) seront archives au changement de version, ## ceux utilisant la terminologie stable, testing, unstable,... seront traites par f_updatecache for s in $(ls $CACHEDIR/sources/) do printf '%b\n' $SOURCES|grep -qxm 1 $s &>/dev/null || { mv -f $CACHEDIR/sources/$s $CACHEDIR/.old/sources/.deleted/$s; DEL="$DEL $s"; } done [ -n "$DEL" ] && echo && for d in $DEL; do echo " [>] Archivage de la source supprimée $d";\ echo "$MACHINE $(date "+%F %T") source supprimée $d archivée" >> ~/.$PROGNAME/$MACHINE/history.txt; done [ -z "$TSOURCESM" -a -n "$DEL" ] && { unset -v DEL; echo; echo >> ~/.$PROGNAME/$MACHINE/history.txt read -s -n 1 -p " [-] valider pour continuer... "; f_clearline r 1 35; $CLEAR; return; }; [ -z "$TSOURCESM" ] && return echo echo " [>] Création du cache initial de paquets installés pour les nouvelles sources:"; echo time\ for a in $SOURCESNEWS do ## supprime la source du repertoire .deleted si elle a ete reactivee [ -f $CACHEDIR/.old/sources/.deleted/$a ] && rm -f $CACHEDIR/.old/sources/.deleted/$a ## ecrit dans $CACHEDIR/sources/$a les noms des paquets installes qui ont une occurrence dans $SOURCESDIR$a local TIMEFORMAT=" »»» réelle: %lR" PROGRESS CSOURCES; let CSOURCES++ echo " [»] Traitement de la source ($CSOURCES/$TSOURCESM) $a" PRERESULT=$(grep "^Package: " $SOURCESDIR$a | mawk '{print $2}') NPA=$(echo $PRERESULT | wc -w) COMPUTEMASS=$(($NPA*$NINSTALLED)) echo " [»] $NPA paquets dans la source, $NINSTALLED paquets installés sur $MACHINE" [ -z "$RATIO" ] && f_benchmachine ### ALPHAPROGRESS: alteration proportionnelle de l'indicateur de progresssion. Utilise le nombre inverse de $NPA, pondere par $RATIO PREALPHAPROG=`echo "scale=20;1/$NPA*(200+$NPA)*10"|bc` [ `echo "scale=20; $PREALPHAPROG<=11"|bc` -eq 1 ]\ && ALPHAPROGRESS=`echo "scale=20;(($PREALPHAPROG-10)*10+$PREALPHAPROG-10)/$RATIO"|bc|mawk '{printf "%0.0f\n",$1}'`\ || ALPHAPROGRESS=`echo "scale=20;$PREALPHAPROG/$RATIO"|bc|mawk '{printf "%0.0f\n",$1}'` [ `echo "scale=0; $ALPHAPROGRESS<1"|bc` -eq 1 ] && ALPHAPROGRESS=1 [ `echo "scale=0; $ALPHAPROGRESS>20"|bc` -eq 1 ] &&\ ALPHAPROGRESS=`echo "scale=20;20+(-1/$ALPHAPROGRESS+$ALPHAPROGRESS)/$NPA/1*$NPA/10"|bc|mawk '{printf "%0.0f\n",$1}'` [ `echo "scale=0; $ALPHAPROGRESS>30"|bc` -eq 1 ] && ALPHAPROGRESS=30 ALPHAPROGRESS2=$(($ALPHAPROGRESS*2)) ALPHAPROGRESS3=$(($ALPHAPROGRESS*3)) ALPHAPROGRESS4=$(($ALPHAPROGRESS*4)) f_benchmark f_estimate [ "$ESTIMATEHS" -lt 120 ] && echo -n " [»] durée estimée de traitement: $ESTIMATE "\ || echo -n " [»] durée estimée de traitement: $ESTIMATE (début $(date +%T)) " time\ for WORKAROUND in 1 do for b in $INSTALLED do f_progress RESULTF="$RESULTF $(echo "$PRERESULT"|grep -xm 1 $b)" done f_clearline b 1 1 done printf '%b\n' $RESULTF|sort -d > $CACHEDIR/sources/$a echo "$MACHINE $(date "+%F %T") nouvelle source $a ajoutée" >>~/.$PROGNAME/$MACHINE/history.txt RESULTFC=$(echo $RESULTF | wc -w) [ $RESULTFC -ne 0 ] && echo " [*] $RESULTFC occurrences" || echo " [×] pas d'occurrence" echo ; unset -v PROGRESS RESULTF [ $TSOURCESM = $CSOURCES ] && local TIMEFORMAT=" [»] durée totale de traitement: %lR" && unset -v DEL SOURCESNEWS TSOURCESM done echo >>~/.$PROGNAME/$MACHINE/history.txt; echo; echo; read -s -n 1 -p " [-] valider pour continuer... "; f_clearline r 1 35; $CLEAR } f_updatecache() { mv -f $CACHEDIR/Installed $CACHEDIR/.old/ 2>/dev/null; printf '%b\n' $INSTALLED > $CACHEDIR/Installed [ -f $CACHEDIR/.old/Installed ] || { echo; return; } echo -e " [>] Mise à jour du cache \c"; f_adv & ICHGE=$(echo $(diff -y --suppress-common-lines $CACHEDIR/.old/Installed $CACHEDIR/Installed)) echo $ICHGE|grep -q "<" && ICHGE=`echo $ICHGE|mawk '{gsub("<","");print $0}'` echo $ICHGE|grep -q ">" && ICHGE=`echo $ICHGE|mawk '{gsub(">","");print $0}'` echo $ICHGE|grep -q "|" && ICHGE=`echo $ICHGE|mawk '{gsub("\|","");print $0}'` for i in $ICHGE do grep -qx $i $CACHEDIR/Installed && INEWS="$INEWS $i" || ISUPR="$ISUPR $i" done [ -n "$INEWS" ] && printf '%b\n' $INEWS > $CACHEDIR/Linews; [ -n "$ISUPR" ] && printf '%b\n' $ISUPR > $CACHEDIR/Lisupr f_updt() { mv -f $CACHEDIR/sources/* $CACHEDIR/.old/sources/ 2>/dev/null for s in $(ls $CACHEDIR/.old/sources/) do ## supprime du cache les occurrences desinstallees for r in $ISUPR do grep -vx "$r" $CACHEDIR/.old/sources/$s > $CACHEDIR/sources/$s; cp -f $CACHEDIR/sources/$s $CACHEDIR/.old/sources/$s done PRERESULT=$(grep "^Package: " $SOURCESDIR$s | mawk '{print $2}') cp -f $CACHEDIR/.old/sources/$s $CACHEDIR/sources/$s ## ajoute au cache les nouvelles occurrences installees si elles apparaissent dans la source sauf si elles y sont deja for n in $INEWS do grep -qxm 1 "$n" $CACHEDIR/sources/$s &>/dev/null && continue echo "$PRERESULT"|grep -xm 1 "$n" >> $CACHEDIR/sources/$s done printf '%b\n' $(echo $(sort -d $CACHEDIR/sources/$s)) > $CACHEDIR/sources/$s done } [ -z "$ISUPR" -a -z "$INEWS" ] || f_updt ## ajoute au cache les occurrences anciennement installees mais nouvelles dans la source (par exemple nouvellement presentes dans security) for s in $(ls $CACHEDIR/sources/) do PRERESULT=$(grep "^Package: " $SOURCESDIR$s | mawk '{print $2}') SOCC=$(printf '%b\n' $PRERESULT $INSTALLED|sort -d|uniq -d) NEWSOCC=$(printf '%b\n' $SOCC $(cat $CACHEDIR/sources/$s)|sort -d|uniq -u) [ -n "$NEWSOCC" ] && { for o in $NEWSOCC do grep -qxm 1 "$o" $CACHEDIR/sources/$s &>/dev/null && continue echo "$o" >> $CACHEDIR/sources/$s done printf '%b\n' $(echo $(sort -d $CACHEDIR/sources/$s)) > $CACHEDIR/sources/$s; } done rm -f $CACHEDIR/.old/sources/* 2>/dev/null; kill -s SIGUSR1 $(jobs -p f_adv); f_clearline r 1 35 ## il est a noter que les paquets obsoletes (plus presents dans les sources) sont conserves dans le cache et analysables comme obsoletes } f_selectsources() { unset -v RESUME TSOURCES ## formatage des sources pour la presentation, comptage des sources, presentation for a in $SOURCES do [ "$(ls -sh $SOURCESDIR$a | mawk '{print $1}')" = "0" ]\ && SOURCESP="$SOURCESP $(ls -sh $SOURCESDIR$a | mawk '{print $1"B"}') $a"\ || SOURCESP="$SOURCESP $(ls -sh $SOURCESDIR$a | mawk '{print $1}') $a" let TSOURCES++ done echo " [>] $TSOURCES sources de paquets actuellement sélectionnées pour analyse:" echo ; unset -v TSOURCES printf ' [%b]\t» %b\n' $SOURCESP echo read -p " [¿] Sélectionner ou éliminer (préfixe «-») un motif pour filtrer, valider pour terminer: " MOTIF ## si le MOTIF est vide, SOURCESS n'est pas initialisee par la boucle d'inclusion. On l'initialise a SOURCESS=$SOURCES [ "$MOTIF" = "" ] && SOURCESS=$SOURCES until [ "$MOTIF" = "" ] do MOTIFS="$MOTIFS $MOTIF" read -p " [¿] continuer la sélection des sources à analyser, valider pour terminer: " MOTIF done ## s'il n'y a que des eliminations, SOURCESS n'est pas initialisee par la boucle d'inclusion. On l'initialise a SOURCESS=$SOURCES for m in $MOTIFS ; do MOTIFC="$(echo $m | cut -c 1) $MOTIFC" ; done MCM=$(printf '%b\n' $MOTIFC | grep -c "-") MC=$( printf '%b\n' $MOTIFC | grep -c "") [ "$MCM" = "$MC" ] && SOURCESS=$SOURCES ## boucle d'inclusion. La boucle interne permet de ne pas inclure une source deja presente (doublon) for MOTIF in $MOTIFS do MOTIFC=$(echo $MOTIF | cut -c 1) [ "$MOTIFC" != "-" ] && SELECT=$(printf '%b\n' $SOURCES | grep $MOTIF) || continue for s in $SELECT do [[ $(printf '%b\n' "$SOURCESS" | grep -w "$s") ]] && continue SOURCESS="$SOURCESS $s" done done ## boucle d'exclusion for MOTIF in $MOTIFS do MOTIFC=$(echo $MOTIF | cut -c 1) [ "$MOTIFC" = "-" ] && MOTIF=$(echo $MOTIF | cut -c 2-) && SOURCESS=$(printf '%b\n' $SOURCESS | grep -v $MOTIF) done SOURCES=$SOURCESS echo ## exclusion des fichiers qui ne sont pas des descripteurs de paquets echo " [>] Analyse des sources:" [ "$SOURCES" != "" ] && NSOURCES=$(printf '%b\n' $SOURCES | grep -c "") || NSOURCES=0 for a in $SOURCES do if ! grep -qm 1 "^Package: " $SOURCESDIR$a then [ "$(ls -sh $SOURCESDIR$a | mawk '{print $1}')" = "0" ]\ && b=$(ls -sh $SOURCESDIR$a | mawk '{print $1"B"}')\ || b=$(ls -sh $SOURCESDIR$a | mawk '{print $1}') echo " [×] non pertinente: $a [$b]" continue fi SOURCESC="$SOURCESC $a" ; let TSOURCES++ done SOURCES="$SOURCESC"; unset -v MOTIFC MOTIFS SOURCESC SOURCESP SOURCESS [ "$SOURCES" = "" ] && TSOURCES=0 [ "$TSOURCES" != "0" ]\ && SOURCES=$(printf '%b\n' $SOURCES|sort -d) SOURCES=$(echo $SOURCES)\ && echo " [»] $TSOURCES sources sur $NSOURCES à traiter dans la sélection:" && printf ' [*] [%b]\n' $SOURCES\ || echo " [»] pas de sources à traiter dans la sélection" echo while true; do let COUNT++; echo ${FUNCNAME[$COUNT]}|grep -qx main && MAIN=$COUNT && unset -v COUNT && break; done RESUME=* ; echo " [-] Aide - Accueil - Quitter <h/w/q>" while true do case "$RESUME" in q|Q) f_exit; RESUME=*;; h) less $0; RESUME=*;; w) read -s -n 1 -p " [¿] Retourner à l'accueil ? <O/n>: " RESUME; [ "$RESUME" = n ] && f_clearline r 1 40 || { $ECHO; break $MAIN; };; p) [ "$TSOURCES" != "0" ] && $CLEAR && echo && f_selectsources || RESUME=r;; l|L|"") [ "$TSOURCES" != "0" ] && break || [ "$RESUME" = "" ] && RESUME=r || RESUME=*;; r|R) $CLEAR; f_init; f_selectsources;; *) [ "$TSOURCES" != "0" ]\ && read -s -n 1 -p " [¿] Préciser encore la sélection - Recommencer - Lancer l'analyse <p/r/L>: " RESUME\ && f_clearline r 1 104 [ "$TSOURCES" = "0" ] && read -s -n 1 -p " [¿] Recommencer <R>: " RESUME && f_clearline r 1 50;; esac done } f_occm() { while true do read -s -n 1 -p " [¿] Par la suite traiter aussi les sources sans occurrences ? <o/N>: " SELECT f_clearline r 1 75 case "$SELECT" in q|Q) f_exit;; h) less $0;; w) read -s -n 1 -p " [¿] Retourner à l'accueil ? <O/n>: " RESUME; [ "$RESUME" = n ] && f_clearline r 1 40 || { $ECHO; break 2; };; o|O) OCCLESS=0; unset -v SELECT; $CLEAR; echo; break;; n|N|"") OCCLESS=1; unset -v SELECT; $CLEAR; echo; break;; esac done } f_squeezecache() { for s in $SOURCES do local CSOURCES CSOURCESM CSOURCESS ; let CSOURCES++ ; let CSOURCESS++ RESULTF=$(cat $CACHEDIR/sources/$s) RESULTFC=$(echo $RESULTF | wc -w) ## eval interprete l'item suivant dans la liste comme une commande s'il y a un espace RESULTF=`echo $RESULTF|mawk '{gsub(" ","¿");print $0}'` ## attribution d'une variable dynamique au resultat individuel - utilisation de eval ## identification par le n° de traitement $CSOURCES, attribution du contenu de RESULTF a la nouvelle variable ## la nouvelle variable recoit le nom de la source en alias, permet la concordance n°/nom [ $RESULTFC -ne 0 ] && eval RESULTF$CSOURCES="$RESULTF" && eval alias RESULTF$CSOURCES=$s\ && echo -e " [*] $RESULTFC occurrences\t$s" [ $RESULTFC -eq 0 -a $OCCLESS -eq 0 ] && eval RESULTF$CSOURCES="$RESULTF" && eval alias RESULTF$CSOURCES=$s\ && echo -e " [×] pas d'occurrence\t$s" && let CSOURCESM++ [ $RESULTFC -eq 0 -a $OCCLESS -eq 1 ] && let CSOURCES-- && echo -e " [×] pas d'occurrence\t$s" unset -v RESULTF done echo ; TSOURCES=$CSOURCES ; [ -z $CSOURCESM ] && CSOURCESM=0 echo " [»] $(($CSOURCES - $CSOURCESM)) sources sur $CSOURCESS présentent des occurrences de paquets installés sur $MACHINE" echo ; unset -v CSOURCESM CSOURCESS CSOURCES ## concatenation des resultats individuels - utilisation de la substitution de variable {!RESULTF} for (( n=1; n <= TSOURCES; n++ )) do RESULTF=RESULTF$n ## RESULTF se substitue a la variable dynamique dont le contenu est appele par {!RESULTF} RESULTFP=`echo ${!RESULTF}|mawk '{gsub("¿"," ");print $0}'` ; RESULTFP=$(echo $RESULTFP) RESULTFT="$RESULTFT $RESULTFP" ## concatenation, doublons compris elimines par sort -u par la suite SOURCESN="$SOURCESN $n" ## extrait les numeros des sources disponibles de 1 a n sources done SOURCESN=$(echo $SOURCESN) SOURCESNP=`echo $SOURCESN|mawk '{gsub(" ","\&|");print $0}'` RESULTFTS=$(printf '%b\n' $RESULTFT | sort -d) RESULTFTU=$(echo $(printf '%b\n' $RESULTFT | sort -u)) RESULTFTC=$(echo $RESULTFT|wc -w) RESULTFTUC=$(echo $RESULTFTU|wc -w) RESULTFTCC=$(($RESULTFTC-$RESULTFTUC)) UNKNOWNS=$(printf '%b\n' $INSTALLED $RESULTFTU|sort -d|uniq -u) UNKNOWNC=$(echo $UNKNOWNS|wc -w) NOPURGE=`dpkg --admindir=$INSTALLDIR -l|grep "^rc "|mawk '{print $2}'` NOPURGEC=$(echo $NOPURGE|wc -w) LINEWSC=$(cat $CACHEDIR/Linews 2>/dev/null|wc -w); LISUPRC=$(cat $CACHEDIR/Lisupr 2>/dev/null|wc -w) LINEWS=$(printf ' [%b]' $(cat $CACHEDIR/Linews 2>/dev/null)) LISUPR=$(printf ' [%b]' $(cat $CACHEDIR/Lisupr 2>/dev/null)) echo echo " [*] paquets installés sur $MACHINE: $NINSTALLED" echo " [*] occurrences installées sur $MACHINE: $RESULTFTUC" echo " [*] paquets installés non analysés: $(($NINSTALLED-$RESULTFTUC))" echo " [*] croisements d'occurrences: $RESULTFTCC" echo " [*] occurrences totales: $RESULTFTC" echo } f_postproc() { f_fmt() { fmt -w $(tput cols); } f_tee() { [ $RECORD = 1 ] && tee -a $RECFILE || tee; } f_less() { [ $LESS = 1 ] && less -m~ || tee; } f_pager() { read -s -n 1 -p " [¿] afficher les occurrences avec Less - directement - ne pas afficher <L/d/n>: " PAGER f_clearline r 1 80 ; [ "$PAGER" = "d" -o "$PAGER" = "n" ] || PAGER=L ; PAGERM="\c" [ "$PAGER" = L ] && LESS=1 PAGERM=" [affichage dans le pager]" || LESS=0; [ "$PAGER" = n ] && PAGERM=" -------------------------" } f_dores() { for S in $S do RESULTF=RESULTF$S RESULTFALIAS=$(eval alias RESULTF$S | cut -d "'" -f2) ; [ "$1" = "-a" ] && return RESULTF=`echo ${!RESULTF}|mawk '{gsub("¿"," ");print $0}'` ; RESULTF=$(echo $RESULTF) RESULTFC=$(echo $RESULTF|wc -w) ; [ "$1" = "-r" ] && return OBSOLETES=OBSOLETES$S; OBSOLETES=`echo ${!OBSOLETES}|mawk '{gsub("¿"," ");print $0}'` OBSOLETES=$(echo $OBSOLETES); OBSOLETESC=$(echo $OBSOLETES|wc -w) done } f_obs() { [ -n "$OBSOLETESTC" ] && return echo -n " [»] traitement "; trap 'kill $(jobs -p f_adv); echo; exit' 2 3 9 15; f_adv & for S in $SOURCESN do f_dores -r; unset -v OBSOLETES for p in $RESULTF do grep -qxm 1 "Package: $p" $SOURCESDIR$RESULTFALIAS\ || OBSOLETES="$OBSOLETES¿$p" OBSOLETEST="$OBSOLETEST $p" done eval OBSOLETES$S="$OBSOLETES" done OBSOLETEST=$(printf '%b\n' $OBSOLETEST|sort -u) OBSOLETESTC=$(echo $OBSOLETEST|wc -w) for o in $OBSOLETEST do unset -v COUNTER NOBS for S in $SOURCESN do f_dores -r let COUNTER++; [ $COUNTER -eq 1 ]\ && LOCI=$(grep -xnm 1 "Package: $o" $INSTALLDIR/status|cut -d: -f1) LOCIF=$(($LOCI+15))\ && VERI=`mawk 'NR==LOCI,NR==LOCIF {print $0}' LOCI=$LOCI LOCIF=$LOCIF $INSTALLDIR/status|grep -m 1 "^Version: "`\ && OBSOLETESTR="$OBSOLETESTR $o" LOC=$(grep -xnm 1 "Package: $o" $SOURCESDIR$RESULTFALIAS); [ -z "$LOC" ] && continue LOC=$(echo $LOC|cut -d: -f1) LOCF=$(($LOC+15)) VER=`mawk 'NR==LOC,NR==LOCF {print $0}' LOC=$LOC LOCF=$LOCF $SOURCESDIR$RESULTFALIAS|grep -m 1 "^Version: "` [ "$VERI" = "$VER" ] && NOBS=1 done [ -n "$NOBS" ] && OBSOLETESTR=$(printf '%b\n' $OBSOLETESTR|grep -vx $o) done OBSOLETESTRC=$(echo $OBSOLETESTR|wc -w); unset -v COUNTER; kill -s SIGUSR1 $(jobs -p f_adv); trap 2 3 9 15; f_clearline r 1 22 } f_twin() { [ -n "$TWIN" -o -n "$SINGLE" ] && return echo -n " [»] traitement "; trap 'kill $(jobs -p f_adv); echo; exit' 2 3 9 15; f_adv & for u in $RESULTFTU do unset -v COUNTER for s in $RESULTFTS do [[ "$u" != "$s" ]] && continue let COUNTER++ done [[ "$COUNTER" < 2 ]] && SINGLE="$SINGLE $u" && continue TWIN="$TWIN $u" TWINP="$TWINP $COUNTER"¿"$u" done TWINC=$(echo $TWIN|wc -w) SINGLEC=$(echo $SINGLE|wc -w) TWINP=`printf ' %b\n' $TWINP|sort -d|mawk '{gsub("¿","× ");print $0}'` SINGLEP=$(printf ' [%b]' $SINGLE) ; TWIND=$(printf '%b\n' $TWIN) unset -v COUNTER; kill -s SIGUSR1 $(jobs -p f_adv); trap 2 3 9 15; f_clearline r 1 22 } f_displayg() { { echo; echo " [>] [$MACHINE] Occurrences globales:"; }|f_tee [ "$SOURCESG" = "" ] &&\ for S in $SOURCESN;do f_dores -r;[ $RESULTFC -ne 0 ] && SOURCESG="$SOURCESG $RESULTFALIAS" && SOURCESNG="$SOURCESNG $S" && let SOURCESGC++ done [ "$SOURCESG" = "" ] && { echo " [×] Aucune des sources analysées n'a d'occurrence installée sur $MACHINE"; echo -e "\n\n"; }|f_tee && return { echo " [»] $SOURCESGC sources analysées ont des occurrences installées sur $MACHINE:"; echo; }|f_tee for S in $SOURCESNG; do f_dores -r; echo " [$S] $RESULTFALIAS [$RESULTFC occurrences]"|f_tee; TTLOCC=$(($TTLOCC+$RESULTFC)); done f_obs NOSOURCEDC=$(($OBSOLETESTRC+$UNKNOWNC)) SOURCEDC=$(($RESULTFTUC-$OBSOLETESTRC)) { echo " [*] total: $TTLOCC occurrences"; echo; echo " [*] $NINSTALLED paquets installés sur $MACHINE" echo " [*] $NOSOURCEDC paquets installés non présents dans les sources analysées" echo " [*] dont $OBSOLETESTRC paquets obsolètes et $UNKNOWNC paquets d'origine inconnue" echo " [*] $SOURCEDC paquets installés présents dans les sources analysées:"; echo; }|f_tee ; unset -v TTLOCC f_pager [ "$SOURCEDP" = "" ] && SOURCEDP=$(printf ' [%b]' $(printf '%b\n' $OBSOLETESTR $RESULTFTU|sort -d|uniq -u)) [ "$NOSOURCEDP" = "" ] && NOSOURCEDP=$(printf ' [%b]' $(printf '%b\n' $OBSOLETESTR $UNKNOWNS|sort -d)) [ "$NOPURGEP" = "" ] && NOPURGEP=$(printf ' [%b]' $NOPURGE) [ $PAGER = L ] && { printf '\n%b\n' " [*] $SOURCEDC paquets installés présents dans les sources analysées:" "$SOURCEDP"|f_fmt [ $NOSOURCEDC -gt 0 ] && printf '\n%b\n' " [*] $NOSOURCEDC paquets installés non présents dans les sources analysées:" "$NOSOURCEDP"|f_fmt [ $LINEWSC -gt 0 ] && printf '\n%b\n' \ " [*] $LINEWSC derniers paquets installés (information mise à jour le $(date -r $CACHEDIR/Linews|cut -d'(' -f1)\b):" "$LINEWS"|f_fmt [ $LISUPRC -gt 0 ] && printf '\n%b\n' \ " [*] $LISUPRC derniers paquets supprimés (information mise à jour le $(date -r $CACHEDIR/Lisupr|cut -d'(' -f1)\b):" "$LISUPR"|f_fmt [ $NOPURGEC -gt 0 ] && printf '\n%b\n' " [*] $NOPURGEC paquets supprimés de $MACHINE mais non purgés:" "$NOPURGEP"|f_fmt; }|f_tee |f_less [ $PAGER = d ] && { echo "$SOURCEDP"|f_fmt; [ $NOSOURCEDC -gt 0 ] &&\ printf '\n%b\n' " [*] $NOSOURCEDC paquets installés non présents dans les sources analysées:" "$NOSOURCEDP"|f_fmt [ $LINEWSC -gt 0 ] && printf '\n%b\n' \ " [*] $LINEWSC derniers paquets installés (information mise à jour le $(date -r $CACHEDIR/Linews|cut -d'(' -f1)\b):" "$LINEWS"|f_fmt [ $LISUPRC -gt 0 ] && printf '\n%b\n' \ " [*] $LISUPRC derniers paquets supprimés (information mise à jour le $(date -r $CACHEDIR/Lisupr|cut -d'(' -f1)\b):" "$LISUPR"|f_fmt [ $NOPURGEC -gt 0 ] && printf '\n%b\n' " [*] $NOPURGEC paquets supprimés de $MACHINE mais non purgés:" "$NOPURGEP"|f_fmt; } |f_tee [ $PAGER = n ] && echo -e "$PAGERM"|f_tee || echo -e "$PAGERM"; { echo ; echo; }|f_tee [ $TSOURCES -eq 1 ] && { [ $RECORD = 1 ] && echo -e " [-] la séquence a été enregistrée dans $RECFILE\n\n" || echo; } && return f_twin [ $TWINC -eq 0 ] && { echo " [×] aucun croisement d'occurrence de paquets installés sur $MACHINE entre les sources analysées" echo -e "\n\n"; }|f_tee && return { echo " [*] $SINGLEC occurrences uniques";echo " [*] $RESULTFTCC croisements d'occurrences";echo " [*] $TWINC occurrences croisées:"; }|f_tee f_pager [ $PAGER = L ] && { printf '\n%b\n%b\n\n%b' " [*] $RESULTFTCC croisements d'occurrences" " [*] $TWINC occurrences croisées:" "$TWINP" printf '\n\n\n%b\n\n%b' " [*] $SINGLEC occurrences uniques:" "$SINGLEP"|f_fmt; }|f_tee |f_less && echo -e "\n$PAGERM" [ $PAGER = d ] && { echo -e "\n$TWINP";echo -e "\n";echo -e " [*] $SINGLEC occurrences uniques:\n";echo "$SINGLEP"|f_fmt; }|f_tee [ $PAGER = n ] && echo -e "\n$PAGERM"|f_tee [ $RECORD = 1 ] && echo -e "\n\n [-] la séquence a été enregistrée dans $RECFILE\n\n" || echo -e "\n\n" } f_display() { { echo; echo " [>] [$MACHINE] Occurrences par sources:"; echo; }|f_tee { for (( S=1; S <= $TSOURCES; S++ )); do f_dores -r; echo $SELECTS|grep -w $S &>/dev/null [ $? -eq 0 ] && echo " [$S] $RESULTFALIAS [$RESULTFC occurrences]" || echo " [×]";done; }|f_tee f_pager [ $PAGER != n ] && f_obs &&\ for S in $SELECTS do f_dores echo -e "\n [*] $RESULTFC occurrences installées présentes dans le cache de la source [$RESULTFALIAS]:" [ $RESULTFC -ne 0 ] && echo && printf ' [%b]' $RESULTF|f_fmt; echo [ $OBSOLETESC -ne 0 ] && echo " [*] dont $OBSOLETESC occurrences obsolètes:" && printf ' [%b]' $OBSOLETES|f_fmt && echo done |f_tee|f_less ; echo|f_tee [ $PAGER = n ] && echo -e "$PAGERM\n"|f_tee || echo -e "$PAGERM\n"; echo|f_tee { printf " [»] occurrences uniques et croisées des sources"; printf ' [%b]' $SELECTS; echo ":"; }|f_tee f_pager f_sort() { f_twin for S in $SELECTS do f_dores -r for r in $RESULTF do echo "$TWIND"|grep -qxm 1 "$r" &>/dev/null && MULTIX="$MULTIX $r" && continue UNIX="$UNIX $r" done UNIXC=$(echo $UNIX|wc -w) MULTIXC=$(echo $MULTIX|wc -w) echo -e "\n [$S] $RESULTFALIAS [$(($UNIXC+$MULTIXC)) occurrences]" ; echo [ $UNIXC -ne 0 ] && echo " [*] $UNIXC occurrences uniques:" && printf ' [%b]' $UNIX|f_fmt && echo [ $MULTIXC -ne 0 ] && echo " [*] $MULTIXC occurrences croisées:" && printf ' [%b]' $MULTIX|f_fmt && echo unset -v UNIX MULTIX done |f_tee |f_less ; echo -e "\n$PAGERM\n\n" [ $RECORD = 1 ] && echo -e " [-] la séquence a été enregistrée dans $RECFILE\n\n" || echo } [ $PAGER != n ] && f_sort || echo -e "\n$PAGERM\n\n\n"|f_tee } f_displaym() { echo; echo " [>] [$MACHINE] Occurrences par sources:"; echo for ((S=1;S<=TSOURCES;S++)); do f_dores -r; echo " [$S] $RESULTFALIAS [$RESULTFC occurrences]"; done; echo while true do read -p " [¿] afficher les occurrences pour $SOURCESNP (défaut &) <$SOURCESN>: " SELECTS case "$SELECTS" in q|Q) f_exit;; h) less $0;; "") SELECTS=$SOURCESN ; $CLEAR ; f_display ; break;; *) SELECTS=$(printf '%b\n' $SELECTS|sort -u) doit=1 for s in $SELECTS; do echo $SOURCESN|grep -w $s &>/dev/null; [ $? -ne 0 ] && doit=0; done [ $doit -ne 0 ] && $CLEAR && f_display && break;; esac done } f_package() { { echo -e "\n [>] [$MACHINE] Analyse par paquets:\n"; echo " [»] analyse des occurrences croisées entre les sources analysées:"; }|f_tee f_twin f_x() { { echo " [*] $RESULTFTCC croisements d'occurrences" echo " [*] $TWINC occurrences croisées:"; echo; }|f_tee f_pager [ $PAGER = n ] && echo -e "$PAGERM\n"|f_tee && return for x in $TWIN do [ -z "$COUNT" -a $PAGER = L ] && printf '%b\n%b\n\n'\ " [*] $RESULTFTCC croisements d'occurrences" " [*] $TWINC occurrences croisées:" let COUNT++; echo " [$COUNT] [$x]"; unset -v COUNTER for S in $SOURCESN do f_dores -r; let COUNTER++ [ $COUNTER -eq 1 ]\ && LOCI=$(grep -xnm 1 "Package: $x" $INSTALLDIR/status|cut -d: -f1) LOCIF=$(($LOCI+15))\ && VERI=`mawk 'NR==LOCI,NR==LOCIF {print $0}' LOCI=$LOCI LOCIF=$LOCIF $INSTALLDIR/status|grep -m 1 "^Version: "`\ && STATI=`mawk 'NR==LOCI,NR==LOCIF {print $0}' LOCI=$LOCI LOCIF=$LOCIF $INSTALLDIR/status|grep -m 1 "^Status: "`\ && echo -e " $VERI $STATI"\ && for d in $(ls $CACHEDIR/.old/sources/.deleted/) do grep -qxm 1 "$x" $CACHEDIR/.old/sources/.deleted/$d && echo " présent dans la source supprimée $d"; done LOC=$(grep -xnm 1 "Package: $x" $SOURCESDIR$RESULTFALIAS) [ -z "$LOC" ] && { printf '%b\n' $RESULTF|grep -qxm 1 $x && echo " obsolète dans $RESULTFALIAS"; true; } && continue LOC=$(echo $LOC|cut -d: -f1) LOCF=$(($LOC+15)) VER=`mawk 'NR==LOC,NR==LOCF {print $0}' LOC=$LOC LOCF=$LOCF $SOURCESDIR$RESULTFALIAS|grep -m 1 "^Version: "` printf ' %b %b\n' "$VER" "dans $RESULTFALIAS" done echo done |f_tee |f_less ; unset -v COUNT COUNTER; echo -e "$PAGERM\n" } [ $TWINC -eq 0 ]&&echo -e " [×] aucun croisement d'occurrences de paquets installés sur $MACHINE entre les sources analysées\n"|f_tee||f_x echo -e "\n\n [»] analyse des paquets installés non présents dans les sources analysées:"|f_tee f_u() { echo " [*] $UNKNOWNC paquets installés non présents dans les sources analysées:"|f_tee f_pager; [ $PAGER = n ] && echo -e "\n$PAGERM\n"|f_tee && return { COUNT=0 TUNKNOWNS=$UNKNOWNS; [ $PAGER = L ] && echo " [*] $UNKNOWNC paquets installés non présents dans les sources analysées:" for u in $UNKNOWNS do unset -v COUNTER for d in $(ls $CACHEDIR/.old/sources/.deleted/) do grep -qxm 1 "$u" $CACHEDIR/.old/sources/.deleted/$d && { TUNKNOWNS=$(printf '%b\n' $TUNKNOWNS|grep -vx $u); let COUNTER++ [ $COUNTER -eq 1 ] && { let COUNT++; echo -e "\n [$COUNT] [$u]"; }; echo " origine possible: source supprimée [$d]"; } done done [ $COUNT -gt 0 -a $COUNT -lt $UNKNOWNC ] && { echo -e \ "\n [×] les données dont dispose $PROGNAME sont trop récentes pour déterminer l'origine des $(($UNKNOWNC-$COUNT)) autres paquets:" printf ' [%b]' $TUNKNOWNS|f_fmt; }\ || { [ $COUNT -eq 0 ]&&echo " [×] les données dont dispose $PROGNAME sont trop récentes pour déterminer l'origine des $UNKNOWNC paquets:" printf ' [%b]' $TUNKNOWNS|f_fmt; }; }|f_tee |f_less; unset -v COUNT COUNTER; echo -e "\n$PAGERM\n" } [ $UNKNOWNC -eq 0 ] && echo -e " [×] aucun paquet d'origine inconnue installé sur $MACHINE\n"|f_tee || f_u echo -e "\n\n [»] analyse des occurrences obsolètes dans le cache des sources analysées:"|f_tee f_obs f_o() { echo " [*] $OBSOLETESTC occurrences obsolètes:"|f_tee f_pager; [ $PAGER = n ] && echo -e "\n$PAGERM\n"|f_tee && return { OBS=$OBSOLETESTC; echo; [ $PAGER = L ] && { echo " [*] $OBSOLETESTC occurrences obsolètes:"; echo; } for o in $OBSOLETEST do let COUNT++; unset -v COUNTER NOBS for S in $SOURCESN do f_dores -r let COUNTER++; [ $COUNTER -eq 1 ] && echo " [$COUNT] [$o]"\ && LOCI=$(grep -xnm 1 "Package: $o" $INSTALLDIR/status|cut -d: -f1) LOCIF=$(($LOCI+15))\ && VERI=`mawk 'NR==LOCI,NR==LOCIF {print $0}' LOCI=$LOCI LOCIF=$LOCIF $INSTALLDIR/status|grep -m 1 "^Version: "`\ && STATI=`mawk 'NR==LOCI,NR==LOCIF {print $0}' LOCI=$LOCI LOCIF=$LOCIF $INSTALLDIR/status|grep -m 1 "^Status: "`\ && echo " $VERI $STATI" && OBSR="$OBSR $o" LOC=$(grep -xnm 1 "Package: $o" $SOURCESDIR$RESULTFALIAS) [ -z "$LOC" ] && { printf '%b\n' $RESULTF|grep -qxm 1 $o && echo " obsolète dans $RESULTFALIAS"; true; }\ && continue LOC=$(echo $LOC|cut -d: -f1) LOCF=$(($LOC+15)) VER=`mawk 'NR==LOC,NR==LOCF {print $0}' LOC=$LOC LOCF=$LOCF $SOURCESDIR$RESULTFALIAS|grep -m 1 "^Version: "` printf ' %b %b\n' "$VER" "dans $RESULTFALIAS" ; [ "$VERI" = "$VER" ] && NOBS=1 done [ -n "$NOBS" ] && { echo " [¡] la version installée de $o n'est PAS obsolète"; let OBS--; OBSR=$(printf '%b\n' $OBSR|grep -vx $o); } echo done [ $OBS -eq 0 ] && echo " [×] aucun des paquets installés sur $MACHINE n'est obsolète"\ || { echo -e "\n [*] $OBS paquets installés sur $MACHINE sont obsolètes:"; printf ' [%b]' $OBSR|f_fmt; echo; } [ $UNKNOWNC -ne 0 ]\ && echo " [¡] il est possible que les $UNKNOWNC paquets non présents dans les sources analysées soient obsolètes" } |f_tee |f_less; unset -v COUNT COUNTER; echo -e "\n$PAGERM\n" } [ $OBSOLETESTC -eq 0 ] && { echo " [×] aucune occurrence obsolète de paquets installés sur $MACHINE dans les sources analysées" [ $UNKNOWNC -ne 0 ] &&\ echo -e " [¡] il est possible que les $UNKNOWNC paquets non présents dans les sources analysées soient obsolètes\n\n"; } |f_tee || f_o [ $RECORD = 1 ] && echo -e "\n [-] la séquence a été enregistrée dans $RECFILE\n\n" || echo -e "\n\n" } echo [ $TSOURCES -eq 0 -a $OCCLESS -eq 1 ]\ && echo " [>] Aucune des sources traitées ne présente d'occurrence en concordance avec les paquets installés sur $MACHINE"\ && echo " [»] aucune analyse à effectuer" && echo && read -s -n 1 -p " [-] valider pour continuer... " && f_clearline r 1 35 && return 2 echo " __________________________________________________________________________" echo " [-] Enregistrer la prochaine séquence - Aide - Accueil - Quitter <r/h/w/q>" ; RECORD=0 REC="" while true do read -s -n 1 -p " [¿]$REC [$MACHINE]: Analyse globale - Par sources - Par paquets <g/s/p>: " SELECT f_clearline r 1 110 case "$SELECT" in q|Q) f_exit;; h) less $0;; w) read -s -n 1 -p " [¿] Retourner à l'accueil ? <O/n>: " RESUME; [ "$RESUME" = n ] && f_clearline r 1 40 || { $ECHO; return; };; r) REC=" [R]" RECORD=1;echo -e "\n\n $(date)" >>$RECFILE;; g) $CLEAR; f_displayg;break;; s) $CLEAR; f_displaym;break;; p) $CLEAR; f_package;break;; esac done f_postproc } f_home() { [ -d ~/.$PROGNAME/$(uname -n) ] || { $CLEAR; echo -e "\n [>] Initialisation de $PROGNAME\n"; MACHINE=$(uname -n) f_init; f_mkcache; f_updatecache; trap 2 3 9 15; return; } [ -d ~/.$PROGNAME/_alternate ] || { mkdir -p ~/.$PROGNAME/_alternate/ echo "Copiez ici les répertoires /var/lib/apt/lists/ et /var/lib/dpkg/ d'un système alternatif que vous souhaitez analyser"\ > ~/.$PROGNAME/_alternate/readme.txt; } $CLEAR; echo -e "\n\n\n\n\n\n" for w in Advanced Packaging Tool DIAGnostic do NL=$(echo ${#w}) NLA=$NL; echo -n " " for ((l=1;l<=NL;l++)) do L=$(echo $w|cut -c $l); echo $L|grep -q [A-Z] && L="\033[1m$L\033[0m" for ((la=NLA;la>=0;la--)) do for ((s=la;s>=1;s--)); do SPACE="$SPACE "; done echo -ne "$SPACE$L "; NSPACE=$(echo ${#SPACE}) unset -v SPACE; sleep 0.01; [ $NSPACE -eq 0 ] && break for ((b=1;b<=NSPACE+2;b++)); do echo -ne "\b"; done done NLA=$(($NLA-1)) let INTER++; for ((s=2;s<=INTER/2;s++)); do echo -n " "; done done echo; unset -v INTER done echo -e "\n\n\n\n\n\n\n\n\n\n\n\n\n\n [>] $PROGNAME"; echo [ -d ~/.$PROGNAME/_alternate/lists/ -a -d ~/.$PROGNAME/_alternate/dpkg/ ] && { echo " [»] un système alternatif a été détecté" [ -w ~/.$PROGNAME/_alternate/lists/ -a -w ~/.$PROGNAME/_alternate/dpkg/ ]\ || { echo -e "\a\n [!] la configuration alternative n'a pas les droits en écriture, sortie\n"; exit 1; } [[ $(ADM=~; dpkg --admindir=$ADM/.$PROGNAME/_alternate/dpkg/ -l 2>/dev/null) ]]\ || { echo -e "\a\n [!] le répertoire ~/.$PROGNAME/_alternate/dpkg/ n'est pas une configuration valide pour dpkg, sortie\n"; exit 1; } read -p " [¿] nom du système: " MACHINE; f_clearline r 1 100 MACHINE=$(echo $MACHINE|tr -d ".%$&|<>*\'\"# /\\" 2>/dev/null|tr "[A-Z]" "[a-z]"|sed 's/^-//') [ $(echo ${#MACHINE}) -gt 35 ] && echo " [!] $MACHINE: ce nom est déraisonnablement long..." && sleep 3 && f_clearline r 1 120 && return [ -d ~/.$PROGNAME/$MACHINE ] && echo " [!] $MACHINE: ce nom de système est déjà utilisé..." && sleep 3 && f_clearline r 1 100 && return read -s -n 1 -p " [¿] ce nom est-il correct: $MACHINE ? <O/n>: " RESUME; [ "$RESUME" = n ] && f_clearline r 1 100 && return $CLEAR; echo -e "\n [>] Initialisation du cache pour $MACHINE\n"; f_init; f_mkcache; f_updatecache; trap 2 3 9 15; return; } echo " [»] systèmes analysables:" echo " [1] $(uname -n)"; COUNTER=1 MACHINES=1 MACHINESP=1; unset -v MACHINESUP MACHINESUPP for m in $(ls ~/.$PROGNAME/) do [ "$m" = "$(uname -n)" -o "$m" = "_alternate" ] && continue; [ -d ~/.$PROGNAME/$m ] || continue let COUNTER++; alias $COUNTER=$m; MACHINES="$MACHINES $COUNTER" MACHINESP="$MACHINESP/$COUNTER" MACHINESUP="$MACHINESUP $COUNTER" MACHINESUPP="$MACHINESUPP/$COUNTER"; echo " [$COUNTER] $m" done echo; unset -v COUNTER; echo " [-] Aide - Accueil - Quitter <h/w/q>" [ -n "$MACHINESUP" ] && MACHINESUPP=$(echo $MACHINESUPP|sed 's/^\///') &&\ while true do read -s -n 1 -p " [¿] Sélectionner un système - Supprimer un système (défaut 1) <$MACHINESP/->: " SELECT f_clearline r 1 100 case "$SELECT" in q|Q) f_exit;; h) less $0;; w) read -s -n 1 -p " [¿] Recommencer ? <O/n>: " RESUME; [ "$RESUME" = n ] && f_clearline r 1 30 || { $ECHO; return; };; -) read -s -n 1 -p " [¿] sélectionner un système pour SUPPRESSION <$MACHINESUPP>: " SELECTM; f_clearline r 1 100 echo $MACHINESUP|grep -w $SELECTM &>/dev/null\ && { read -s -n 1 -p " [¿] supprimer $(alias $SELECTM|cut -d "'" -f2) de $PROGNAME ? <o/N>: " DEL; f_clearline r 1 100 [ "$DEL" = o ] && rm -fr ~/.$PROGNAME/$(alias $SELECTM|cut -d "'" -f2); unset -v DEL; return; };; ""|1) MACHINE=$(uname -n); break;; *) echo $MACHINES|grep -w $SELECT &>/dev/null && MACHINE=$(alias $SELECT|cut -d "'" -f2) && break;; esac done || MACHINE=$(uname -n); for m in $MACHINESUP; do unalias $m &>/dev/null; done while true do read -s -n 1 -p " [¿] [$MACHINE]: travailler sur l'ensemble des sources ? <O/n>: " SELECT f_clearline r 1 100 case "$SELECT" in q|Q) f_exit;; h) less $0;; w) read -s -n 1 -p " [¿] Recommencer ? <O/n>: " RESUME; [ "$RESUME" = n ] && f_clearline r 1 30 || { $ECHO; return; };; o|O|"") $CLEAR; f_init; f_mkcache; f_updatecache; trap 2 3 9 15; OCCLESS=1; f_squeezecache; f_postproc; break;; n) $CLEAR; f_init; f_mkcache; f_updatecache; trap 2 3 9 15; f_selectsources; f_occm; f_squeezecache; f_postproc; break;; esac done } while true; do f_home; done