• [^] # Re: Dégrossissons le problème

    Posté par . En réponse au message autoextractible : théorie. Évalué à 2.

    Exemple de manip:
    On veut caser toute un tar.gz dans un executable, le decompresser a la volee dans un repertoire temporaire, et executer le programme nommé "run" contenu dans cette archive.

    Pour ca, on commence a fabriquer son tar.gz avec son executable "run" a faire demarrer une fois que la decompression sera faite : binaire ou script shell. Ensuite on fabrique un .o qui contient cette archive dans la section .rodata, et on repere les donnees ainsi enfouies par les symboles "__embed" et "_e_embed". Enfin, on lie ce .o avec un autre .o qui contient le code de decompression.

    Bon, finalement c'est peut-etre plus simple avec le code sous les yeux.

    - Le fichier qui decompresse l'archive integree dans le binaire et qui lance le programme "run" de cette archive :

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>

    extern char _b_embed, _e_embed;

    int main ()
    {
    FILE * pipe;
    char dirname[] = "/tmp/.embedXXXXXX";
    char * contents;

    mkdtemp(dirname);
    if (! dirname)
    return -1;

    if (chdir(dirname))
    return -1;

    pipe = popen("tar xzf -", "w");
    if (! pipe)
    return -1;

    for (contents = & _b_embed ; contents < & _e_embed ; contents ++)
    {
    if (fwrite(contents, 1, 1, pipe) != 1)
    return -1;
    }

    if (pclose(pipe))
    return -1;

    execl("./run", "./run", NULL);

    return -1;
    }


    - Le Makefile qui fait l'archive a compresser avec le fichier run (un script de base) a demarrer une fois que tout sera decompresse. On en profite pour mettre d'autres trucs bidon dans l'archive. Au final, le make construit le binaire avec l'archive enfouie :

    all: demo

    demo: unembed.o embedded_archive.o
    $(CC) -o $@ unembed.o embedded_archive.o

    embedded_archive.o: archive.tgz
    touch container.c && $(CC) -c container.c
    objcopy --add-section .embed=$< container.o
    echo "SECTIONS { .rodata . : { _b_embed = .; container.o(.embed); _e_embed = .; }}" \
    > script.lds
    ld -r -o $@ script.lds

    archive.tgz:
    echo "#! /bin/sh" > run
    echo 'echo "######### Hello World ! #########"' >> run
    echo 'echo Cur dir=`pwd`' >> run
    echo "echo Dir contents:" >> run
    echo "ls -la" >> run
    # echo "make && ./demo" >> run
    chmod 755 run
    tar czf $@ run Makefile unembed.c

    clean:
    $(RM) unembed.o* demo archive.tgz embedded_archive.o


    Et voila ! Maintenant je mets l'executable "demo" n'importe ou, je l'execute, et, dans le /tmp/.embedXYZTUV, ce decompressera tout et ca lancera le script "run" !

    Note : le "XYZTUV" est genere par mkdtemp, le script "run" s'occupera de l'afficher.

    Note 2 : le code a l'air de marcher, il y a peut-etre quelques optimisations a faire (regarder du cote de fwrite).