Extraire fichier image ISO

Vous ne pouvez pas être root, vous avez un compte sur une machine éloignée mais avec une bande passante de la mort qui tue et vous avez besoin de mettre un fichier extrait d’une image ISO présente sur cette machine. Par exemple un le fichier agreg/agreg de ClefOffi-6.6.iso.

  • La méthode classqiue via loop: Vous vous dites facile, je rapatrie le fichier, je monte le bazar en loop, et je récupère le fichier et je le renvoie. Ah mais zut, vous avez un débit montant de 4K/s et le fichier fait 700M. Bon, c’est rapé. Et pas question de le faire là bas, vous n’êtes pas root.

  • Vous réfléchissez et vous vous dites que ISO est un format débile et primaire. Un epu de renseignenemnt et hop, la soluton s’impose: Le paquet isoutils contient isoinfo. Vous le rapatriez là bas et là vous tapez

parmi les lignes vous repérez

[quote]---------- 0 0 0 726237184 Apr 25 2011 [ 2776 00] AGREG.;1
[/quote]C’est votre fichier, là vous notez 726237184 (la taille) et 2776 (l’offset.
Vous tapez alors

en ayant noté que 354609 = (726237184/2048) + 1
Là vous obtenez le fichier /tmp/agreg qui est le fichier voulu.

La méthode peut être utilisé pour récupérer des fichiers d’une iso disponible sur Internet lorsqu’on a une faible bande passante et qu’on ne veut pas charger tout le CD ou DVD. Par exemple, on voudrait un paquet du DVD2 de la squeeze (microcode.ctl_1.17-13_i386.deb). Et on ne l’a pas trouvé sur le dépot. Ce DVD a comme adresse cdimage.debian.org/debian-cd/6.0 … -DVD-2.iso

Bon, on charge le début de DVD de manière à avoir le fichier dans le morceau de répertoire chargé:

[code]francois@totoche:/tmp/demo$ curl -L -r 0-2000000 http://cdimage.debian.org/debian-cd/6.0.1ai386/iso-dvd/debian-6.0.1a-i386-DVD-2.iso > tt.iso
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 1953k 100 1953k 0 0 652k 0 0:00:02 0:00:02 --:–:-- 844k
francois@totoche:/tmp/demo$ isoinfo -l -R -i tt.iso | grep micro
lr-xr-xr-x 1 0 0 0 Mar 22 2011 [ 4316 00] microcode.ctl_1.17-13_i386.deb -> …/pool/contrib/m/microcode.ctl/microcode.ctl_1.17-13_i386.deb
dr-xr-xr-x 1 0 0 2048 Mar 22 2011 [ 50 02] microcode.ctl
isoinfo: Short read on old image

[damned: RATÉ]

francois@totoche:/tmp/demo$ curl -L -r 0-4000000 http://cdimage.debian.org/debian-cd/6.0.1a/i386/iso-dvd/debian-6.0.1a-i386-DVD-2.iso > tt.iso
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 3906k 100 3906k 0 0 844k 0 0:00:04 0:00:04 --:–:-- 901k
francois@totoche:/tmp/demo$ isoinfo -l -R -i tt.iso | grep microlr-xr-xr-x 1 0 0 0 Mar 22 2011 [ 4316 00] microcode.ctl_1.17-13_i386.deb -> …/pool/contrib/m/microcode.ctl/microcode.ctl_1.17-13_i386.deb
dr-xr-xr-x 1 0 0 2048 Mar 22 2011 [ 50 02] microcode.ctl
dr-xr-xr-x 1 0 0 2048 Mar 22 2011 [ 1094 02] libmicrohttpd
isoinfo: Short read on old image

[damned: encore RATÉ]
[/code]
Jusqu’à présent c’est décevant mais on chargeant 8M:

francois@totoche:/tmp/demo$ curl -L -r 0-8000000 http://cdimage.debian.org/debian-cd/6.0.1a/i386/iso-dvd/debian-6.0.1a-i386-DVD-2.iso > tt.iso % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 7812k 100 7812k 0 0 591k 0 0:00:13 0:00:13 --:--:-- 747k francois@totoche:/tmp/demo$ isoinfo -l -R -i tt.iso | grep microlr-xr-xr-x 1 0 0 0 Mar 22 2011 [ 4316 00] microcode.ctl_1.17-13_i386.deb -> ../pool/contrib/m/microcode.ctl/microcode.ctl_1.17-13_i386.deb dr-xr-xr-x 1 0 0 2048 Mar 22 2011 [ 50 02] microcode.ctl dr-xr-xr-x 1 0 0 2048 Mar 22 2011 [ 1094 02] libmicrohttpd Directory listing of /pool/contrib/m/microcode.ctl/ -r--r--r-- 1 0 0 23230 Mar 22 2011 [1066829 00] microcode.ctl_1.17-13_i386.deb Directory listing of /pool/main/libm/libmicrohttpd/ -r--r--r-- 1 0 0 29280 Mar 22 2011 [1149407 00] libmicrohttpd5_0.4.6-1_i386.deb -r--r--r-- 1 0 0 369694 Mar 22 2011 [1450474 00] libmono-microsoft-build2.0-cil_2.6.7-5_all.deb -r--r--r-- 1 0 0 166514 Mar 22 2011 [1450655 00] libmono-microsoft7.0-cil_2.6.7-5_all.deb -r--r--r-- 1 0 0 166642 Mar 22 2011 [1423592 00] libmono-microsoft8.0-cil_2.6.7-5_all.deb francois@totoche:/tmp/demo$
La commande est

$ curl -L -r 0-[taillechargée] URLdel’ISO > tempo.iso
$ isoinfo -l -R -i tempo.iso
et on cherche dans la sortie le nom du fichier.

Pour les CDs, 256K suffisent largement, sur le DVD, ici il a fallu pousser à 8M.

Bon on a enfin la ligne de microcode.ctl_1.17-13_i386.deb:

[quote]-r–r--r-- 1 0 0 23230 Mar 22 2011 [1066829 00] microcode.ctl_1.17-13_i386.deb[/quote]L’offset est de 2048*1066829 soit 2184865792 et la taille de 23230, le paquet est donc composé des octets de 2184865792 à 2184889021 qui vaut 2184865792+23230-1

La commande $ curl -L -r 2184865792-2184889021 http://cdimage.debian.org/debian-cd/6.0.1a/i386/iso-dvd/debian-6.0.1a-i386-DVD-2.iso > microcode.ctl_1.17-13_i386.deb récvupère le paquet.

francois@totoche:/tmp/demo$ dpkg-deb -c microcode.ctl_1.17-13_i386.deb drwxr-xr-x root/root 0 2009-10-07 08:38 ./ drwxr-xr-x root/root 0 2009-10-07 08:38 ./etc/ drwxr-xr-x root/root 0 2009-10-07 08:38 ./etc/init.d/ -rwxr-xr-x root/root 2181 2009-10-07 08:38 ./etc/init.d/microcode.ctl drwxr-xr-x root/root 0 2009-10-07 08:38 ./usr/ drwxr-xr-x root/root 0 2009-10-07 08:38 ./usr/share/ drwxr-xr-x root/root 0 2009-10-07 08:38 ./usr/share/man/ drwxr-xr-x root/root 0 2009-10-07 08:38 ./usr/share/man/man8/ -rw-r--r-- root/root 468 2009-10-07 08:38 ./usr/share/man/man8/update-intel-microcode.8.gz -rw-r--r-- root/root 1171 2009-10-07 08:38 ./usr/share/man/man8/microcode_ctl.8.gz drwxr-xr-x root/root 0 2009-10-07 08:38 ./usr/share/doc/ drwxr-xr-x root/root 0 2009-10-07 08:38 ./usr/share/doc/microcode.ctl/ -rw-r--r-- root/root 5147 2009-10-07 08:38 ./usr/share/doc/microcode.ctl/changelog.Debian.gz -rw-r--r-- root/root 812 2009-10-07 08:38 ./usr/share/doc/microcode.ctl/copyright -rw-r--r-- root/root 1594 2009-10-07 08:38 ./usr/share/doc/microcode.ctl/README.Debian -rw-r--r-- root/root 1115 2007-04-26 12:59 ./usr/share/doc/microcode.ctl/changelog.gz -rw-r--r-- root/root 2361 2009-10-07 08:38 ./usr/share/doc/microcode.ctl/README.gz drwxr-xr-x root/root 0 2009-10-07 08:38 ./usr/share/misc/ drwxr-xr-x root/root 0 2009-10-07 08:38 ./usr/sbin/ -rwxr-xr-x root/root 10388 2009-10-07 08:38 ./usr/sbin/microcode_ctl -rwxr-xr-x root/root 2503 2009-10-07 08:38 ./usr/sbin/update-intel-microcode francois@totoche:/tmp/demo$ montre qu’on a bien récupéré le bon paquet (démo faite en direct, j’ignore ce que fait ce paquet :slightly_smiling:).

Je vais utiliser cette méthode pour faire un installateur universel de ClefAgreg à partir des ISOs du site.

Tout bonnement épatant! :038

[quote=“fran.b”]La commande est

$ curl -L -r 0-[taillechargée] URLdel’ISO > tempo.iso[/quote]

C’est vrai que c’est astucieux. Cela provoquerait-il une erreur si l’on essayait de ne pas retélécharger le début du fichier à chaque fois ? Par exemple au lieu de :

$ curl -L -r 0-2000000 URL > tempo.iso $ curl -L -r 0-4000000 URL > tempo.iso $ curl -L -r 0-8000000 URL > tempo.iso

ne pourrait-on pas faire quelque chose du genre :

$ curl -L -r 0-2000000 URL > tempo.iso $ curl -L -r 2000001-4000000 URL >> tempo.iso $ curl -L -r 4000001-8000000 URL >> tempo.iso

Si ça évite de recharger la partie déjà chargée. Comme j’ai fait ça au fur et à mesure, je n’y ai pas pensé sur le coup.

[code]#!/bin/sh
FICHIER=$1
URL=$2
FICHIERMAJ=echo $FICHIER | tr '[:upper:]' '[:lower:]'
NOM=basename $FICHIER
ISO=/tmp/getfic-date +%s.iso
DEB=0
PAS=65536
FIN=expr $PAS - 1
FINP=$DEB

ONCHERCHE=true

while ($ONCHERCHE) ; do
echo curl -L -r $FINP-$FIN $URL
curl -L -r $FINP-$FIN $URL >> $ISO
isoinfo -l -R -i $ISO | tr ‘[:upper:]’ ‘[:lower:]’ | grep -v “^ *$” > /tmp/listing
while read ligne ; do
if echo $ligne | grep -q “^directory” ; then
DIR=echo $ligne | awk '{print $4}'
elif echo $ligne | grep -q “^-” ; then
ligne=echo $ligne | sed -e '1,$s/\[//g'| sed -e '1,$s/\]//g'
FIC=echo $ligne | awk '{print $11}' | sed -e 's/;1 *$//' | sed -e 's/\.$//'

echo $DIR$FIC $FIC $FICHIERMAJ

    if ( [ ! -z $FIC ] && ([ $DIR$FIC = $FICHIERMAJ ] || [ $FIC = $FICHIERMAJ ])) ; then
	ONCHERCHE=false
	OFFSET=`echo $ligne  | awk '{print $9}'`
	DEBUT=`expr $OFFSET \* 2048`
	LONGUEUR=`echo $ligne | awk '{print $5}'`

echo $OFFSET $DEBUT $LONGUEUR

	BOUT=`expr $DEBUT + $LONGUEUR - 1`
	curl -L -r $DEBUT-$BOUT $URL > $NOM
	exit 0
    fi 
fi
done < /tmp/listing
if ($ONCHERCHE) ; then
    FINP=`expr $FIN + 1`
    FIN=`expr $FIN + $PAS`
    PAS=`expr $PAS + $PAS`
fi

done
[/code]
fait le travail seul:

$ sh getfic.sh microcode.ctl_1.17-13_i386.deb http://cdimage.debian.org/debian-cd/6.0.1a/i386/iso-dvd/debian-6.0.1a-i386-DVD-2.iso

Bonjour,

Beau boulot !

Une petite question :

[code]isoinfo -l -R -i $ISO | tr [:upper:] [:lower:] | grep -v “^ *$” > /tmp/listing

while read ligne ; do
if echo $ligne | grep -q “^DIRECTORY” ; then
DIR=echo $ligne | awk '{print $4}' | tr [:upper:] [:lower:]
# …
fi
done < /tmp/listing[/code]

D’abord tu convertis tout en minuscules, ensuite tu fais un grep sur le motif DIRECTORY tout en majuscules. Il n’y aura jamais de correspondances non ? Et pourquoi reconvertir en minuscules encore une fois avec tr après ?

[quote=“branch”]Bonjour,

Beau boulot !

Une petite question :

[code]isoinfo -l -R -i $ISO | tr [:upper:] [:lower:] | grep -v “^ *$” > /tmp/listing

while read ligne ; do
if echo $ligne | grep -q “^DIRECTORY” ; then
DIR=echo $ligne | awk '{print $4}' | tr [:upper:] [:lower:]
# …
fi
done < /tmp/listing[/code]

D’abord tu convertis tout en minuscules, ensuite tu fais un grep sur le motif DIRECTORY tout en majuscules. Il n’y aura jamais de correspondances non ? Et pourquoi reconvertir en minuscules encore une fois avec tr après ?[/quote]

J’ai eu des soucis, initalement je convertissais en majuscules mais j’ai eu un message bizarre sur squeeze d’où cette inversion et l’oubli dans DIRECTORY (je corrige). Par contre, le deuxième tr est un reste du débuggage, on peut le virer. (C’est un code que j’ai fait rapidement, j’aurais du attendre un peu).

Il y a de toute façon un réel problème:

francois@totoche:/tmp$ echo ABCD Directory | tr [:upper:] [:lower:] llll lirectory francois@totoche:/tmp$

et

francois@totoche:/tmp$ echo ABCD Directory | tr [:lower:] [:upper:] tr: construit [:upper:] et/ou [:lower:] mal aligné francois@totoche:/tmp$

Edit: pétard, ça n’est pas banal comme bug:

francois@totoche:~$ echo ABCD Directory | tr [:lower:] [:upper:] ABCD DIRECTORY francois@totoche:~$

tr plante si c’est éxécuté dans le répertoire /tmp!!!

Edit: oubli de protéger lower et upper, il faut faire
echo ABCD Directory | tr ‘[:lower:]’ ‘[:upper:]’

J’ai tenté d’améliorer un peu le script, il faut voir ce qu’il y a à prendre et à laisser :

[code]#!/bin/sh

FICHIER_ENTREE="$1" #nom du fichier local contenant les noms de fichiers distants a telecharger
URL="$2"

ENTREES_RESTANTES=/tmp/copie_fichier_entree
TMPFILE=/tmp/tmpfile
cat “$FICHIER_ENTREE” | tr ‘[:upper:]’ ‘[:lower:]’ > "$ENTREES_RESTANTES"
ISO=/tmp/getfic-date +%s.iso
LISTING1=/tmp/listing1
LISTING2=/tmp/listing2
DEBUT=0
PAS=65536
FIN=expr "$PAS" - 1
TAILLE_INDEX=1

while [ -s “$ENTREES_RESTANTES” ]; do
echo '
echo DEBUT "$DEBUT"
echo FIN "$FIN"
echo '

curl -L -r “$DEBUT”-"$FIN" “$URL” >> "$ISO"
isoinfo -l -R -i “$ISO” | grep -vx ‘’ | tr ‘[:upper:]’ ‘[:lower:]’ > “$LISTING1”

ANCIENNE_TAILLE_INDEX="$TAILLE_INDEX"
TAILLE_INDEX=wc -l "$LISTING1" | grep -o '^[0-9]*'
tail -n +"$ANCIENNE_TAILLE_INDEX" “$LISTING1” > "$LISTING2"
echo ‘
echo NB DE LIGNES PRODUITES PAR ISOINFO "$TAILLE_INDEX"
echo NB DE LIGNES IGNOREES expr "$ANCIENNE_TAILLE_INDEX" - 1
echo NB DE LIGNES DU LISTING wc -l "$LISTING2"
echo '

while read ligne; do
if echo “$ligne” | grep -q ‘^directory’; then
DIR=echo "$ligne" | sed 's/^directory listing of //'
elif echo “$ligne” | grep -q ‘^-’; then
ligne=echo "$ligne" | sed -e 's/\[//' -e 's/\]//'
NAME=echo "$ligne" | sed -E 's/( *[^ ]*){10} //'
if grep -Fqxe “$NAME” -Fqxe “$DIR$NAME” “$ENTREES_RESTANTES”; then
echo '--------'
echo FICHIERS RECHERCHES ':'
cat "$ENTREES_RESTANTES"
echo '--------'
echo CORRESPONDANCE ‘:’ "$NAME"
echo ‘--------’

    grep -Fvxe "$NAME" -Fvxe "$DIR$NAME" "$ENTREES_RESTANTES" > "$TMPFILE"
    cp -fT "$TMPFILE" "$ENTREES_RESTANTES"

    echo FICHIERS RESTANTS ':'
    cat "$ENTREES_RESTANTES"
    echo '--------'

    OFFSET=`echo "$ligne" | awk '{print $9}'`
    LONGUEUR=`echo "$ligne" | awk '{print $5}'`
    PREMIER_OCTET=`expr "$OFFSET" \* 2048`
    DERNIER_OCTET=`expr "$PREMIER_OCTET" + "$LONGUEUR" - 1`
    DESTINATION=`basename "$NAME"`
    echo PREMIER_OCTET "$PREMIER_OCTET"
    echo DERNIER_OCTET "$DERNIER_OCTET"
    echo '--------'
    curl -L -r "$PREMIER_OCTET"-"$DERNIER_OCTET" "$URL" -o "$DESTINATION"

    if [ ! -s "$ENTREES_RESTANTES" ]; then
      break
    fi
  fi
fi

done < “$LISTING2”

PAS=expr "$PAS" + "$PAS"
DEBUT=expr "$FIN" + 1
FIN=expr "$FIN" + "$PAS"
done

rm “$ISO” “$LISTING1” “$LISTING2” “$TMPFILE” “$ENTREES_RESTANTES”[/code]

Exemple d’utilisation :

$ cat rechercher.txt hfsprogs_332.25-8_i386.deb zerofree_1.0.1-2_i386.deb release libxft2-dbg_2.1.14-2_i386.deb libzzip-0-13_0.13.56-1+b1_i386.deb microcode.ctl_1.17-13_i386.deb $ ./getfic.sh rechercher.txt http://cdimage.debian.org/debian-cd/6.0.1a/i386/iso-dvd/debian-6.0.1a-i386-DVD-2.iso

Changements :

  • le premier argument est un nom de fichier contenant la liste des fichiers à télécharger

  • on stocke le nombre de lignes de isoinfo qu’on a déjà traitées, pour ne pas les relire à chaque fois

  • pour récupérer le nom du répertoire, il vaut mieux éviter awk car un nom de répertoire peut contenir un espace (remplacer awk ‘{print $4}’ par sed ‘s/^directory listing of //’)

  • quand on retire les crochets [] parasites, il ne faut en retirer que deux (les deux premiers), car les noms de fichier peuvent contenir des crochets

  • suppression de sed -e ‘s/;1 *$//’ | sed -e ‘s/.$//’ , car il n’y a aucune raison de retirer ces caractères à la fin des noms de fichier

  • pour récupérer le nom du fichier, utilisation de sed -E ‘s/( [^ ]){10} //’ afin d’avoir les espaces éventuels présents dans le nom du fichier (il y a précisément 2 espaces à sauter après le 10ème champ)

Avertissement :

  • ne pas essayer de passer les noms des fichiers à télécharger dans des variables du shell, les laisser dans un fichier (sinon les espaces et les backslashs sont supprimés, les étoiles remplacées par le contenu du répertoire …)

J’ai eu des soucis avec la récupération sur des sites redirigeant vers du FTP, il a fallu couper le rapatriement en plusieurs petits morceaux avec des timeouts:

[code]#!/bin/sh
FICHIER=$1
URL=$2
FICHIERMAJ=echo $FICHIER | tr '[:upper:]' '[:lower:]'
NOM=basename $FICHIER
ISO=/tmp/getfic-date +%s.iso
DEB=0
PAS=65536
FIN=expr $PAS - 1
FINP=$DEB
MAXDL=1048576
TEMPS=5
#4194304
ONCHERCHE=true
VITMIN=1024
while ($ONCHERCHE) ; do
echo curl -L -r $FINP-$FIN $URL
curl -L -r $FINP-$FIN $URL >> $ISO
isoinfo -l -R -i $ISO | tr ‘[:upper:]’ ‘[:lower:]’ | grep -v “^ *$” > /tmp/listing
while read ligne ; do
if echo $ligne | grep -q “^directory” ; then
DIR=echo $ligne | awk '{print $4}'
elif echo $ligne | grep -q “^-” ; then
ligne=echo $ligne | sed -e '1,$s/\[//g'| sed -e '1,$s/\]//g'
FIC=echo $ligne | awk '{print $11}' | sed -e 's/;1 *$//' | sed -e 's/\.$//'

echo $DIR$FIC $FIC $FICHIERMAJ

    if ( [ ! -z $FIC ] && ([ $DIR$FIC = $FICHIERMAJ ] || [ $FIC = $FICHIERMAJ ])) ; then
	ONCHERCHE=false
	OFFSET=`echo $ligne  | awk '{print $9}'`
	DEBUT=`expr $OFFSET \* 2048`
	LONGUEUR=`echo $ligne | awk '{print $5}'`

echo $OFFSET $DEBUT $LONGUEUR

	echo -n > $NOM
	while [ $LONGUEUR -ge $MAXDL ] ; do
	BOUT=`expr $DEBUT + $MAXDL - 1`
            curl -L -y $TEMPS --speed-limit $VITMIN -r $DEBUT-$BOUT $URL > t_$NOM
	LONG=`ls -l t_$NOM | awk '{print $5}'` 
	if [ $LONG -eq $MAXDL ] ; then
	cat t_$NOM >> $NOM
	rm t_$NOM
	DEBUT=`expr $BOUT + 1`
	LONGUEUR=`expr $LONGUEUR - $MAXDL`
	else
	rm t_$NOM
	fi
	done
	BOUT=`expr $DEBUT + $LONGUEUR - 1`
	while [ $LONGUEUR -gt 0 ] ; do
		curl -L -y $TEMPS --speed-limit $VITMIN  -r $DEBUT-$BOUT $URL > t_$NOM
            	LONG=`ls -l t_$NOM | awk '{print $5}'` 
            	if [ $LONG -eq $LONGUEUR ] ; then
            		cat t_$NOM >> $NOM
            		rm t_$NOM
			LONGUEUR=0
            	else
            		rm t_$NOM
            	fi
	done
	exit 0
    fi 
fi
done < /tmp/listing
if ($ONCHERCHE) ; then
    FINP=`expr $FIN + 1`
    FIN=`expr $FIN + $PAS`
    PAS=`expr $PAS + $PAS`
fi

done
[/code]J’ai du utilisé ça sur ClefAgreg.