                     Livre de chevet du developpeur FreeBSD

  Le groupe du projet de documentation FreeBSD

   Version: 43126

   Copyright (c) 2000-2003 Le groupe du projet de documentation FreeBSD

   Copyright

   Redistribution and use in source (XML DocBook) and 'compiled' forms (XML,
   HTML, PDF, PostScript, RTF and so forth) with or without modification, are
   permitted provided that the following conditions are met:

    1. Redistributions of source code (XML DocBook) must retain the above
       copyright notice, this list of conditions and the following disclaimer
       as the first lines of this file unmodified.

    2. Redistributions in compiled form (transformed to other DTDs, converted
       to PDF, PostScript, RTF and other formats) must reproduce the above
       copyright notice, this list of conditions and the following disclaimer
       in the documentation and/or other materials provided with the
       distribution.

  Important:

   THIS DOCUMENTATION IS PROVIDED BY THE FREEBSD DOCUMENTATION PROJECT "AS
   IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
   THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD DOCUMENTATION
   PROJECT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

   Aout 2000 par .
   Resume

   Bienvenue dans le livre de chevet du developpeur

   Version franc,aise de Frederic Praca <frederic.praca@freebsd-fr.org>.

   N.d.T.: La version franc,aise est publiee sur le serveur World Wide Web du
   groupe de traduction en langue franc,aise de la documentation de FreeBSD.

   N.d.T.: Contactez la liste de diffusion du groupe d'utilisateurs
   francophones de FreeBSD <freebsd-questions@FreeBSD-fr.org> si vous voulez
   collaborer `a la traduction.

   La traduction de ce manuel est "en cours". Dans la table des matieres
   ci-dessous:

     * Les chapitres marques de deux asterisques sont en cours de traduction.

     * Les chapitres marques de trois asterisques sont `a traduire.

     * L'asterisque simple est reserve aux chapitres et sections en cours de
       redaction dans la version U.S.

   [ Split HTML / Single HTML ]

     ----------------------------------------------------------------------

   Table des matieres

   I. Introduction

                1. Developper sous FreeBSD

                2. La vision BSD

                3. Survol de l'architecture

                4. L'agencement de /usr/src

   II. Les fondamentaux

                5. Outils de programmation

                             5.1. Synopsis

                             5.2. Introduction

                             5.3. Introduction `a la programmation

                             5.4. Compiler avec cc

                             5.5. Make

                             5.6. Deverminer

                             5.7. Utiliser Emacs comme environnement de
                             developpement

                             5.8. Pour aller plus loin

                6. Programmation securisee

                             6.1. Synopsis

                             6.2. Methodologie de developpement securise

                             6.3. Depassement de capacite

                             6.4. Les problemes lies `a SetUID

                             6.5. Limiter l'environnement de votre programme

                             6.6. La confiance

                             6.7. Les conditions de course

   III. Le noyau

                7. Histoire du noyau Unix

                8. Notes sur le verrouillage

                             8.1. Les mutex

                             8.2. Les verrous du gestionnaire de verrous
                             (Lock Manager)

                             8.3. Variables protegees atomiquement

   IV. Memoire et memoire virtuelle

                9. La memoire virtuelle

   V. Systeme E/S (Entrees/Sorties)

                10. UFS

   VI. Communication InterProcessus (IPC)

                11. Les signaux

   VII. Le reseau

                12. Les prises

   VIII. Systemes de fichiers en reseau

                13. AFS

   IX. Gestion du terminal

                14. Syscons

   X. Le son

                15. OSS

   XI. Pilotes de peripherique

                16. Ecrire des pilotes de peripheriques pour FreeBSD

                             16.1. Introduction

                             16.2. L'editeur de liens dynamiques du noyau -
                             KLD

                             16.3. Acceder au pilote d'un peripherique

                             16.4. Les peripheriques caracteres

                             16.5. Pilotes Reseau

                17. Les peripheriques PCI

                             17.1. Rechercher et rattacher

                             17.2. Les ressources du bus

                18. Controleurs SCSI Common Access Method (CAM) **

                             18.1. En cours de traduction

                19. Peripheriques USB ***

                             19.1. Introduction

                20. NewBus

   XII. Architectures

                21. IA-32

                22. Alpha

                23. IA-64

   XIII. Deverminage

                24. Truss

   XIV. Les couches de compatibilite

                25. Linux

   XV. Bibligraphie

                Bibliographie

   Liste des tableaux

   8.1. Liste du mutex

   8.2. lockmgr(9) List de verrou

   Liste des exemples

   5.1. Un fichier exemple .emacs

                             Partie I. Introduction

   Table des matieres

   1. Developper sous FreeBSD

   2. La vision BSD

   3. Survol de l'architecture

   4. L'agencement de /usr/src

Chapitre 1. Developper sous FreeBSD

   Ce document a pour but de decrire FreeBSD comme une plateforme de
   developpement, la vision de BSD, un survol de l'architecture, l'agencement
   de /usr/src, l'histoire, etc.

   Merci d'adopter FreeBSD comme votre plateforme de developpement ! Nous
   esperons qu'elle ne vous laissera pas tomber.

Chapitre 2. La vision BSD

Chapitre 3. Survol de l'architecture

Chapitre 4. L'agencement de /usr/src

   Le code source complet de FreeBSD est disponible depuis notre base CVS
   publique. Le code source est normalement installe sous /usr/src qui
   contient les sous-repertoires suivants.

   Repertoire                           Description                           
   bin/        Sources des fichiers de /bin                                   
   contrib/    Sources des fichiers des logiciels fournis ("contributed").    
   crypto/     Sources du DES                                                 
   etc/        Sources des fichiers de /etc                                   
   games/      Sources des fichiers de /usr/games                             
   gnu/        Utilitaires sous licence publique GNU                          
   include/    Sources des fichiers de /usr/include                           
   kerberosIV/ Sources de Kerbereros version IV                               
   kerberos5/  Sources de Kerbereros version 5                                
   lib/        Sources des fichiers de /usr/lib                               
   libexec/    Sources des fichiers de /usr/libexec                           
   release/    Fichiers requis pour la production d'une version stable de     
               FreeBSD                                                        
   sbin/       Sources des fichiers de /sbin                                  
   secure/     Sources de FreeSec                                             
   share/      Sources des fichiers de /sbin                                  
   sys/        Fichiers source du noyau                                       
   tools/      Outils utilises pour la maintenance et les tests de FreeBSD    
   usr.bin/    Sources des fichiers de /usr/bin                               
   usr.sbin/   Sources des fichiers de /usr/sbin                              

                          Partie II. Les fondamentaux

   Table des matieres

   5. Outils de programmation

                5.1. Synopsis

                5.2. Introduction

                5.3. Introduction `a la programmation

                5.4. Compiler avec cc

                5.5. Make

                5.6. Deverminer

                5.7. Utiliser Emacs comme environnement de developpement

                5.8. Pour aller plus loin

   6. Programmation securisee

                6.1. Synopsis

                6.2. Methodologie de developpement securise

                6.3. Depassement de capacite

                6.4. Les problemes lies `a SetUID

                6.5. Limiter l'environnement de votre programme

                6.6. La confiance

                6.7. Les conditions de course

Chapitre 5. Outils de programmation

   Table des matieres

   5.1. Synopsis

   5.2. Introduction

   5.3. Introduction `a la programmation

   5.4. Compiler avec cc

   5.5. Make

   5.6. Deverminer

   5.7. Utiliser Emacs comme environnement de developpement

   5.8. Pour aller plus loin

   Ce chapitre a ete ecrit par James Raynard. Les modifications pour le livre
   de chevet du developpeur par Murray Stokely.

5.1. Synopsis

   Ce document est une introduction `a l'utilisation de quelques outils de
   programmation fournis avec FreeBSD, toutefois tout sera applicable `a
   beaucoup d'autres versions d'Unix. Cette introduction n'essaye pas de
   decrire la programmation dans le detail. La plupart du document suppose
   que vous possedez peu ou pas de connaissances en programmation, esperant
   que les programmeurs trouveront un interet dans ce document.

5.2. Introduction

   FreeBSD offre un excellent environnement de developpement. Des
   compilateurs pour C, C++ et Fortran ainsi qu'un assembleur sont fournis
   avec le systeme de base, sans parler de l'interpreteur PERL ni des outils
   classiques Unix comme sed et awk. Si cela n'est pas suffisant, il y a
   encore plus de compilateurs et d'interpreteurs dans la collection des
   logiciels portes. FreeBSD est compatible avec les standards comme POSIX et
   C ANSI, aussi bien qu'avec son propre heritage BSD, aussi il est possible
   d'ecrire des applications qui se compileront et s'executeront avec peu ou
   pas de modifications sur un grand nombre de plateformes.

   Toutefois, toute cette puissance peut etre plutot ecrasante au premier
   abord si vous n'avez jamais ecrit de programmes sur une plateforme Unix
   auparavant. Ce document a pour but de vous aider `a commencer, sans entrer
   trop loin dans des sujets plus avances. L'intention est que ce document
   devrait vous donner assez de bases pour etre capable de donner du sens `a
   la documentation.

   La majeure partie du document requiert peu ou pas de connaissance de la
   programmation, bien qu'il suppose une competence de base dans
   l'utilisation d'Unix et dans la bonne volonte d'apprendre !

5.3. Introduction `a la programmation

   Un programme est un ensemble d'instructions qui disent `a l'ordinateur de
   faire diverses choses; quelques fois, l'instruction qu'il a `a executer
   depend de ce qui s'est passe lors de l'execution d'une instruction
   precedente. Cette section donne un aperc,u des deux manieres par
   lesquelles vous pouvez donner ces instructions, ou << commandes >> comme
   elles sont habituellement nommees. Une fac,on utilise un interpreteur,
   l'autre un compilateur. Comme les langages humains sont trop difficiles `a
   comprendre sans ambiguite par un ordinateur, les commandes sont
   habituellement ecrites dans un langage ou un autre specialement conc,us
   pour cet usage.

  5.3.1. Les interpreteurs

   Avec un interpreteur, le langage va avec un environnement ou vous entrez
   des commandes `a un invite de commandes et l'environnement les execute
   pour vous. Pour des programmes plus compliques, vous pouvez entrer les
   commandes dans un fichier et demander `a l'interpreteur de charger le
   fichier et d'executer les commandes qui sont `a l'interieur. Si quoique ce
   soit se passe mal, beaucoup d'interpreteurs vous enverrons dans un
   devermineur pour vous aider `a debusquer le probleme.

   L'avantage de cela est que vous pouvez voir les resultats de vos commandes
   immediatement, et les erreurs peuvent etre corrigees facilement. Le plus
   gros desavantage arrive quand vous voulez partager vos programmes avec
   d'autres personnes. Ils doivent avoir le meme interpreteur ou bien vous
   devez avoir un moyen de leur donner, et ils doivent comprendre comment
   l'utiliser. Par ailleurs, les utilisateurs pourraient ne pas apprecier
   d'etre renvoyes dans un devermineur s'ils ont appuye sur la mauvaise
   touche ! D'un point de vue performance, les interpreteurs peuvent utiliser
   beaucoup de memoire et generalement ne generent pas un code aussi efficace
   que les compilateurs.

   A mon avis, les langages interpretes sont le meilleur moyen pour demarrer
   si vous n'avez jamais programme. Ce genre d'environnement se trouve
   typiquement avec des langages comme Lisp, Smalltalk, Perl et Basic. Il
   peut aussi etre dit que l'interpreteur de commandes Unix (sh, csh) est
   lui-meme un interpreteur, et beaucoup de gens ecrivent en fait des
   << scripts >> (procedures) pour l'interpreteur pour les aider dans
   diverses taches << domestiques >> sur leur machine. En effet, une partie
   de la philosophie d'origine d'Unix etait de fournir plein de petits
   programmes utilitaires qui pouvaient etre lies ensemble dans des
   procedures pour effectuer des taches utiles.

  5.3.2. Les interpreteurs disponibles avec FreeBSD

   Voici la liste des interpreteurs qui sont disponibles sous la forme de
   logiciels pre-compiles pour FreeBSD, avec une breve description de
   quelques uns des langages interpretes les plus populaires.

   Pour obtenir un de ces logiciels pre-compiles, tout ce que vous avez `a
   faire est de cliquer sur le lien du logiciel et d'executer

 # pkg_add nom du logiciel
      

   en tant que super-utilisateur. Evidemment, vous aurez besoin d'un FreeBSD
   2.1.0 ou plus en etat de marche pour que le logiciel fonctionne !

   BASIC

           Abbreviation de "Beginner's All-purpose Symbolic Instruction Code"
           (code d'instruction symbolique tout usage pour le debutant).
           Developpe dans les annees 50 pour apprendre aux etudiants
           d'universite `a programmer et fourni avec tout ordinateur qui se
           respecte dans les annees 80, BASIC a ete le premier langage de
           programmation pour beaucoup de programmeurs. Il est aussi le
           fondement meme du Visual Basic.

           L'interpreteur Basic Bywater et l'interpreteur Basic de Phil
           Cockroft (anciennement Rabbit Basic) sont disponibles pour FreeBSD
           sous forme de logiciels pre-compiles

   Lisp

           Un langage qui a ete developpe `a la fin des annees 50 comme une
           alternative aux langages << devoreurs de calculs >> qui etaient
           tres populaires `a l'epoque. Plutot qu'etre base sur les nombres,
           Lisp est base sur les listes; en fait le nom est l'abbreviation de
           << List Processing >>. Tres populaire en IA (Intelligence
           Artificielle).

           Lisp est un langage extremement puissant et sophistique , mais
           peut etre assez lourd et peu maniable.

           FreeBSD a GNU Common Lisp de disponible sous la forme d'un
           logiciel pre-compile.

   Perl

           Tres populaire aupres des administrateurs systeme pour la
           redaction de procedures; aussi souvent utilise sur les serveurs
           Internet pour l'ecriture de procedures CGI.

           La derniere version (version 5) est fournie avec FreeBSD.

   Scheme

           Un derive du Lisp qui est plutot plus compact et plus propre que
           le Common Lisp. Populaire dans les universites etant suffisamment
           simple `a apprendre aux etudiants comme premier langage , il
           possede un niveau d'abstraction suffisamment important pour etre
           utilise dans le travail de recherche.

           On trouve pour FreeBSD les logiciels pre-compiles interpreteur
           Scheme Elk, l'interpreteur Scheme du MIT et l'interpreteur Scheme
           SCM.

   Icon

           Le langage de programmation Icon.

   Logo

           l'interpreteur Logo de Brian Harvey.

   Python

           Le langage oriente objet Python

  5.3.3. Les compilateurs

   Les compilateurs sont plutot differents entre eux. Tout d'abord, vous
   ecrivez votre code dans un fichier (ou des fichiers) en utilisant un
   editeur de texte. Vous executez ensuite le compilateur et verifiez qu'il
   accepte votre programme. S'il ne compile pas, grincez des dents et
   retournez `a l'editeur; s'il compile et vous donne un programme, vous
   pouvez executer ce dernier `a l'invite de commande ou dans un devermineur
   pour voir s'il fonctionne correctement. [1]

   Evidemment, ce n'est pas aussi direct que d'utiliser un interpreteur.
   Toutefois cela vous permet de faire beaucoup de choses qui sont difficiles
   ou meme impossibles avec un interpreteur, comme ecrire du code qui
   interagit de fac,on proche du systeme d'exploitation ou meme d'ecrire
   votre propre systeme d'exploitation ! C'est aussi utile si vous avez
   besoin d'ecrire du code tres efficace, etant donne que le compilateur peut
   prendre son temps et optimiser le code, ce qui ne serait pas acceptable
   avec un interpreteur. Et distribuer un programme ecrit pour un compilateur
   est habituellement plus evident qu'un ecrit pour un interpreteur-vous
   pouvez juste donner une copie de l'executable, en supposant que
   l'utilisateur possede le meme systeme d'exploitation que vous.

   Les langages compiles incluent Pascal, C et C++. C et C++ sont des
   langages plutot impitoyables et conviennent mieux aux programmeurs
   experimentes; Pascal, d'autre part, a ete conc,u comme un langage
   educatif, et est un assez bon langage pour commencer. Malheureusement,
   FreeBSD ne possede aucun support Pascal, excepte pour un convertisseur
   Pascal vers C dans les logiciels portes.

   Le cycle edition-compilation-execution-deverminage etant relativement
   penible lors de l'utilisation de programmes separes, beaucoup de
   fabricants de compilateur ont produit des environnements de developpement
   integres (ou IDE pour Integrated Development Environments et EDI dans la
   langue de Moliere). FreeBSD ne possede pas d'EDI tel quel; toutefois il
   est possible d'utiliser Emacs `a cet effet. Ceci est vu dans Section 5.7,
   << Utiliser Emacs comme environnement de developpement >>.

5.4. Compiler avec cc

   Cette section traite uniquement du compilateur GNU pour C et C++, celui-ci
   faisant partie du systeme FreeBSD de base. Il peut etre invoque soit par
   cc ou gcc. Les details de production d'un programme avec un interpreteur
   varient considerablement d'un interpreteur `a l'autre, et sont
   habituellement bien couverts par la documentation et l'aide en ligne de
   l'interpreteur.

   Une fois que vous avez ecrit votre chef d'oeuvre, la prochaine etape est
   de le convertir en quelque chose qui s'executera (esperons !) sur FreeBSD.
   Cela implique normalement plusieurs etapes, realisees chacune par un
   programme different.

    1. Pre-traiter votre code source pour retirer les commentaires et faire
       d'autres trucs comme developper (expanser) les macros en C.

    2. Verifier la syntaxe de votre code source pour voir si vous avez obei
       aux regles du langage. Si vous ne l'avez pas fait, il se plaindra !

    3. Convertir le code source en langage assembleur- cela est vraiment
       proche du code machine, mais reste comprehensible par des humains.
       Pretendument. [2]

    4. Convertir le langage assembleur en code machine -ouais, on parle de
       bits et d'octets, de uns et de zeros.

    5. Verifier que vous avez utilise des choses comme des fonctions et des
       variables globales de fac,on consistente. Par exemple, si vous avez
       appele une fonction inexistente, le compilateur se plaindra.

    6. Si vous essayez de produire un executable depuis plusieurs fichiers de
       code source, resoudre comment les faire fonctionner ensemble.

    7. Resoudre comment produire quelque chose que le chargeur au vol du
       systeme sera capable de charger en memoire et executer.

    8. Finalement, ecrire l'executable dans le systeme de fichiers.

   Le mot compilation est souvent utilise pour les etapes 1 `a 4 seules-les
   autres correspondent au terme liaison. Quelquefois, l'etape 1 est appelee
   pre-traitement et les etapes 3-4 assemblage.

   Heureusement, la plupart de ces details vous sont caches, etant donne que
   cc est un frontal qui s'occupe d'appeler tous les programmes avec les
   arguments corrects pour vous; tapez simplement

 % cc foobar.c
    

   compilera foobar.c avec toutes les etapes au-dessus. Si vous avez plus
   d'un fichier `a compiler, faites simplement quelque chose comme

 % cc foo.c bar.c
    

   Notez que la verification de syntaxe n'est que cela-verifier la syntaxe.
   Cela ne verifiera pas les erreurs de logique que vous pouvez avoir faites,
   comme mettre le programme en boucle infinie ou utiliser un tri `a bulles
   quand vous devriez utiliser un tri binaire. [3]

   Il y a beaucoup d'options pour cc, qui qui se trouvent toutes dans les
   pages de manuel en ligne. Voici quelques unes des plus importantes, avec
   des exemples illustrant leur utilisation.

   -o nom_du_fichier

           Le nom de sortie du fichier. Si vous n'utilisez pas cette option,
           cc produira un executable appele a.out. [4]

 % cc foobar.c               l'executable est a.out
 % cc -o foobar foobar.c     l'executable est foobar
            

   -c

           Compile juste le fichier, ne le lie pas. Utile pour les programmes
           jouets dont vous voulez juste verifier la syntaxe, ou si vous
           utilisez un Makefile.

 % cc -c foobar.c
            

           Cela va produire un fichier objet (pas un executable) appele
           foobar.o. Celui-ci peut etre lie ensuite avec d'autres fichiers
           objets pour produire un executable.

   -g

           Cree une version de deverminage de l'executable. Cela oblige le
           compilateur `a placer des informations dans l'executable comme
           telle ligne du fichier source correspond `a tel appel de fonction.
           Un devermineur peut utiliser cette information pour vous montrer
           le code source au fur et `a mesure que vous avancez pas `a pas
           dans le programme, ce qui est tres utile; le desavantage est que
           toutes ces informations supplementaires rendent le programme plus
           gros. Normalement, vous compilez avec l'option -g quand vous etes
           en train de developper un programme et compilez ensuite une
           << version de production >> sans -g quand vous etes satisfait du
           fonctionnement.

 % cc -g foobar.c
            

           Cela va produire une version de deverminage du programme foobar.
           [5]

   -O

           Cree une version optimisee de l'executable. Le compilateur
           effectue differents trucs malins pour essayer de produire un
           executable qui s'execute plus rapidement que normal. Vous pouvez
           ajouter un nombre apres l'option -O pour specifier un niveau
           d'optimisation plus important, mais cela vous expose souvent aux
           bogues dans l'optimiseur du compilateur. Par exemple, la version
           de cc fournit avec la version 2.1.0 FreeBSD est connue pour
           produire du mauvais code avec l'option -O2 dans certaines
           circonstances.

           L'optimisation est habituellement activee uniquement lors de la
           compilation d'une version de production.

 % cc -O -o foobar foobar.c
            

           Cela va produire une version optimisee de foobar.

   Les trois prochaines options vont forcer cc `a verifier que votre code est
   conforme au standard international en cours, se referant souvent `a la
   norme ANSI, qui pour dire precisement est un standard ISO.

   -Wall

           Active tous les avertissements que les auteurs de cc pensent
           valoir le coup. Malgre le nom, il n'active pas tous les
           avertissements dont cc est capable.

   -ansi

           Desactive la plupart, mais pas toutes, des caracteristiques du C
           fournies par cc qui sont non-ANSI . Malgre le nom, cela ne
           garantit pas strictement que votre code sera conforme au standard.

   -pedantic

           Desactive toutes les caracteristiques de cc qui ne sont pas ANSI .

   Sans ces options, cc vous permettrait d'utiliser quelques extensions au
   standard non-standards. Quelques unes de celles-ci sont tres utiles, mais
   ne fonctionneront pas avec d'autres compilateurs -en fait, un des
   principaux buts du standard est de permettre aux gens d'ecrire du code qui
   fonctionnera avec n'importe quel compilateur sur n'importe quel systeme.
   Cela est connu sous le nom de code portable.

   Generalement, vous devriez essayer de faire votre code aussi portable que
   possible, sinon vous pourriez avoir a re-ecrire totalement votre programme
   plus tard pour le faire fonctionner autre part-et qui sait ce que vous
   utiliserez dans quelques annees?

 % cc -Wall -ansi -pedantic -o foobar foobar.c
      

   Cela produira un executable foobar apres avoir verifie que foobar.c est
   conforme au standard.

   -llibrairie

           Specifie une librairie de fonctions `a utiliser lors de l'edition
           des liens.

           L'exemple le plus commun de cela est lors de la compilation d'un
           programme qui utilise quelques fonctions mathematiques en C. A
           l'inverse de la plupart des plateformes, celles-ci se trouvent
           dans une librairie standard du C et vous devez dire au compilateur
           de l'ajouter.

           La regle est que si une librairie est appelee libquelque_chose.a,
           vous donnez `a cc l'argument -lquelque_chose. Par exemple, la
           librairie des fonctions mathematiques est libm.a, aussi vous
           donnez `a cc le parametre -lm. Un << piege >> habituel avec la
           librairie math est qu'elle doit etre la derniere sur la ligne de
           commande.

 % cc -o foobar foobar.c -lm
            

           Cela va lier les fonctions de la librairie math `a l'interieur de
           foobar.

           Si vous compilez du C++; vous devrez ajouter -lg++, ou -lstdc++ si
           vous utilisez FreeBSD 2.2 ou ulterieur, `a la ligne de commande de
           cc pour lier avec les fonctions de la librairie C++.
           Alternativement, vous pouvez utiliser c++ plutot que cc, qui fait
           tout cela pour vous. c++ peut aussi etre invoque par g++ sur
           FreeBSD.

 % cc -o foobar foobar.cc -lg++     Pour FreeBSD 2.1.6 et anterieur
 % cc -o foobar foobar.cc -lstdc++  Pour FreeBSD 2.2 et ulterieur
 % c++ -o foobar foobar.cc
            

           Chacune de ces commandes va produire un executable foobar `a
           partir du fichier source C++ foobar.cc. Notez que, sur les
           systemes Unix , les fichiers source C++ se terminent
           traditionnellement en .C, .cxx ou .cc, plutot que le style MS-DOS
           .cpp (qui etait dej`a utilise pour autre chose). gcc a utilise
           cela pour trouver le type de compilateur `a utiliser sur le
           fichier source; toutefois, cette restriction ne s'applique plus,
           aussi vous pouvez maintenant appeler vos fichiers C++ .cpp en
           toute impunite !

  5.4.1. Questions et problemes usuels sur cc

   5.4.1.1. J'essaye d'ecrire un programme qui utilise la fonction sin() et
   je rec,ois l'erreur suivante. Que cela signifie-t-il ?

   5.4.1.2. J'ai ecrit un programme simple pour m'exercer `a l'utilisation de
   l'option -lm. Tout ce qu'il fait est d'elever 2,1 `a la puissance 6.

   5.4.1.3. Alors comment puis-je le reparer?

   5.4.1.4. J'ai compile un fichier appele foobar.c et je ne trouve pas
   d'executable appele foobar. Ou est-il parti?

   5.4.1.5. OK, j'ai un executable appele foobar, je peux le voir en
   executant ls, mais quand je tape foobar `a l'invite de commandes, la
   reponse est qu'il n'y a pas de tel fichier. Pourquoi le systeme ne le
   trouve pas?

   5.4.1.6. J'ai appele mon executable test, mais rien ne se passe quand je
   l'execute. Que se passe-t-il?

   5.4.1.7. J'ai compile mon programme et il semble fonctionner au premier
   abord, puis il y a une erreur et le systeme a dit quelque chose comme core
   dumped. Que cela signifie-t-il?

   5.4.1.8. Fascinant, mais que suis-je suppose faire ?

   5.4.1.9. Quand mon programme a genere un fichier core, il a parle d'une
   erreur segmentation fault. Qu'est-ce que c'est ?

   5.4.1.10. Des fois quand je rec,oit une erreur core dump, il est precise
   bus error. Il est dit dans mon livre Unix qu'il s'agit d'un probleme
   materiel mais l'ordinateur semble toujours fonctionner. Est-ce vrai ?

   5.4.1.11. Toute cette affaire de fichier core semble etre assez utile, si
   je peux le faire apparaitre quand je le desire. Puis-je faire cela, ou
   dois-je attendre la prochaine erreur ?

5.4.1.1.  J'essaye d'ecrire un programme qui utilise la fonction sin() et je rec,ois 
          l'erreur suivante. Que cela signifie-t-il ?                                
                                                                                     
          /var/tmp/cc0143941.o: Undefined symbol `_sin' referenced from text segment 
                                                                                     
          Lors de l'utilisation des fonctions mathematiques comme sin(), vous devez  
          dire `a cc de lier avec la librairie math, comme :                         
                                                                                     
          % cc -o foobar foobar.c -lm                                                
                                                                                     
5.4.1.2.  J'ai ecrit un programme simple pour m'exercer `a l'utilisation de l'option 
          -lm. Tout ce qu'il fait est d'elever 2,1 `a la puissance 6.                
                                                                                     
          #include <stdio.h>                                                         
                                                                                     
          int main() {                                                               
                  float f;                                                           
                                                                                     
                  f = pow(2.1, 6);                                                   
                  printf("2.1 ^ 6 = %f\n", f);                                       
                  return 0;                                                          
          }                                                                          
                                                                                     
                                                                                     
          j'ai effectue la compilation comme suit :                                  
                                                                                     
          % cc temp.c -lm                                                            
                                                                                     
                                                                                     
          et comme explique ici, mais j'obtiens ceci quand je l'execute :            
                                                                                     
          % ./a.out                                                                  
          2.1 ^ 6 = 1023.000000                                                      
                                                                                     
                                                                                     
          Ce n'est pas la reponse correcte ! Que se passe-t-il ?                     
          Quand le compilateur voit que vous appelez une fonction, il verifie s'il a 
          dej`a un prototype pour celle-ci. S'il ne l'a pas vu, il suppose que la    
          fonction retourne un int, ce qui n'est absolument pas ce que vous voulez   
          ici.                                                                       
5.4.1.3.  Alors comment puis-je le reparer?                                          
          Les prototypes des fonctions mathematiques sont dans math.h. Si vous       
          incluez ce fichier, le compilateur sera capable de trouver le prototype et 
          il arretera de faire des trucs etranges `a vos calculs!                    
                                                                                     
          #include <math.h>                                                          
          #include <stdio.h>                                                         
                                                                                     
          int main() {                                                               
          ...                                                                        
                                                                                     
                                                                                     
          Apres avoir recompile comme precedemment, executez :                       
                                                                                     
          % ./a.out                                                                  
          2.1 ^ 6 = 85.766121                                                        
                                                                                     
                                                                                     
          Si vous utilisez quelques fonctions mathematiques que ce soit, incluez     
          toujours math.h et n'oubliez pas de lier avec la librairie math.           
5.4.1.4.  J'ai compile un fichier appele foobar.c et je ne trouve pas d'executable   
          appele foobar. Ou est-il parti?                                            
          Souvenez-vous, cc appellera l'executable a.out sauf si vous lui dites de   
          faire autrement. Utilisez l'option -o nomfichier:                          
                                                                                     
          % cc -o foobar foobar.c                                                    
                                                                                     
5.4.1.5.  OK, j'ai un executable appele foobar, je peux le voir en executant ls,     
          mais quand je tape foobar `a l'invite de commandes, la reponse est qu'il   
          n'y a pas de tel fichier. Pourquoi le systeme ne le trouve pas?            
          A l'inverse de MS-DOS, Unix ne regarde pas dans le repertoire courant      
          lorsqu'il essaye de trouver un executable que vous voulez executer, sauf   
          si vous lui avez dit de le faire. Vous pouvez soit taper ./foobar, ce qui  
          signifie << execute le fichier nomme foobar dans le repertoire courant >>, 
          soit changer votre variable d'environnement PATH de fac,on `a ce qu'elle   
          ressemble `a quelque chose comme                                           
                                                                                     
          bin:/usr/bin:/usr/local/bin:.                                              
                                                                                     
                                                                                     
          Le point `a la fin signifie << regarde dans le repertoire courant s'il     
          n'est dans aucun autre >>.                                                 
5.4.1.6.  J'ai appele mon executable test, mais rien ne se passe quand je l'execute. 
          Que se passe-t-il?                                                         
          La plupart des systemes Unix ont un programme appele test dans /usr/bin et 
          l'interpreteur prend celui-ci avant de verifier dans le repertoire         
          courant. Soit vous tapez                                                   
                                                                                     
          % ./test                                                                   
                                                                                     
                                                                                     
          soit vous choisissez un meilleur nom pour votre programme !!               
5.4.1.7.  J'ai compile mon programme et il semble fonctionner au premier abord, puis 
          il y a une erreur et le systeme a dit quelque chose comme core dumped. Que 
          cela signifie-t-il?                                                        
          Le nom core dump date des tous premiers jours d'Unix, quand les machines   
          utilisaient la memoire centrale[6]pour stocker les donnees. Simplement, si 
          le programme a echoue sous certaines conditions, le systeme va ecrire le   
          contenu de la memoire centrale sur le disque dans un fichier appele core,  
          que le programmeur peut ensuite examiner de pres pour trouver ce qui s'est 
          mal passe.                                                                 
5.4.1.8.  Fascinant, mais que suis-je suppose faire ?                                
          Utilisez gdb pour analyser le fichier core (voir Section 5.6,              
          << Deverminer >>).                                                         
5.4.1.9.  Quand mon programme a genere un fichier core, il a parle d'une erreur      
          segmentation fault. Qu'est-ce que c'est ?                                  
          Cela signifie simplement que votre programme a essaye d'effectuer une      
          operation illegale sur la memoire; Unix est conc,u pour proteger le        
          systeme d'exploitation et les autres programmes des programmes crapuleux.  
                                                                                     
          Les causes habituelles de cela sont :                                      
                                                                                     
            * Essayer d'ecrire dans un pointeur NULL, par exemple                    
                                                                                     
           char *foo = NULL;                                                         
           strcpy(foo, "bang!");                                                     
                                                                                     
                                                                                     
            * Utiliser un pointeur qui n'a pas ete initialise, par exemple           
                                                                                     
           char *foo;                                                                
           strcpy(foo, "bang!");                                                     
                                                                                     
                                                                                     
              Le pointeur va avoir une valeur aleatoire qui avec de la chance,       
              pointera dans une zone de la memoire qui n'est pas disponible pour     
              votre programme et le noyau va tuer votre programme avant qu'il ne     
              fasse des dommages. Si vous etes malchanceux, il pointera quelque part 
              dans votre propre programme et alterera une de vos structures de       
              donnees, faisant planter votre programme mysterieusement.              
                                                                                     
            * Essayer d'acceder la memoire au-del`a de la fin d'un tableau, par      
              exemple                                                                
                                                                                     
           int bar[20];                                                              
           bar[27] = 6;                                                              
                                                                                     
                                                                                     
            * Essayer de stocker quelque chose dans la memoire en lecture seule, par 
              exemple                                                                
                                                                                     
           char *foo = "Ma chaine";                                                  
           strcpy(foo, "bang!");                                                     
                                                                                     
                                                                                     
              Les compilateurs Unix mettent souvent les chaines comme "Ma chaine"    
              dans des zones de memoire en lecture seule.                            
                                                                                     
            * Faire des trucs sales avec malloc() et free(), par exemple             
                                                                                     
           char bar[80];                                                             
           free(bar);                                                                
                                                                                     
                                                                                     
              ou                                                                     
                                                                                     
           char *foo = malloc(27);                                                   
           free(foo);                                                                
           free(foo);                                                                
                                                                                     
                                                                                     
          Faire une de ces fautes ne conduit pas toujours `a une erreur, mais elles  
          sont toujours de mauvais entrainements. Certains systemes et compilateurs  
          sont plus tolerants que d'autres, ce qui explique pourquoi des programmes  
          qui fonctionnent bien sur un systeme peuvent planter si vous les essayer   
          sur un autre.                                                              
5.4.1.10. Des fois quand je rec,oit une erreur core dump, il est precise bus error.  
          Il est dit dans mon livre Unix qu'il s'agit d'un probleme materiel mais    
          l'ordinateur semble toujours fonctionner. Est-ce vrai ?                    
          Non, heureusement non (sauf si bien sur vous avez reellement un probleme   
          materiel...). Cela est habituellement une maniere de dire que vous avez    
          accede `a la memoire d'une fac,on que vous n'auriez pas du.                
5.4.1.11. Toute cette affaire de fichier core semble etre assez utile, si je peux le 
          faire apparaitre quand je le desire. Puis-je faire cela, ou dois-je        
          attendre la prochaine erreur ?                                             
          Oui, ouvrez une autre console ou xterm, faites                             
                                                                                     
          % ps                                                                       
                                                                                     
                                                                                     
          pour trouver l'identifiant du processus de votre programme, et faites      
                                                                                     
          % kill -ABRT identifiant                                                   
                                                                                     
                                                                                     
          ou identifiant est l'identifiant du processus que vous avez trouve.        
                                                                                     
          Ceci est utile si votre programme est bloque dans une boucle infinie, par  
          exemple. Si votre programme arrive `a bloquer le signal SIGABRT, il y a    
          d'autres signaux qui ont des effets similaires.                            
                                                                                     
          Alternativement, vous pouvez creer un fichier core depuis votre programme, 
          en appelant la fonction abort(). Voir la page de manuel en ligne de        
          abort(3) pour en savoir plus.                                              
                                                                                     
          Si vous voulez creer un fichier core depuis l'exterieur de votre           
          programme, mais ne voulez pas que le processus s'arret,vous pouvez         
          utiliser le programme gcore. Voir la page de manuel en ligne de gcore(1)   
          pour plus d'informations.                                                  

5.5. Make

  5.5.1. Qu'est-ce que make?

   Quand vous travaillez sur un programme simple avec seulement un ou deux
   fichiers source, taper

 % cc fichier1.c fichier2.c
      

   n'est pas si mal, mais cela devient rapidement fastidieux quand il y a
   plusieurs fichiers-et cela peut prendre du temps `a compiler aussi.

   Une fac,on de contourner cela est d'utiliser les fichiers objet et de
   recompiler le fichier source seulement si le code source a change. Aussi,
   nous pourrions avoir quelque chose comme c,a:

 % cc fichier1.o fichier2.o ... fichier37.c ...
      

   si nous avions change le fichier fichier37.c mais aucun des autres depuis
   la dernere compilation. Cela pourrait accelerer assez bien la compilation
   mais cela ne resoud pas le probleme de la frappe au clavier.

   Ou nous pourrions ecrire une procedure pour resoudre ce probleme de
   frappe, mais celle-ci devrait tout re-compiler, devenant ainsi inefficace
   sur un gros projet.

   Que se passe-t-il si nous avons des centaines de fichiers source ? Que se
   passe-t-il si nous travaillons dans une equipe avec d'autres personnes qui
   oublient de nous dire quand ils ont change un de leurs fichiers source que
   nous utilisons ?

   Peut-etre pourrions nous mettre ensemble les deux solutions et ecrire
   quelque chose comme une procedure qui contiendrait quelque regle magique
   disant quand notre fichier source doit etre compile. Maintenant, tout ce
   dont nous avons besoin est un programme qui comprend ces regles, alors que
   c'est trop complique pour l'interpreteur.

   Ce programme s'appelle make. Il lit dans un fichier, appele un makefile,
   qui lui dit comment les differents fichiers dependent les uns des autres,
   et determine quels fichiers ont besoin d'etre recompiles et quels n'en ont
   pas besoin. Par exemple, une regle pourrait dire quelque chose comme << si
   fromboz.o est plus ancien que fromboz.c, cela signifie que quelqu'un a du
   changer fromboz.c, aussi il a besoin d'etre recompile. >> Le makefile
   possede aussi des regles pour dire `a make comment re-compiler un fichier
   source, en faisant ainsi un outil encore plus puissant.

   Les Makefiles sont typiquement stockes dans le meme repertoire que le
   source auxquels il s'appliquent, et peuvent etre appeles makefile,
   Makefile ou MAKEFILE. La plupart des programmeurs utilise le nom Makefile,
   celui-ci se trouvant proche du debut de la liste du contenu du repertoire
   ou il peut etre facilement vu. [7]

  5.5.2. Exemple d'utilisation de make

   Voici un exemple tres simple de Makefile:

 foo: foo.c
         cc -o foo foo.c

   Il consiste en deux lignes, une ligne de dependance et une ligne de
   creation.

   La ligne de dependance ici consiste en le nom du programme (connu comme
   cible), suivi de deux-points puis un espace et enfin le nom du fichier
   source. Quand make lit cette ligne, il verifie si foo existe; s'il existe,
   il compare la date `a laquelle foo a ete modifie la derniere fois avec la
   date de derniere modification de foo.c. Si foo n'existe pas ou est plus
   ancien que foo.c, il regarde la ligne de creation pour trouver ce qu'il
   doit faire. En d'autres termes, il s'agit de la regle `a utiliser quand
   foo.c a besoin d'etre re-compile.

   La ligne de creation commence avec un tab (appuyez sur la touche tab)
   suivi de la commande que vous taperiez pour creer foo si vous deviez le
   faire `a l'invite de commandes. Si foo n'est pas `a jour ou n'existe pas,
   make execute alors cette commande pour le creer. En d'autres termes, il
   s'agit de la regle permettant `a make de re-compiler foo.c.

   Aussi, quand vous tapez make, il verifiera que foo est `a jour en respect
   de vos derniers changements sur foo.c. Ce principe peut etre etendu `a des
   Makefiles de plusieurs centaines de cibles-en fait, sur FreeBSD, il est
   possible de compiler un systeme d'exploitation entier en tapant juste make
   world dans le repertoire approprie !

   Une autre propriete utile des makefiles est que les cibles n'ont pas
   necessairement besoin d'etre des programmes. Par exemple, nous pourrions
   avoir un Makefile qui ressemble `a cela:

 foo: foo.c
         cc -o foo foo.c

 install:
         cp foo /home/moi

   Nous pouvons dire `a make quelle cible nous voulons en tapant:

 % make cible
      

   make ira seulement voir cette cible et ingorera les autres. Par exemple,
   si nous tapons make foo avec le Makefile du dessus, make ignorera la cible
   install.

   Si nous tapons juste make, make regardera toujours la premiere cible et
   s'arretera sans regarder aucune autre. Aussi, si nous avions tape make
   seul, make serait juste alle `a la cible foo, aurait recompile foo si
   necessaire et se serait arrete sans aller `a la cible install.

   Notez que la cible install ne depend pour l'instant de rien ! Cela
   signifie que la commande qui suit est toujours executee lorsque nous
   essayons de creer cette cible en tapant make install. Dans ce cas, make va
   copier foo dans le repertoire de l'utilisateur. Cela est souvent utilise
   par les Makefiles des applications, ainsi l'application peut etre
   installee dans le repertoire correct quand elle a ete correctement
   compilee

   Il s'agit d'un sujet legerement embrouillant `a essayer et expliquer. Si
   vous ne comprenez pas bien comment make fonctionne, la meilleure chose `a
   faire est d'ecrire un petit programme comme << bonjour monde >> et un
   fichier Makefile comme le precedent et de le tester. Ensuite continuez en
   utilisant plus d'un fichier source ou en ayant un fichier source incluant
   un fichier d'en-tete. La commande touch est tres utile ici-elle change la
   date sur un fichier sans avoir `a l'editer.

  5.5.3. Les Makefilesde FreeBSD

   Les Makefiles peuvent etre plutot compliques `a ecrire. Heureusement, les
   systemes BSD comme FreeBSD sont fournis avec des fichiers tres puissants
   comme partie integrante du systeme. Un tres bon exemple est le systeme des
   logiciels portes. Voici la partie essentielle d'un Makefile typique des
   logiciels portes:

 MASTER_SITES=   ftp://freefall.cdrom.com/pub/FreeBSD/LOCAL_PORTS/
 DISTFILES=      scheme-microcode+dist-7.3-freebsd.tgz

 .include <bsd.port.mk>

   Maintenant, si nous allons dans le repertoire de ce logiciel porte et
   tapons make, la chose suivante se passe :

    1. Une verification est faite pour voir si le code source de ce logiciel
       porte est dej`a dans le systeme.

    2. Si celui-ci n'y est pas, une connexion FTP `a l'URL dans MASTER_SITES
       est faite pour telecharger le source.

    3. La somme de controle (checksum) du source est calculee et comparee
       avec celle d'une bonne et connue copie du source. Cela est fait pour
       etre sur que le source n'a pas ete corrompu pendant le transfert.

    4. Tout changement requis pour faire fonctionner le source sur FreeBSD
       est applique- cela est connu sous le nom de correctif[8].

    5. Toute configuration speciale necessaire pour le source est faite.
       (Beaucoup de distributions de programmes Unix essaye de fonctionner
       quelle que soit la version d'Unix sur laquelle elles sont compilees et
       quelles que soient les caracteristiques optionnelles qui sont
       presentes-c'est ce qui se trouve dans le scenario des logiciels portes
       pour FreeBSD).

    6. Le code source pour ce programme est compile. En effet, nous changeons
       de repertoire pour le repertoire ou le source a ete decompresse et
       faisons make-le fichier Makefile du programme contient les
       informations necessaires pour construire le programme.

    7. Nous avons maintenant une version compilee du programme. Si nous le
       desirons, nous pouvons le tester maintenant; quand nous sommes
       confiant dans le programme, nous pouvons taper make install. Cela va
       installer le programme et ses fichiers de soutien necessaires au bon
       endroit; une entree est aussi creee dans la base de donnees des
       logiciels pre-compiles, ainsi le logiciel porte peut etre facilement
       desinstalle plus tard si nous changeons d'avis sur ce programme.

   Maintenant je pense que vous serez d'accord que c'est plus impressionnant
   qu'une procedure de quatre lignes !

   Le secret reside dans la derniere ligne qui dit `a make de regarder dans
   le Makefile systeme appele bsd.port.mk. Il est facile de fermer les yeux
   sur cette ligne mais c'est ici que tous les trucs forts se
   passent-quelqu'un a ecrit un Makefile qui dit `a make de faire tout ce
   qu'il y a au-dessus (plus un couple d'autres choses que je n'ai pas
   mentionnees, comme la gestion des erreurs) et n'importe qui peut avoir
   acces `a cela simplement est ajoutant une simple ligne dans son propre
   fichier Makefile !

   Si vous voulez jeter un regard sur ces Makefiles systeme, ils se trouvent
   /usr/share/mk mais il est probablement mieux d'attendre un moment jusqu'`a
   ce que vous ayez un peu d'entrainement avec les Makefiles car ceux-ci sont
   tres compliques (et si vous les lisez, soyez sur d'avoir un thermos de
   cafe fort `a portee de main !)

  5.5.4. Utilisations plus avancees de make

   Make est un outil tres puissant et peut faire beaucoup plus que le simple
   exemple precedent ne l'a montre. Malheureusement, il y a differentes
   versions de make et elles different considerablement. Le meilleur moyen
   d'apprendre ce qu'elles peuvent faire est probablement de lire la
   documentation-heureusement cette introduction vous donnera la base `a
   partir de laquelle vous pourrez faire cela.

   La version de make fournies avec FreeBSD est le Berkeley make(make de
   Berkeley); il y a un cours d'instruction pour celui-ci dans
   /usr/share/doc/psd/12.make. Pour le voir, faites

 % zmore paper.ascii.gz
      

   dans ce repertoire.

   Beaucoup d'applications dans les logiciels portes utilisent GNU make, qui
   possede un tres bon ensemble de page d'<< info >>. Si vous avez installe
   un de ces logiciels portes, GNU make aura ete automatiquement installe
   sous le nom de gmake. Il est aussi disponible comme logiciel porte ou
   logiciel pre-compile seul.

   Pour voir les pages d'info pour GNU make, vous devrez editer le fichier
   dir dans le repertoire /usr/local/info pour ajouter une entree pour
   celui-ci. Cela implique d'ajouter une ligne

  * Make: (make).                 l'utilitaire GNU Make.

   au fichier. Une fois que vous avez fait ceci, vous pouvez taper info et
   ensuite selectionner make dans le menu (ou dans Emacs, faites C-h i).

5.6. Deverminer

  5.6.1. Le devermineur

   Le devermineur fourni avec FreeBSD est appele gdb (GNU debugger). Vous
   pouvez le demarrer en tapant

 % gdb nomprog
      

   bien que la plupart des gens preferent le demarrer au sein d'Emacs. Vous
   pouvez faire cela avec:

 M-x gdb RET nomprog RET
      

   Utiliser un devermineur vous permet d'executer le programme dans des
   circonstances plus controlees. Typiquement, vous pouvez executer le
   programme ligne `a ligne, inspecter la valeur des variables, changer cette
   derniere, dire au devermineur d'executer jusqu'`a un certain point puis de
   s'arreter etc... Vous pouvez meme vous brancher sur un programme en
   fonctionnement, ou charger un fichier core pour enqueter sur le plantage
   du programme. Il est meme possible de deverminer le noyau, quoique ce soit
   un peu plus ruse que de deverminer des applications utilisateur dont nous
   discuterons dans cette section.

   gdb dispose d'une assez bonne aide en ligne comme d'un ensemble de pages
   d'info, aussi cette section va se concentrer sur quelques commandes
   basiques.

   Finalement, si vous trouvez son interface texte non fonctionnelle, il y a
   une interface graphique pour celui-ci, xxgdb, dans la collection des
   logiciels portes.

   Cette section a pour but d'etre une introduction `a l'utilisation de gdb
   et ne couvre pas les sujets tres specialises comme le deverminage du
   noyau.

  5.6.2. Executer un programme dans le devermineur

   Vous devrez avoir compile le programme avec l'option -g pour avoir la
   meilleure utilisation de gdb. Il fonctionnera sans mais vous ne verrez que
   le nom de la fonction dans laquelle vous vous trouvez plutot que son code
   source. Si vous voyez une ligne comme:

 ... (no debugging symbols found) ...
      

   quand gdb demarre, vous saurez que le programme n'a pas ete compile avec
   l'option -g.

   A l'invite de gdb, tapez break main. Cela dira au devermineur de passer le
   code preliminaire d'initialisation du programme et de demarrer au debut de
   votre code. Maintenant tapez run pour demarrer le programme-cela va
   demarrer au debut du code d'initialisation et ensuite s'arretera lors de
   l'appel `a main(). (Si vous vous etes toujours demande ou main() etait
   appele, maintenant vous le savez !).

   Vous pouvez maintenant vous deplacer dans le programme ligne par ligne en
   pressant n. Si vous arrivez `a l'appel d'une fonction, vous pouvez entrer
   dans celle-ci en appuyant sur s. Une fois que vous etes dans l'appel de la
   fonction, vous pouvez retourner dans le code appelant en appuyant sur f.
   Vous pouvez aussi utiliser up et down pour avoir une vue rapide de
   l'appelant.

   Voici un exemple simple de comment detecter une erreur dans un programme
   avec gdb. Voici notre programme (avec une erreur deliberee):

 #include <stdio.h>

 int bazz(int anint);

 main() {
         int i;

         printf("C'est mon programme\n");
         bazz(i);
         return 0;
 }

 int bazz(int anint) {
         printf("Vous m'avez fourni %d\n", anint);
         return anint;
 }

   Le programme met i `a 5 et le passe `a une fonction bazz() qui imprime le
   nombre que nous lui avons donne.

   Puis nous compilons et executons le programme obtenu

 % cc -g -o temp temp.c
 % ./temp
 C'est mon programme
 Vous m'avez fourni 4231
      

   Ce n'etait pas ce que nous attendions ! Il est temps de voir ce qui se
   passe !

 % gdb temp
 GDB is free software and you are welcome to distribute copies of it
  under certain conditions; type "show copying" to see the conditions.
 There is absolutely no warranty for GDB; type "show warranty" for details.
 GDB 4.13 (i386-unknown-freebsd), Copyright 1994 Free Software Foundation, Inc.
 (gdb) break main                                passe le code d'initialisation
 Breakpoint 1 at 0x160f: file temp.c, line 9.    gdb met un point d'arret sur main()
 (gdb) run                                       Execute jusqu'`a main()
 Starting program: /home/james/tmp/temp          Le programme demarre

 Breakpoint 1, main () at temp.c:9               gdb s'arrete `a main()
 (gdb) n                                         Va `a la ligne suivante
 C'est mon programme                             Le programme ecrit
 (gdb) s                                         entre dans bazz()
 bazz (anint=4231) at temp.c:17                  gdb montre la pile
 (gdb)
      

   Arretons-nous une minute! Comment anint a eu la valeur 4231? Ne
   l'avons-nous pas mis `a 5 dans main()? Remontons dans main() et regardons.

 (gdb) up                                        Remonte la pile des appels
 #1  0x1625 in main () at temp.c:11              gdb montre la pile
 (gdb) p i                                       Montre la valeur de i
 $1 = 4231                                       gdb montre 4231
      

   Oh ! En regardant dans le code, nous avons oublie d'initialiser i. Nous
   aurions du mettre

 ...
 main() {
         int i;

         i = 5;
         printf("C'est mon programme\n");
 ...

   mais nous n'avions pas mis la ligne i=5;. Comme nous n'avons pas
   initialise i, il a pris le nombre se trouvant dans la zone de memoire
   quand le programme a demarre, ce qui dans ce cas etait 4231.

  Note:

   gdb montre la pile chaque fois que nous entrons ou sortons d'une fonction,
   meme si nous avons utilise up et down pour nous deplacer dans la pile des
   appels. Cela montre le nom de la fonction et les valeurs de ses arguments,
   ce qui nous aide `a garder une trace d'ou nous sommes et de ce qui se
   passe. (La pile est une zone de stockage ou le programme stocke les
   informations sur les arguments passes aux fonctions et ou il doit aller
   quand il revient d'une fonction).

  5.6.3. Examiner un fichier core

   Un fichier core est basiquement un fichier qui contient l'etat complet du
   processus quand il s'est plante. Dans << le bon vieux temps >>, les
   programmeurs devait imprimer des listings en hexadecimal de fichiers core
   et transpirer sur leur manuels de code machine, mais la vie est maintenant
   un peu plus facile. Par chance, sous FreeBSD et les autres systemes
   4.4BSD, un fichier core est appele nomprog.core plutot que juste core,
   pour mieux savoir `a quel programme appartient un fichier core.

   Pour examiner un fichier core, demarrez gdb de fac,on habituel. Plutot que
   de taper break ou run, tapez

 (gdb) core nomprog.core
      

   Si vous n'etes pas dans le meme repertoire que le fichier core, vous
   devrez faire dir /path/to/core/file d'abord.

   Vous devriez voir quelque chose comme cela:

 % gdb a.out
 GDB is free software and you are welcome to distribute copies of it
  under certain conditions; type "show copying" to see the conditions.
 There is absolutely no warranty for GDB; type "show warranty" for details.
 GDB 4.13 (i386-unknown-freebsd), Copyright 1994 Free Software Foundation, Inc.
 (gdb) core a.out.core
 Core was generated by `a.out'.
 Program terminated with signal 11, Segmentation fault.
 Cannot access memory at address 0x7020796d.
 #0  0x164a in bazz (anint=0x5) at temp.c:17
 (gdb)
      

   Dans ce cas, le programme a ete appele a.out, aussi le fichier core
   s'appelle a.out.core. Nous pouvons voir que le programme s'est plante car
   il a essaye d'acceder `a une zone dans la memoire qui n'etait pas
   disponible dans la fonction appelee bazz.

   Quelquefois il est utile de pouvoir voir comment une fonction a ete
   appelee car le probleme peut avoir eu lieu bien avant dans la pile des
   appels dans un programme complexe. La commande bt demande `a gdb
   d'afficher une trace inverse de la pile des appels:

 (gdb) bt
 #0  0x164a in bazz (anint=0x5) at temp.c:17
 #1  0xefbfd888 in end ()
 #2  0x162c in main () at temp.c:11
 (gdb)
      

   La fonction end() est appelee lorsque le programme se plante; dans ce cas,
   la fonction bazz() a ete appelee main().

  5.6.4. Se brancher sur un programme en cours d'execution

   Une des plus belles caracteristiques de gdb est qu'il peut se brancher sur
   un programme qui s'execute dej`a. Bien sur, cela suppose que vous ayez les
   privileges suffisants pour le faire. Un probleme habituel est quand vous
   vous deplacez dans un programme qui se dedouble et que vous voulez tracer
   le programme fils cependant le devermineur ne vous laissera seulement
   tracer le pere.

   Ce que vous devez faire est de demarrer un autre gdb, utiliser ps pour
   trouver l'ID du processus fils et faire

 (gdb) attach identifiant_processus
      

   dans gdb, et deverminer ensuite comme d'habitude.

   << C'est tout simple, >> pensez-vous certainement,<<  mais pendant le
   temps que je faisais c,a, le processus fils sera dej`a parti loin >>. Ne
   vous en faites pas, noble lecteur, voici comment faire (avec l'appui des
   pages d'info de gdb):

 ...
 if ((pid = fork()) < 0)         /* _Toujours_ verifier cela */
         error();
 else if (pid == 0) {            /* le fils */
         int PauseMode = 1;

         while (PauseMode)
                 sleep(10);      /* Attendre jusqu'a ce que quelqu'un se brache sur nous */
         ...
 } else {                        /* le pere */
         ...
      

   Maintenant tout ce que nous avons `a faire est de nous brancher sur le
   processus fils, de mettre PauseMode `a 0 et d'attendre que l'appel `a la
   fonction sleep() retourne !

5.7. Utiliser Emacs comme environnement de developpement

  5.7.1. Emacs

   Malheureusement, les systemes Unix ne sont pas fournis avec des sortes
   d'environnements de developpement integres
   tout-ce-que-vous-avez-toujours-voulu-et-beaucoup-plus-dans-un-ensemble-gigantesque
   que d'autres sytemes ont. [9] Toutefois, il est possible de se faire son
   propre environnement. Cela n'est pas forcement aussi joli et il peut ne
   pas etre autant integre mais vous pouvez le personnaliser comme vous
   voulez. Et c'est gratuit. Et vous en avez les sources.

   La cle de tout cela est Emacs. Maintenant il y a des gens qui le
   detestent, mais beaucoup l'aiment. Si vous etes un du premier groupe, j'ai
   peur que cette section ait peu d'interet pour vous. Vous aurez besoin
   d'une quantite moyenne de memoire pour le faire fonctionner-Je
   recommenderai 8Mo en mode texte et 16Mo dans X pour avoir un minimum de
   performances.

   Emacs est basiquement un editeur hautement personnalisable -en effet, il a
   ete personnalise au point de ressembler plus `a un systeme d'exploitation
   qu'`a un editeur! Beaucoup de developpeurs et d'administrateurs systeme
   passent en fait pratiquement tout leur temps `a travailler dans Emacs, en
   ne le quittant qu'`a leur deconnexion.

   Il est impossible de dire tout ce qu'Emacs peut faire ici, mais voici
   quelques unes des caracteristiques d'interet pour les developpeurs:

     * Un tres puissant editeur, permettant le chercher-remplacer sur les
       chaines et les expressions regulieres (motifs), sauter `a la fin ou au
       debut d'un bloc, etc, etc.

     * Menus deroulants et aide en ligne.

     * Colorisation syntaxique en fonction du langage et indentation.

     * Totalement personnalisable.

     * Vous pouvez compiler et deverminer des programmes dans Emacs.

     * Sur erreur de compilation, vous pouvez aller directement `a la ligne
       de code source fautive.

     * Une interface amicale au programme info utilise pour lire la
       documentation hypertexte GNU, incluant la documentation sur Emacs
       elle-meme.

     * Une interface agreable `a gdb, vous permettant de voir le code source
       au fur et `a mesure que vous vous deplacez dans votre programme.

     * Vous pouvez lire les nouvelles Usenet et envoyer des e-mails pendant
       que votre programme est en compilation.

   Et sans doute beaucoup plus que je n'ai survole.

   Emacs peut etre installe sur FreeBSD en utilisant Emacs le logiciel porte
   Emacs.

   Une fois installe, demarrez-le et faites C-h t pour lire un cours sur
   Emacs-cela signifie maintenir la touche control, presser h, relacher la
   touche control et presser t. (Alternativement, vous pouvez utiliser la
   souris pour selectionner Emacs Tutorial dans le menu Help).

   Bien que Emacs possede des menus, il est valable d'apprendre les
   raccourcis clavier, etant plus rapide quand vous editez quelque chose
   d'appuyer sur un couple de touches que de reprendre la souris et de
   cliquer au bon endroit. Et, quand vous discutez avec des utilisateurs
   experimentes d'Emacs, vous trouverez qu'ils parlent souvent de choses
   comme << M-x replace-s RET foo RET bar RET >> aussi il est utile de savoir
   ce que cela veut dire. Et dans tous les cas, Emacs possede beaucoup trop
   de fonctions pour qu'elles soient dans les barres de menus.

   Heureusement, il est assez simple de recuperer les raccourcis clavier car
   ils sont affiches `a cote des elements des menus deroulants. Mon conseil
   est d'utiliser un element de menu pour, disons, ouvrir un fichier jusqu'`a
   ce que vous sachiez comment cela fonctionne et que quand vous vous sentez
   `a l'aise avec, essayez C-x C-f. Quand vous serez content avec c,a, passez
   `a une autre commande du menu.

   Si vous ne pouvez pas vous rappeler de ce qu'une combinaison de touches
   particulieres fait, selectionnez Describe Key dans le menu Help et
   tapez-la-Emacs vous dira ce qu'elle fait. Vous pouvez aussi utiliser
   l'element de menu Command Apropos pour trouver toutes les commandes qui
   contiennent un mot particulier, avec leur raccourci clavier.

   De cette maniere, l'expression ci-dessus signifie maintenir la touche
   Meta, taper x, relacher la touche Meta, taper replace-s (raccourci pour
   replace-string- une autre caracteristique d'Emacs est que vous pouvez
   abreger les commandes), appuyer sur la touche Entree, taper foo (la chaine
   que vous voulez remplacer), presser la touche Entree, taper bar (la chaine
   que vous voulez substituer `a foo) puis appuyer sur Entree une derniere
   fois. Emacs va alors faire l'operation chercher-remplacer que vous avez
   demande.

   Si vous vous demandez ce qu'est cette touche Meta, il s'agit d'une touche
   speciale que beaucoup de stations de travail Unix possedent.
   Malheureusement, les PC n'en ont pas, aussi c'est habituellement la touche
   alt (ou si vous n'avez pas de chance, la touche echap).

   Oh, et pour sortir d'Emacs, faites C-x C-c (ce qui signifie maintenir la
   touche control appuyee, appuyer c et relacher la touche control. Si vous
   avez des fichiers non sauvegardes ouverts, Emacs vous demandera si vous
   voulez les sauvegarder. (Ignorez le bout de documentation ou il est dit
   que C-z est la maniere habituelle de quitter Emacs- qui quitte Emacs en le
   laissant tourner en tache de fond et qui n'est vraiment utile que si vous
   avez un systeme sans terminal virtuel).

  5.7.2. Configurer Emacs

   Emacs fait des choses merveilleuses; une partie est integree directement,
   une autre doit etre configuree.

   Plutot que d'utiliser un macro langage proprietaire pour la configuration,
   Emacs utilise une version du Lisp specialement adaptee pour les editeurs,
   connue sous le nom d'Emacs Lisp. Celui-ci peut etre assez utile si vous
   voulez poursuivre et apprendre quelque chose comme le Common Lisp, car il
   est considerablement plus petit que le Common Lisp (bien que dej`a assez
   gros!).

   La meilleure fac,on d'apprendre l'Emacs Lisp est de telecharger le cours
   d'Emacs

   Toutefois, il n'y a pas besoin de connaitre le Lisp pour commencer la
   configuration d'Emacs, car j'ai inclus un exemple de fichier .emacs qui
   devrait etre suffisant pour commencer. Copiez juste celui-ci dans votre
   repertoire utilisateur et redemarrez Emacs si celui-ci s'execute, il lira
   les commandes du fichier et (si tout va bien!) vous donnera une
   configuration basique utile.

  5.7.3. Un fichier exemple .emacs

   Malheureusement, il y a beaucoup trop de choses ici pour les expliquer en
   detail; toutefois, il y a un ou deux points qui valent d'etre mentionnes.

     * Tout ce qui commence avec un ; est un commentaire et est ignore par
       Emacs.

     * A la premiere ligne, le -*- Emacs-Lisp -*- est tel que vous pouvez
       editer le fichier .emacs lui-meme `a l'interieur d'Emacs et d'obtenir
       tous les fantaisistes dispositifs pour l'edition en Emacs Lisp. Emacs
       essaye habituellement de deviner cela en se basant sur le nom du
       fichier, et ne trouvera peut-etre pas pour .emacs.

     * La touche tab est liee `a la fonction d'indentation dans certains
       modes, aussi quand vous l'enfoncez, cela va indenter la ligne courante
       de code. Si vous voulez mettre un caractere tab dans quoique ce soit
       que vous tapiez, maintenez la touche control enfoncee pendant que vous
       appuyez sur tab.

     * Ce fichier supporte la colorisation de syntaxe pour les langages C,
       C++, Perl, Lisp et Scheme en devinant le langage par leur nom.

     * Emacs possede dej`a une fonction pre-definie appelee next-error. Dans
       la fenetre de sortie d'une compilation, cela vous permet de vous
       deplacer d'une erreur de compilation `a la suivante en faisant M-n;
       nous definissons une fonction complementaire previous-error, qui vous
       permet d'aller `a l'erreur precedente en faisant M-p. Le plus beau
       dispositif de tous est que C-c C-c va ouvrir le fichier source dans
       lequel l'erreur a eu lieu et sautera `a la ligne appropriee.

     * Nous autorisons la capacite d'Emacs `a agir comme un serveur ainsi si
       vous faites quelque chose en dehors d'Emacs et voulez editer un
       fichier, tapez juste

 % emacsclient nomfichier
          

       et alors vous pouvez editer le fichier dans votre Emacs! [10]

   Exemple 5.1. Un fichier exemple .emacs

 ;; -*-Emacs-Lisp-*-

 ;; Ce fichier est concu pour etre reevalue, utiliser la variable first-time
 ;; pour eviter tout probleme.
 (defvar first-time t
   "Valeur signifiant que c'est la premiere fois que .emacs a ete evalue"
   )

 ;; Meta
 (global-set-key "\M- " 'set-mark-command)
 (global-set-key "\M-\C-h" 'backward-kill-word)
 (global-set-key "\M-\C-r" 'query-replace)
 (global-set-key "\M-r" 'replace-string)
 (global-set-key "\M-g" 'goto-line)
 (global-set-key "\M-h" 'help-command)

 ;; Function keys
 (global-set-key [f1] 'manual-entry)
 (global-set-key [f2] 'info)
 (global-set-key [f3] 'repeat-complex-command)
 (global-set-key [f4] 'advertised-undo)
 (global-set-key [f5] 'eval-current-buffer)
 (global-set-key [f6] 'buffer-menu)
 (global-set-key [f7] 'other-window)
 (global-set-key [f8] 'find-file)
 (global-set-key [f9] 'save-buffer)
 (global-set-key [f10] 'next-error)
 (global-set-key [f11] 'compile)
 (global-set-key [f12] 'grep)
 (global-set-key [C-f1] 'compile)
 (global-set-key [C-f2] 'grep)
 (global-set-key [C-f3] 'next-error)
 (global-set-key [C-f4] 'previous-error)
 (global-set-key [C-f5] 'display-faces)
 (global-set-key [C-f8] 'dired)
 (global-set-key [C-f10] 'kill-compilation)

 ;; Keypad bindings
 (global-set-key [up] "\C-p")
 (global-set-key [down] "\C-n")
 (global-set-key [left] "\C-b")
 (global-set-key [right] "\C-f")
 (global-set-key [home] "\C-a")
 (global-set-key [end] "\C-e")
 (global-set-key [prior] "\M-v")
 (global-set-key [next] "\C-v")
 (global-set-key [C-up] "\M-\C-b")
 (global-set-key [C-down] "\M-\C-f")
 (global-set-key [C-left] "\M-b")
 (global-set-key [C-right] "\M-f")
 (global-set-key [C-home] "\M-<")
 (global-set-key [C-end] "\M->")
 (global-set-key [C-prior] "\M-<")
 (global-set-key [C-next] "\M->")

 ;; Souris
 (global-set-key [mouse-3] 'imenu)

 ;; Divers
 (global-set-key [C-tab] "\C-q\t")       ; Control tab quotes a tab.
 (setq backup-by-copying-when-mismatch t)

 ;; Traite 'y' ou <CR> comme yes, 'n' comme no.
 (fset 'yes-or-no-p 'y-or-n-p)
     (define-key query-replace-map [return] 'act)
     (define-key query-replace-map [?\C-m] 'act)

 ;; Charge les ajouts
 (require 'desktop)
 (require 'tar-mode)

 ;; Diff mode sympa
 (autoload 'ediff-buffers "ediff" "Intelligent Emacs interface to diff" t)
 (autoload 'ediff-files "ediff" "Intelligent Emacs interface to diff" t)
 (autoload 'ediff-files-remote "ediff"
   "Intelligent Emacs interface to diff")

 (if first-time
     (setq auto-mode-alist
           (append '(("\\.cpp$" . c++-mode)
                     ("\\.hpp$" . c++-mode)
                     ("\\.lsp$" . lisp-mode)
                     ("\\.scm$" . scheme-mode)
                     ("\\.pl$" . perl-mode)
                     ) auto-mode-alist)))

 ;; Mode de verrouillage automatique de la police de caracteres
 (defvar font-lock-auto-mode-list
   (list 'c-mode 'c++-mode 'c++-c-mode 'emacs-lisp-mode 'lisp-mode 'perl-mode 'scheme-mode)
   "List of modes to always start in font-lock-mode")

 (defvar font-lock-mode-keyword-alist
   '((c++-c-mode . c-font-lock-keywords)
     (perl-mode . perl-font-lock-keywords))
   "Associations between modes and keywords")

 (defun font-lock-auto-mode-select ()
   "Automatically select font-lock-mode if the current major mode is
 in font-lock-auto-mode-list"
   (if (memq major-mode font-lock-auto-mode-list)
       (progn
         (font-lock-mode t))
     )
   )

 (global-set-key [M-f1] 'font-lock-fontify-buffer)

 ;; New dabbrev stuff
 ;(require 'new-dabbrev)
 (setq dabbrev-always-check-other-buffers t)
 (setq dabbrev-abbrev-char-regexp "\\sw\\|\\s_")
 (add-hook 'emacs-lisp-mode-hook
           '(lambda ()
              (set (make-local-variable 'dabbrev-case-fold-search) nil)
              (set (make-local-variable 'dabbrev-case-replace) nil)))
 (add-hook 'c-mode-hook
           '(lambda ()
              (set (make-local-variable 'dabbrev-case-fold-search) nil)
              (set (make-local-variable 'dabbrev-case-replace) nil)))
 (add-hook 'text-mode-hook
           '(lambda ()
              (set (make-local-variable 'dabbrev-case-fold-search) t)
              (set (make-local-variable 'dabbrev-case-replace) t)))

 ;; mode C++ et C...
 (defun my-c++-mode-hook ()
   (setq tab-width 4)
   (define-key c++-mode-map "\C-m" 'reindent-then-newline-and-indent)
   (define-key c++-mode-map "\C-ce" 'c-comment-edit)
   (setq c++-auto-hungry-initial-state 'none)
   (setq c++-delete-function 'backward-delete-char)
   (setq c++-tab-always-indent t)
   (setq c-indent-level 4)
   (setq c-continued-statement-offset 4)
   (setq c++-empty-arglist-indent 4))

 (defun my-c-mode-hook ()
   (setq tab-width 4)
   (define-key c-mode-map "\C-m" 'reindent-then-newline-and-indent)
   (define-key c-mode-map "\C-ce" 'c-comment-edit)
   (setq c-auto-hungry-initial-state 'none)
   (setq c-delete-function 'backward-delete-char)
   (setq c-tab-always-indent t)
 ;; Style d'indentation BSD
   (setq c-indent-level 4)
   (setq c-continued-statement-offset 4)
   (setq c-brace-offset -4)
   (setq c-argdecl-indent 0)
   (setq c-label-offset -4))

 ;; mode Perl
 (defun my-perl-mode-hook ()
   (setq tab-width 4)
   (define-key c++-mode-map "\C-m" 'reindent-then-newline-and-indent)
   (setq perl-indent-level 4)
   (setq perl-continued-statement-offset 4))

 ;; mode Scheme...
 (defun my-scheme-mode-hook ()
   (define-key scheme-mode-map "\C-m" 'reindent-then-newline-and-indent))

 ;; mode Emacs-Lisp...
 (defun my-lisp-mode-hook ()
   (define-key lisp-mode-map "\C-m" 'reindent-then-newline-and-indent)
   (define-key lisp-mode-map "\C-i" 'lisp-indent-line)
   (define-key lisp-mode-map "\C-j" 'eval-print-last-sexp))

 ;; Ajoute tout le reste...
 (add-hook 'c++-mode-hook 'my-c++-mode-hook)
 (add-hook 'c-mode-hook 'my-c-mode-hook)
 (add-hook 'scheme-mode-hook 'my-scheme-mode-hook)
 (add-hook 'emacs-lisp-mode-hook 'my-lisp-mode-hook)
 (add-hook 'lisp-mode-hook 'my-lisp-mode-hook)
 (add-hook 'perl-mode-hook 'my-perl-mode-hook)

 ;; Le complement a next-error
 (defun previous-error (n)
   "Visit previous compilation error message and corresponding source code."
   (interactive "p")
   (next-error (- n)))

 ;; Divers...
 (transient-mark-mode 1)
 (setq mark-even-if-inactive t)
 (setq visible-bell nil)
 (setq next-line-add-newlines nil)
 (setq compile-command "make")
 (setq suggest-key-bindings nil)
 (put 'eval-expression 'disabled nil)
 (put 'narrow-to-region 'disabled nil)
 (put 'set-goal-column 'disabled nil)

 ;; Recherche des archives Elisp
 (autoload 'format-lisp-code-directory "lispdir" nil t)
 (autoload 'lisp-dir-apropos "lispdir" nil t)
 (autoload 'lisp-dir-retrieve "lispdir" nil t)
 (autoload 'lisp-dir-verify "lispdir" nil t)

 ;; Mode de verrouillage de police
 (defun my-make-face (face colour &optional bold)
   "Create a face from a colour and optionally make it bold"
   (make-face face)
   (copy-face 'default face)
   (set-face-foreground face colour)
   (if bold (make-face-bold face))
   )

 (if (eq window-system 'x)
     (progn
       (my-make-face 'blue "blue")
       (my-make-face 'red "red")
       (my-make-face 'green "dark green")
       (setq font-lock-comment-face 'blue)
       (setq font-lock-string-face 'bold)
       (setq font-lock-type-face 'bold)
       (setq font-lock-keyword-face 'bold)
       (setq font-lock-function-name-face 'red)
       (setq font-lock-doc-string-face 'green)
       (add-hook 'find-file-hooks 'font-lock-auto-mode-select)

       (setq baud-rate 1000000)
       (global-set-key "\C-cmm" 'menu-bar-mode)
       (global-set-key "\C-cms" 'scroll-bar-mode)
       (global-set-key [backspace] 'backward-delete-char)
                                         ;      (global-set-key [delete] 'delete-char)
       (standard-display-european t)
       (load-library "iso-transl")))

 ;; X11 ou PC utilisant les ecritures directes a l'ecran
 (if window-system
     (progn
       ;;      (global-set-key [M-f1] 'hilit-repaint-command)
       ;;      (global-set-key [M-f2] [?\C-u M-f1])
       (setq hilit-mode-enable-list
             '(not text-mode c-mode c++-mode emacs-lisp-mode lisp-mode
                   scheme-mode)
             hilit-auto-highlight nil
             hilit-auto-rehighlight 'visible
             hilit-inhibit-hooks nil
             hilit-inhibit-rebinding t)
       (require 'hilit19)
       (require 'paren))
   (setq baud-rate 2400)                 ; For slow serial connections
   )

 ;; Terminal de type TTY
 (if (and (not window-system)
          (not (equal system-type 'ms-dos)))
     (progn
       (if first-time
           (progn
             (keyboard-translate ?\C-h ?\C-?)
             (keyboard-translate ?\C-? ?\C-h)))))

 ;; Sous Unix
 (if (not (equal system-type 'ms-dos))
     (progn
       (if first-time
           (server-start))))

 ;; Add any face changes here
 (add-hook 'term-setup-hook 'my-term-setup-hook)
 (defun my-term-setup-hook ()
   (if (eq window-system 'pc)
       (progn
 ;;      (set-face-background 'default "red")
         )))

 ;; Restaure le  "desktop" - faire cela le plus tard possible
 (if first-time
     (progn
       (desktop-load-default)
       (desktop-read)))

 ;; Indique que ce fichier a ete lu au moins une fois
 (setq first-time nil)

 ;; Pas besoin de deverminer quoique ce soit maintenant

 (setq debug-on-error nil)

 ;; Tout est fait
 (message "All done, %s%s" (user-login-name) ".")
        

  5.7.4. Etendre la palette de langages qu'Emacs comprend

   Maintenant, Emacs est tres bien si vous voulez seulement programmer dans
   des langages dej`a fournis dans le fichier .emacs (C, C++, Perl, Lisp et
   Scheme), mais qu'arrive-t-il si un nouveau langage appele << whizbang >>
   sort, plein d'excitantes fonctionnalites ?

   La premiere chose `a faire est de savoir si whizbang est fourni avec des
   fichiers de configuration pour Emacs. Ceux-ci se terminent habituellement
   par .el, raccourci pour << Emacs Lisp >>. Par exemple, si whizbang est un
   logiciel porte FreeBSD, nous pouvons localiser ces fichiers en faisant

 % find /usr/ports/lang/whizbang -name "*.el" -print
      

   et les installer en les copiant dans le repertoire Lisp d'Emacs. Sur
   FreeBSD 2.1.0-RELEASE, il s'agit de /usr/local/share/emacs/site-lisp [11].

   Aisni par exemple, si la sortie de la commande find etait

 /usr/ports/lang/whizbang/work/misc/whizbang.el
      

   nous ferions

 # cp /usr/ports/lang/whizbang/work/misc/whizbang.el /usr/local/share/emacs/site-lisp
      

   Ensuite, nous devons decider quel extension les fichiers source whizbang
   ont. Disons qu'il s'agit de fichiers se terminant par .wiz. Nous devons
   ajouter une entree dans notre fichier .emacs pour etre sur qu'Emacs sera
   capable d'utiliser les informations dans whizbang.el.

   Trouvez l'entree auto-mode-alist dans .emacs et ajoutez une ligne pour
   whizbang, comme :

 ...
 ("\\.lsp$" . lisp-mode)
 ("\\.wiz$" . whizbang-mode)
 ("\\.scm$" . scheme-mode)
 ...

   Cela signifie qu'Emacs ira automatiquement dans la fonction whizbang-mode
   quand vous editerez un fichier se terminant par .wiz.

   Juste en-dessous, vous trouverez l'entree font-lock-auto-mode-list.
   Ajoutez whizbang-mode `a celle-ci comme ceci :

 ;; Auto font lock mode
 (defvar font-lock-auto-mode-list
   (list 'c-mode 'c++-mode 'c++-c-mode 'emacs-lisp-mode 'whizbang-mode 'lisp-mode 'perl-mode 'scheme-mode)
   "List of modes to always start in font-lock-mode")

   Cela signifie qu'Emacs autorisera toujours font-lock-mode (ie colorisation
   de la syntaxe) pendant l'edition d'un fichier .wiz.

   Et c'est tout ce qui est necessaire. S'il y a quoique ce soit que vous
   voulez de fait automatiquement quand vous ouvrez un fichier .wiz, vous
   pouvez ajouter un whizbang-mode hook (voir my-scheme-mode-hook pour un
   exemple simple qui ajoute auto-indent, l'auto-indentation).

5.8. Pour aller plus loin

     * Brian Harvey and Matthew Wright Simply Scheme MIT 1994. ISBN
       0-262-08226-8

     * Randall Schwartz Learning Perl O'Reilly 1993 ISBN 1-56592-042-2

     * Patrick Henry Winston and Berthold Klaus Paul Horn Lisp (3rd Edition)
       Addison-Wesley 1989 ISBN 0-201-08319-1

     * Brian W. Kernighan and Rob Pike The Unix Programming Environment
       Prentice-Hall 1984 ISBN 0-13-937681-X

     * Brian W. Kernighan and Dennis M. Ritchie The C Programming Language
       (2nd Edition) Prentice-Hall 1988 ISBN 0-13-110362-8

     * Bjarne Stroustrup The C++ Programming Language Addison-Wesley 1991
       ISBN 0-201-53992-6

     * W. Richard Stevens Advanced Programming in the Unix Environment
       Addison-Wesley 1992 ISBN 0-201-56317-7

     * W. Richard Stevens Unix Network Programming Prentice-Hall 1990 ISBN
       0-13-949876-1

     ----------------------------------------------------------------------

   [1] Si vous l'executer `a l'invite de commande, vous pouvez recevoir un
   fichier d'image memoire (NDT: le desormais celebre "core dump").

   [2] Pour etre vraiment precis, cc convertit `a ce niveau le code source
   dans son propre p-code independant de la machine plutot qu'en langage
   assembleur.

   [3] Au cas ou vous ne le sauriez pas, un tri binaire est un maniere
   efficace de trier les elements et le tri `a bulles n'en est pas une.

   [4] Les raisons de ceci sont enterrees dans les brumes de l'histoire.

   [5] Notez, nous n'avons pas utilise l'option -o pour specifier le nom de
   l'executable, aussi nous obtiendrons un executable du nom de a.out.
   Produire une version de deverminage du nom de foobar est laisse en
   exercice pour le lecteur!

   [6] NDT: je n'ai pas trouve de meilleure traduction pour core memory

   [7] Ils n'utilisent pas la forme MAKEFILE car les bloques de majuscules
   sont souvent utilises pour les fichiers de documentation comme README.

   [8] NDT: On entendra plus souvent parler de patch.

   [9] Sauf si vous payez des sommes importantes.

   [10] Beaucoup d'utilisateurs d'Emacs mettent leur variable d'environnement
   EDITOR `a emacsclient ainsi cela se passe `a chaque fois qu'ils ont besoin
   d'editer un fichier.

   [11] NDT : Sur FreeBSD 4.2-RELEASE aussi.

Chapitre 6. Programmation securisee

   Table des matieres

   6.1. Synopsis

   6.2. Methodologie de developpement securise

   6.3. Depassement de capacite

   6.4. Les problemes lies `a SetUID

   6.5. Limiter l'environnement de votre programme

   6.6. La confiance

   6.7. Les conditions de course

   Ce chapitre a ete ecrit par Murray Stokely.

6.1. Synopsis

   Ce chapitre decrit quelques problemes de securite qui ont tourmente les
   programmeurs Unix depuis des dizaines d'annees et quelques uns des
   nouveaux outils disponibles pour aider les programmeurs `a eviter
   l'ecriture de code non securise.

6.2. Methodologie de developpement securise

   Ecrire des applications securisees demande une tres minutieuse et
   pessimiste vision de la vie. Les applications devrait fonctionner avec le
   principe du << privilege moindre >> de fac,on `a ce qu'aucun processus ne
   fonctionne avec plus que le strict minimum dont il a besoin pour accomplir
   sa tache. Le code pre-teste devrait etre reutilise autant que possible
   pour eviter les erreurs communes que d'autres peuvent dej`a avoir
   reparees.

   Un des pieges de l'environnement Unix est qu'il est facile d'affecter la
   stabilite de l'environnement. Les applications ne devraient jamais avoir
   confiance dans la saisie de l'utilisateur (sous toutes ses formes), les
   ressources systeme, la communication inter-processus, ou l'enchainement
   des evenements. Les processus Unix n'executent pas de maniere synchrone
   aussi, logiquement, les operations sont rarement atomiques.

6.3. Depassement de capacite

   Les depassements de capacite ("Buffer Overflows") existent depuis les
   debuts de l'architecture de Von-Neuman 1. Ils gagnerent une grande
   notoriete en 1988 avec le ver pour Internet de Morris. Malheureusement, la
   meme attaque basique reste effective aujourd'hui. Des 17 rapports de
   securite du CERT de 1999, 10 furent causes directement des bogues
   logiciels de depassement de capacite. De loin la plus commune de types
   d'attaques par depassement de capacite est basee sur la corruption de la
   pile.

   La plupart des systemes informatiques modernes utilise une pile pour
   passer les arguments aux procedures et stocker les variables locales Une
   pile est une zone memoire dernier entre-premier sorti (Last In-First Out :
   LIFO) dans la zone de memoire haute de l'image d'un processus. Quand un
   programme invoque une fonction une nouvelle structure pile est creee.
   Cette structure pile consiste dans les arguments passes `a la fonction
   aussi bien que dans une quantite dynamique d'espace pour la variable
   locale. Le pointeur de pile est un registre qui reference la position
   courante du sommet de la pile. Etant donne que cette valeur change
   constamment au fur et `a mesure que de nouvelles valeurs sont ajoutees au
   sommet de la pile, beaucoup d'implementations fournissent aussi un
   pointeur de structure qui est positionne dans le voisinage du debut de la
   structure pile de fac,on `a ce que les variables locales soient plus
   facilement adressables relativement `a cette valeur. 1 L'adresse de retour
   des appels de fonction est aussi stocke dans la pile, et cela est la cause
   des decouvertes des depassements de pile puisque faire deborder une
   variable locale dans une fonction peut ecraser l'adresse de retour de
   cette fonction, permettant potentiellement `a un utilisateur malveillant
   d'executer le code qu'il ou elle desire.

   Bien que les attaques basees sur les depassements de pile soient de loin
   les plus communes, il serait aussi possible de faire exploser la pile avec
   une attaque du tas (malloc/free).

   Le langage de programmation C ne realise pas de verifications automatiques
   des limites sur les tableaux ou pointeurs comme d'autres langages le font.
   De plus, la librairie standard du C est remplie d'une poignee de fonctions
   tres dangereuses.

   +------------------------------------------------------------------------+
   | strcpy(char *dest, const char *src)          | Peut faire deborder le  |
   |                                              | tampon dest             |
   |----------------------------------------------+-------------------------|
   | strcat(char *dest, const char *src)          | Peut faire deborder le  |
   |                                              | tampon dest             |
   |----------------------------------------------+-------------------------|
   | getwd(char *buf)                             | Peut faire deborder le  |
   |                                              | tampon buf              |
   |----------------------------------------------+-------------------------|
   | gets(char *s)                                | Peut faire deborder le  |
   |                                              | tampon s                |
   |----------------------------------------------+-------------------------|
   | [vf]scanf(const char *format, ...)           | Peut faire deborder ses |
   |                                              | arguments.              |
   |----------------------------------------------+-------------------------|
   | realpath(char *path, char resolved_path[])   | Peut faire deborder le  |
   |                                              | tampon path             |
   |----------------------------------------------+-------------------------|
   | [v]sprintf(char *str, const char *format,    | Peut faire deborder le  |
   | ...)                                         | tampon str.             |
   +------------------------------------------------------------------------+

  6.3.1. Exemple de depassement de capacite

   L'exemple de code suivant contient un depassement de capacite conc,u pour
   ecraser l'adresse de retour et "sauter" l'instruction suivant
   immediatement l'appel de la fonction. (Inspire par 4)

 #include stdio.h

 void manipulate(char *buffer) {
   char newbuffer[80];
   strcpy(newbuffer,buffer);
 }

 int main() {
   char ch,buffer[4096];
   int i=0;

   while ((buffer[i++] = getchar()) != '\n') {};

   i=1;
   manipulate(buffer);
   i=2;
   printf("La valeur de i est : %d\n",i);
   return 0;
 }

   Examinons quel serait l'aspect de l'image memoire de ce processus si nous
   avions entre 160 espaces dans notre petit programme avant d'appuyer sur
   Entree.

   [XXX Schema ici!]

   Evidemment une entree plus malveillante pourrait etre imaginee pour
   executer des instructions dej`a compilees (comme exec(/bin/sh)).

  6.3.2. Eviter les depassements de capacite

   La solution la plus simple au probleme de debordement de pile est de
   toujours utiliser de la memoire restreinte en taille et les fonctions de
   copie de chaine de caracteres. strncpy et strncat font parties de la
   libraire standard du C. Ces fonctions acceptent une valeur de longueur
   comme parametre qui qui ne devrait pas etre plus grande que la taille du
   tampon de destination. Ces fonctions vont ensuite copier `taille' octets
   de la source vers la destination. Toutefois, il y a un certain nombre de
   problemes avec ces fonctions. Aucune fonction ne garantit une terminaison
   par le caractere NULL si la taille du tampon d'entree est aussi grand que
   celui de destination. Le parametre taille est aussi utilise de fac,on
   illogique entre strncpy et strncat aussi il est facile pour les
   programmeurs d'etre deroutes sur leur utilisation convenable. Il y a aussi
   une perte significative des performances compare `a strcpy lorsque l'on
   copie une courte chaine dans un grand tampon puisque strncpy remplit de
   caracteres NULL jusqu'`a la taille specifiee.

   Dans OpenBSD, une autre implementation de la copie de memoire a ete creee
   pour contourner ces problemes. Les fonctions strlcpy et strlcat
   garantissent qu'elles termineront toujours le tampon de destination par un
   caractere NULL losque l'argument de taille est different de zero. Pour
   plus d'informations sur ces fonctions, voir 6. Les fonctions strlcpy et
   strlcat d'OpenBSD ont ete inclues dans FreeBSD depuis la version 3.5.

    6.3.2.1. V#233;rifications des limites en fonctionnement basees sur le
    compilateur

   Malheureusement il y a toujours un tres important assortiment de code en
   utilisation publique qui copie aveuglement la memoire sans utiliser une
   des routines de copie limitee dont nous venons juste de discuter.
   Heureusement, il y a une autre solution. Plusieurs produits
   complementaires pour compilateur et librairies existent pour faire de la
   verification de limites pendant le fonctionnement en C/C++.

   StackGuard est un de ces produits qui est implemente comme un petit
   correctif ("patch") pour le generateur de code gcc. Extrait du site
   Internet de StackGuard, http://immunix.org/stackguard.html :

     "StackGuard detecte et fait echouer les attaques par debordement de pile
     en empechant l'adresse de retour sur la pile d'etre alteree. StackGuard
     place un mot "canari" [12] `a cote de l'adresse de retour quand la
     fontion est appelee. Si le mot "canari" a ete altere au retour de la
     fonction, alors une attaque par debordement de pile a ete tentee et le
     programme repond en envoyant une alerte d'intrusion dans la trace
     systeme (syslog) et s'arrete alors."

     "StackGuard est implemente comme un petit correctif au generateur de
     code gcc, specifiquement sur les routines function_prolog() et
     function_epilog(). function_prolog() a ete ameliore pour laisser des
     "canaris" sur la pile quand les fonctions demarrent, et function_epilog
     verifie l'integrite des "canaris" quand la fonction se termine. Tout
     essai pour corrompre l'adresse de retour est alors detectee avant que la
     fonction ne retourne."

   Recompiler votre application avec StackGuard est un moyen efficace pour
   stopper la plupart des attques par depassement de capacite, mais cela peut
   toujours etre compromis.

    6.3.2.2. Verifications des limites en fonctionnement basees sur les
    librairies

   Les mecanismes bases sur le compilateur sont totalement inutiles pour
   logiciel seulement binaire que vous ne pouvez recompiler. Pour ces
   situations, il existe un nombre de librairies qui re-implemente les
   fonctions peu sures de la librairie C (strcpy, fscanf, getwd, etc..) et
   assurent que ces fonctions ne peuvent pas ecrire plus loin que le pointeur
   de pile.

     * libsafe
     * libverify
     * libparnoia

   Malheureusement ces defenses basees sur les librairies possedent un
   certain nombre de defauts. Ces librairies protegent seulement d'un tres
   petit ensemble de problemes lies `a la securite et oublient de reparer le
   probleme actuel. Ces defenses peuvent echouer si l'application a ete
   compilee avec -fomit-frame-pointer. De meme, les variables d'environnement
   LD_PRELOAD et LD_LIBRARY_PATH peuvent etre reecrites/non definies par
   l'utilisateur.

6.4. Les problemes lies `a SetUID

   Il y a au moins 6 differents ID (identifiants) associes `a un processus
   donne. A cause de cela, vous devez etre tres attentif avec l'acces que
   votre processus possede `a un instant donne. En particulier, toutes les
   applications ayant rec,u des privileges par seteuid doivent les abandonnes
   des qu'ils ne sont plus necessaires.

   L'identifiant de l'utilisateur reel (real user ID) peut seulement etre
   change par un processus super-utilisateur. Le programme login met celui `a
   jour quand un utilisateur se connecte et il est rarement change.

   L'identifiant de l'utilisateur effectif (effective user ID) est mis `a
   jour par les fonctions exec() si un programme possede son bit seteuid
   place. Une application peut appeler seteuid() `a n'importe quel moment
   pour regler l'identifiant de l'utilisateur effectif sur l'identifiant d'un
   utilisateur reel ou sur le "set-user-ID" sauve. Quand l'identifiant de
   l'utilisateur effectif est place par les fonctions exec(), la valeur
   precedente est sauvee dans le "set-user-ID" sauve.

6.5. Limiter l'environnement de votre programme

   La methode traditionnelle pour restreindre l'acces d'un processus se fait
   avec l'appel systeme chroot(). Cet appel systeme change le repertoire
   racine depuis lequel tous les autres chemins sont references pour un
   processus et ses fils. Pour que cet appel reussisse, le processus doit
   avoir execute (recherche) la permission dans le repertoire reference. Le
   nouvel environnement environment ne prend pas effet que lorsque vous
   appelez chdir() dans celui-ci. Il doit etre aussi note qu'un processus
   peut facilement s'echapper d'un environnement chroot s'il a les privileges
   du super-utilisateur. Cela devrait etre accompli en creant des fichiers
   speciaux de peripherique pour la memoire du noyau, en attachant un
   devermineur `a un processus depuis l'exterieur de sa "prison", ou par
   d'autres manieres creatrices.

   Le comportement de l'appel systeme chroot() peut etre un peu controle avec
   la commande sysctl et la variable kern.chroot_allow_open_directories.
   Quand cette valeur est reglee `a 0, chroot() echouera avec EPERM s'il y a
   un repertoire d'ouvert. Si la variable est reglee sur la valeur par defaut
   1, alors chroot() echouera avec EPERM s'il y a un repertoire d'ouvert et
   que le processus est dej`a sujet `a un appel chroot(). Pour toute autre
   valeur, la verification des repertoires ouverts sera totalement
   court-circuitee.

  6.5.1. La fonctionnalite "prison" de FreeBSD

   Le concept de Prison ("Jail") etend chroot() en limitant les droits du
   super-utilisateur pour creer un veritable `serveur virtuel'. Une fois
   qu'une prison est mise en place, toute communication reseau doit avoir
   lieu au travers de l'adresse IP specifiee, et le droit du "privilege
   super-utilisateur" dans cette prison est severement gene.

   Tant qu'il se trouve en prison, tout test avec les droits du
   super-utilisateur dans le noyau au travers d'un appel `a suser() echouera.
   Toutefois, quelques appels `a suser() ont ete changes par la nouvelle
   interface suser_xxx(). Cette fonction est responsable de fournir ou de
   retirer les acces aux droits du super-utilisateur pour les processus
   emprisonnes.

   Un processus super-utilisateur dans un environnement emprisonne a le
   pouvoir de :

     * Manipuler les identitifications avec setuid, seteuid, setgid, setegid,
       setgroups, setreuid, setregid, setlogin
     * Regler les limites en ressources avec setrlimit
     * Modifier quelques variables du noyau par sysctl (kern.hostname)
     * chroot()
     * Regler les parametres d'un noeud virtuel (vnode): chflags, fchflags
     * Regler les attributs d'un noeud virtuel comme les permissions d'un
       fichier, le proprietaire, le groupe, la taille, la date d'acces, et la
       date de modification.
     * Se lier `a des ports privilegies sur Internet (ports < 1024)

   Jail est un outil tres utile pour executer des applications dans un
   environnement securise mais il a des imperfections. Actuellement, les
   mecanismes IPC (Inter-Process Communications) n'ont pas ete convertis pour
   utiliser suser_xxx aussi des applications comme MySQL ne peuvent etre
   executee dans une prison. L'acces super-utilisateur peut avoir un sens
   tres limite dans une prison, mais il n'y aucune fac,on de specifier
   exactement ce que tres limite veut dire.

  6.5.2. Les capacites des processus POSIX.1e

   Posix a realise un document de travail qui ajoute l'audit d'evenement, les
   listes de controle d'acces, les privileges fins, l'etiquetage
   d'information, et le controle d'acces mandate.

   Il s'agit d'un travail en cours et c'est l'objectif du projet TrustedBSD.
   Une partie du travail initial a ete integre dans FreeBSD-current
   (cap_set_proc(3)).

6.6. La confiance

   Une application ne devrait jamais supposer que tout est sain dans
   l'environnement des utilisateurs. Cela inclut (mais n'est certainement pas
   limite `a) : la saisie de l'utilisateur, les signaux, les variables
   d'environnement, les ressources, les communication inter-processus, les
   mmaps, le repertoire de travail du systeme de fichiers, les descripteurs
   de fichier, le nombre de fichiers ouverts, etc.

   Vous ne devriez jamais supposer que vous pouvez gerer toutes les formes de
   saisie invalide qu'un utilisateur peut entrer. Votre application devrait
   plutot utiliser un filtrage positif pour seulement permettre un
   sous-ensemble specifique que vous jugez sain. Une mauvaise validation des
   entrees a ete la cause de beaucoup decouvertes de bogues, specialement
   avec les scripts CGI sur le web. Pour les noms de fichier, vous devez etre
   tout particulierement attentif aux chemins ("../", "/"), liens symboliques
   et caracteres d'echappement de l'interpreteur de commandes.

   Perl possede une caracteristique tes sympathique appelee mode "Taint" qui
   peut etre utilisee pour empecher les scripts d'utiliser des donnees
   externes au programme par un moyen non sur. Ce mode verifiera les
   arguments de la ligne de commandes, les variables d'environnement, les
   informations localisees (propres aux pays), les resultats de certains
   appels systeme (readdir(), readlink(), getpwxxx()) et toute entree de
   fichier.

6.7. Les conditions de course

   Une condition de course est un comportement anormal cause par une
   dependance inattendue sur le sequencement relatif des evenements. En
   d'autres mots, un programmeur a suppose `a tort qu'un evenement
   particulier se passerait avant un autre.

   Quelques causes habituelles de conditions de course sont les signaux, les
   verifications d'acces et les fichiers ouverts. Les signaux sont des
   evenements asynchrones par nature aussi un soin particulier doit etre pris
   pour les utiliser. Verifier les acces avec access(2) puis open(2) n'est
   clairement pas atomique. Les utilisateurs peuvent deplacer des fichiers
   entre les deux appels. Les applications privilegiees devraient plutot
   faire un appel `a seteuid() puis appeler open() directement. Dans le meme
   esprit, une application devrait toujours regler un umask correct avant un
   appel `a open() pour prevenir le besoin d'appels non valides `a chmod().

     ----------------------------------------------------------------------

   [12] NDT : Jaune de preference pour etre bien visible

                              Partie III. Le noyau

   Table des matieres

   7. Histoire du noyau Unix

   8. Notes sur le verrouillage

                8.1. Les mutex

                8.2. Les verrous du gestionnaire de verrous (Lock Manager)

                8.3. Variables protegees atomiquement

Chapitre 7. Histoire du noyau Unix

   Un peu d'histoire sur le noyau Unix/BSD, les appels systeme, comment
   fonctionnent les processus, bloquer, planifier, les threads (noyau), le
   basculement de contexte, les signaux, les interruptions, les modules, etc.

Chapitre 8. Notes sur le verrouillage

   Table des matieres

   8.1. Les mutex

   8.2. Les verrous du gestionnaire de verrous (Lock Manager)

   8.3. Variables protegees atomiquement

   Ce chapitre est maintenu par The FreeBSD SMP Next Generation Project.
   Envoyez leur directement les commentaires et les suggestions `a liste de
   diffusion concernant le traitement symetrique multiprocesseurs (SMP) sous
   FreeBSD.

   Ce document souligne le verrouillage utilise dans le noyau FreeBSD pour
   permettre d'utiliser du vrai multi-processeur `a l'interieur du noyau. Le
   verrouillage peut etre realise par differents moyens. Les structures de
   donnees puvent etre protegees par des mutex ou lockmgr(9) verrous.
   Quelques variables sont protegees simplement par l'utilisation continuelle
   d'operations atomiques pour y acceder.

8.1. Les mutex

   Un mutex est simplement un verrou utilise pour garantir exclusion
   mutuelle. Specifiquement, un mutex ne peut appartenir qu'`a une entite `a
   la fois. Si une autre entite desire obtenir un mutex dej`a pris , elle
   doit attendre jusqu'`a ce que le mutex soit relache. Dans le noyau
   FreeBSD, les mutex appartiennent aux processus.

   Les mutex peuvent etre acquis recursivement, mais ils sont conc,us pour
   n'etre pris que pendant une courte periode. Specifiquement, le detenteur
   ne doit pas se suspendre pendant qu'il retient un mutex. Si vous avez
   besoin de maintenir un verrouillage pendant une suspension, utilisez un
   lockmgr(9) verrou ("lock").

   Chaque mutex a plusieurs interets :

   Nom de la variable

           Nom de la variable struct mtx dans le code source du noyau.

   Nom logique

           Le nom du mutex lui est assigne par mtx_init. Ce nom est affiche
           dans les messages de trace KTR, temoigne des erreurs et
           avertissements et est utilise pour distinguer les mutex dans les
           traces.

   Type

           Le type du mutex en termes de constantes nommees MTX_*. La
           signification de chaque constante nommee est documentee dans
           mutex(9).

                MTX_DEF

                        Un mutex endormi

                MTX_SPIN

                        Un mutex tournant

                MTX_COLD

                        Ce mutex est initialise tres tard. Toutefois, il doit
                        etre declare via MUTEX_DECLARE, et la constante
                        nommee MTX_COLD doit etre passee `a mtx_init.

                MTX_TOPHALF

                        Ce mutex tournant ne desactive pas les interruptions.

                MTX_NORECURSE

                        Ce mutex n'a pas la permission d'etre recursif.

   Proteges

           Une liste de structures de donnees ou des membres de structure de
           donnees que cette entree protege. Pour les membres de structures
           de donnees, le nom sera de la forme structure name.member name.

   Fonctions dependantes

           Les fonctions qui peuvent seulement etre appelees si ce mutex est
           pris.

   Tableau 8.1. Liste du mutex

   +------------------------------------------------------------------------+
   | Nom de la  |Nom logique|  Type  |       Proteges        |  Fonctions   |
   |  variable  |           |        |                       | dependantes  |
   |------------+-----------+--------+-----------------------+--------------|
   |            |           |        |_gmonparam,            |              |
   |            |           |        |cnt.v_swtch, cp_time,  |              |
   |            |           |        |curpriority,           |              |
   |            |           |        |mtx.mtx_blocked,       |              |
   |            |           |        |mtx.mtx_contested,     |              |
   |            |           |        |proc.p_contested,      |              |
   |            |           |        |proc.p_blocked,        |              |
   |            |           |        |proc.p_flag (P_PROFIL  |              |
   |            |           |        |XXX, P_INMEM, P_SINTR, |              |
   |            |           |        |P_TIMEOUT, P_SWAPINREQ |              |
   |            |           |        |XXX, P_INMEN XXX),     |              |
   |            |           |        |proc.p_nice,           |              |
   |            |           |        |proc.p_procq,          |              |
   |            |           |        |proc.p_blocked,        |              |
   |            |           |        |proc.p_estcpu,         |              |
   |            |           |        |proc.p_nativepri,      |              |
   |            |           |        |proc.p_priority,       |setrunqueue,  |
   |            |           |        |proc.p_usrpri,         |remrunqueue,  |
   |            |           |        |proc.p_rtprio,         |mi_switch,    |
   |            |           |        |proc.p_rqindex,        |chooseproc,   |
   |            |<< sched   |MTX_SPIN|proc.p_stats->p_prof,  |schedclock,   |
   |sched_lock  |lock >>    ||       |proc.p_stats->p_ru,    |resetpriority,|
   |            |           |MTX_COLD|proc.p_stat,           |updatepri,    |
   |            |           |        |proc.p_cpticks,        |maybe_resched,|
   |            |           |        |proc.p_iticks,         |cpu_switch,   |
   |            |           |        |proc.p_uticks,         |cpu_throw     |
   |            |           |        |proc.p_sticks,         |              |
   |            |           |        |proc.p_swtime,         |              |
   |            |           |        |proc.p_slptime,        |              |
   |            |           |        |proc.p_runtime,        |              |
   |            |           |        |proc.p_pctcpu,         |              |
   |            |           |        |proc.p_oncpu,          |              |
   |            |           |        |proc.p_asleep,         |              |
   |            |           |        |proc.p_wchan,          |              |
   |            |           |        |proc.p_wmesg,          |              |
   |            |           |        |proc.p_slpq,           |              |
   |            |           |        |proc.p_vmspace (XXX -  |              |
   |            |           |        |in statclock), pscnt,  |              |
   |            |           |        |slpque, itqueuebits,   |              |
   |            |           |        |itqueues, rtqueuebits, |              |
   |            |           |        |rtqueues, queuebits,   |              |
   |            |           |        |queues, idqueuebits,   |              |
   |            |           |        |idqueues, switchtime,  |              |
   |------------+-----------+--------+-----------------------+--------------|
   |            |<< vm86pcb |MTX_DEF |                       |              |
   |vm86pcb_lock|lock >>    ||       |vm86pcb                |vm86_bioscall |
   |            |           |MTX_COLD|                       |              |
   |------------+-----------+--------+-----------------------+--------------|
   |            |           |MTX_DEF |                       |              |
   |Giant       |<< Giant >>||       |nearly everything      |lots          |
   |            |           |MTX_COLD|                       |              |
   |------------+-----------+--------+-----------------------+--------------|
   |            |           |        |callfree, callwheel,   |              |
   |            |<< callout |        |nextsoftcheck,         |              |
   |callout_lock|lock >>    |MTX_SPIN|proc.p_itcallout,      |              |
   |            |           |        |proc.p_slpcallout,     |              |
   |            |           |        |softticks, ticks       |              |
   +------------------------------------------------------------------------+

8.2. Les verrous du gestionnaire de verrous (Lock Manager)

   Les verrous qui sont fournis par l'interface lockmgr(9) sont les verrous
   du gestionnaire de verrous. Ces verrous sont des verrous lecture-ecriture
   et peuvent etre retenus par un process suspendu.

   Tableau 8.2. lockmgr(9) List de verrou

   +------------------------------------------------------------------------+
   |  Nom de la   |       Proteges        |               |                 |
   |   variable   |                       |               |                 |
   |--------------+-----------------------+---------------+-----------------|
   |              | allproc zombproc      |               |                 |
   | allproc_lock | pidhashtbl            | proctree_lock | proc.p_children |
   |              | proc.p_list           |               | proc.p_sibling  |
   |              | proc.p_hash nextpid   |               |                 |
   +------------------------------------------------------------------------+

8.3. Variables protegees atomiquement

   Une variable protegee atomiquement est une variable speciale qui n'est pas
   protege par un verrou explicite. Toutefois, tous les acces de donnees aux
   variables utilisent des operations atomiques speciales comme decrit dans
   atomic(9). Tres peu de variables sont traitees de cette fac,on, bien que
   les autres primitives de synchronisation comme les mutex soient
   implementees avec des variables protegees atomiquement.

     * astpending

     * mtx.mtx_lock

                    Partie IV. Memoire et memoire virtuelle

   Table des matieres

   9. La memoire virtuelle

Chapitre 9. La memoire virtuelle

   MV, gestion par page, gestion sur disque, allouer de la memoire, tester
   les fuites de memoires, mmap, vnodes, etc.

                    Partie V. Systeme E/S (Entrees/Sorties)

   Table des matieres

   10. UFS

Chapitre 10. UFS

   UFS, FFS, Ext2FS, JFS, inodes, memoire tampon, mettre `a jour les donnees
   d'un disque, verrouillage, metadata, soft-updates, LFS, portalfs, procfs,
   vnodes, partage de memoire, objets en memoire, TLBs, mettre en cache

                 Partie VI. Communication InterProcessus (IPC)

   Table des matieres

   11. Les signaux

Chapitre 11. Les signaux

   Signaux, tubes, semaphores, files de message, segments de memoire
   partagee, ports, prises, portes

                             Partie VII. Le reseau

   Table des matieres

   12. Les prises

Chapitre 12. Les prises

   Prises, bpf, IP, TCP, UDP, ICMP, OSI, ponts, pare-feux, translation
   d'adresses (NAT), separation de reseaux, etc

                  Partie VIII. Systemes de fichiers en reseau

   Table des matieres

   13. AFS

Chapitre 13. AFS

   AFS, NFS, SANs etc]

                         Partie IX. Gestion du terminal

   Table des matieres

   14. Syscons

Chapitre 14. Syscons

   Syscons, tty, PCVT, console en liaison serie, economiseurs d'ecran, etc

                                Partie X. Le son

   Table des matieres

   15. OSS

Chapitre 15. OSS

   OSS, formes d'ondes, etc

                       Partie XI. Pilotes de peripherique

   Table des matieres

   16. Ecrire des pilotes de peripheriques pour FreeBSD

                16.1. Introduction

                16.2. L'editeur de liens dynamiques du noyau - KLD

                16.3. Acceder au pilote d'un peripherique

                16.4. Les peripheriques caracteres

                16.5. Pilotes Reseau

   17. Les peripheriques PCI

                17.1. Rechercher et rattacher

                17.2. Les ressources du bus

   18. Controleurs SCSI Common Access Method (CAM) **

                18.1. En cours de traduction

   19. Peripheriques USB ***

                19.1. Introduction

   20. NewBus

Chapitre 16. Ecrire des pilotes de peripheriques pour FreeBSD

   Table des matieres

   16.1. Introduction

   16.2. L'editeur de liens dynamiques du noyau - KLD

   16.3. Acceder au pilote d'un peripherique

   16.4. Les peripheriques caracteres

   16.5. Pilotes Reseau

   Ce chapitre a ete ecrit par Murray Stokely avec des selections depuis une
   variete de codes source inclus dans la page de manuel d'intro(4) de Joerg
   Wunsch.

16.1. Introduction

   Ce chapitre fournit une breve introduction sur l'ecriture de pilotes de
   peripheriques pour FreeBSD. Un peripherique, dans ce contexte, est un
   terme utilise le plus souvent pour tout ce qui est lie au materiel et qui
   depend du systeme, comme les disques, imprimantes, ou un ecran avec son
   clavier. Un pilote de peripherique est un composant logiciel du systeme
   d'exploitation qui controle un peripherique specifique. Il y a aussi ce
   que l'on apelle les pseudo-peripheriques ("pseudo-devices") ou un pilote
   de peripherique emule le comportement d'un peripherique dans un logiciel
   sans materiel particulier sous-jacent. Les pilotes de peripheriques
   peuvent etre compiles dans le ysteme statiquement ou charge `a la demande
   via l'editeur de liens dynamique du noyau "kld".

   La plupart des peripheriques dans un systeme d'exploitation de type Unix
   sont accessibles au travers de fichiers speciaux de peripherique
   (device-nodes), appeles parfois fichiers speciaux. Ces fichiers sont
   habituellement stockes dans le repertoire /dev de la hierarchie du systeme
   de fichiers. Jusqu'`a ce que devfs soit totalement integre dans FreeBSD,
   chaque fichier special de peripherique doit etre cree statiquement et
   independamment de l'existence du pilote de peripherique associe. La
   plupart des fichiers speciaux de peripherique du systeme sont crees en
   executant MAKEDEV.

   Les pilotes de peripherique peuvent etre en gros separes en deux
   categories; les pilotes de peripherique en mode caractere et les pilotes
   de peripheriques reseau.

16.2. L'editeur de liens dynamiques du noyau - KLD

   L'interface kld permet aux administrateurs systeme d'ajouter et d'enlever
   dynamiquement une fonctionnalite `a un systeme en marche. Cela permet aux
   developpeurs de pilote de peripherique de charger leurs nouveaux
   changements dans le noyau en fonctionnement sans redemarrer constamment
   pour tester ces derniers.

   L'interface kld est utilise au travers des commandes d'administrateur
   suivantes :

     * kldload - charge un nouveau module dans le noyau
     * kldunload - decharge un module du noyau
     * kldstat - liste les modules charges dans le noyau

   Structure squelettique d'un module de noyau

 /*
  * Squelette KLD
  * Inspire de l'article d'Andrew Reiter paru sur Daemonnews
  */

 #include <sys/types.h>
 #include <sys/module.h>
 #include <sys/systm.h>  /* uprintf */
 #include <sys/errno.h>
 #include <sys/param.h>  /* defines utilise dans kernel.h */
 #include <sys/kernel.h> /* types utilise dans le module d'initialisation */

 /*
  * charge le gestionnaire quit traite du chargement et dechargement d'un KLD.
  */

 static int
 skel_loader(struct module *m, int what, void *arg)
 {
   int err = 0;

   switch (what) {
   case MOD_LOAD:                /* kldload */
    
     uprintf("Skeleton KLD charge.\n");
     break;
   case MOD_UNLOAD:
     uprintf("Skeleton KLD decharge.\n");
     break;
   default:
     err = EINVAL;
     break;
   }
   return(err);
 }

 /* Declare ce module au reste du noyau */

 DECLARE_MODULE(skeleton, skel_loader, SI_SUB_KLD, SI_ORDER_ANY);

  16.2.1. Makefile

   FreeBSD fournit un fichier d'inclusion "makefile" que vous pouvez utiliser
   pour compiler rapidement votre ajout au noyau.

 SRCS=skeleton.c
 KMOD=skeleton

 .include <bsd.kmod.mk>

   Lancer simplement la commande make avec ce fichier Makefile creera un
   fichier skeleton.ko qui peut etre charge dans votre systeme en tapant :

  #
           kldload -v ./skeleton.ko

16.3. Acceder au pilote d'un peripherique

   Unix fournit un ensemble d'appels syteme communs utilisable par les
   applications de l'utilisateur. Les couches superieures du noyau renvoient
   ces appels au pilote de peripherique correspondant quand un utilisateur
   accede au fichier special de peripherique. Le script /dev/MAKEDEV cree la
   plupart des fichiers speciaux de peripherique pour votre systeme mais si
   vous faites votre propre developpement de pilote, il peut etre necessaire
   de creer vos propres fichiers speciaux de peripherique avec la commande
   mknod

  16.3.1. Creer des fichiers speciaux de peripheriques statiques

   La commande mknod necessite quatre arguments pou creer un fichier special
   de peripherique. Vous devez specifier le nom de ce fichier special de
   peripherique, le type de peripherique, le numero majeur et le numero
   mineur du peripherique.

  16.3.2. Les fichiers speciaux de peripherique dynamiques

   Le peripherique systeme de fichiers, ou devfs, fournit l'acces `a l'espace
   des noms des peripheriques du noyau dans l'espace du systeme de fichiers
   global. Ceci elimine les problemes de pilote sans fichier special
   statique, ou de fichier special sans pilote installe. Devfs est toujours
   un travail en cours mais il fonctionne dej`a assez bien.

16.4. Les peripheriques caracteres

   Un pilote de peripherique caractere est un pilote qui tranfere les donnees
   directement au processus utilisateur ou vers celui-ci. Il s'agit du plus
   commun des types de pilote de peripherique et il y en a plein d'exemples
   simples dans l'arbre des sources.

   Cet exemple simple de pseudo-peripherique enregistre toutes les valeurs
   que vous lui avez ecrites et peut vous les renvoyer quand vous les lui
   demandez.

 /*
  * un simple pseudo-peripherique `echo' KLD
  *
  * Murray Stokely
  */

 #define MIN(a,b) (((a) < (b)) ? (a) : (b))

 #include <sys/types.h>
 #include <sys/module.h>
 #include <sys/systm.h> /* uprintf */
 #include <sys/errno.h>
 #include <sys/param.h>  /* defines utilises dans kernel.h */
 #include <sys/kernel.h> /* types utilises dans me module d'initialisation */
 #include <sys/conf.h>   /* cdevsw struct */
 #include <sys/uio.h>    /* uio struct */
 #include <sys/malloc.h>

 #define BUFFERSIZE 256

 /* Prototypes des fonctions */
 d_open_t      echo_open;
 d_close_t     echo_close;
 d_read_t      echo_read;
 d_write_t     echo_write;

 /* Points d'entree du peripherique Caractere */
 static struct cdevsw echo_cdevsw = {
   echo_open,
   echo_close,
   echo_read,
   echo_write,
   noioctl,
   nopoll,
   nommap,
   nostrategy,
   "echo",
   33,                   /* reserve pour lkms - /usr/src/sys/conf/majors */
   nodump,
   nopsize,
   D_TTY,
   -1
 };

 typedef struct s_echo {
   char msg[BUFFERSIZE];
   int len;
 } t_echo;

 /* variables */
 static dev_t sdev;
 static int len;
 static int count;
 static t_echo *echomsg;

 MALLOC_DECLARE(M_ECHOBUF);
 MALLOC_DEFINE(M_ECHOBUF, "echobuffer", "cache pour le module echo");

 /*
  * Cette fonction est appele par les appels systeme kld[un]load(2) pour
  * determiner quelles actions doivent etre faites quand le
  * module est charge ou decharge
  */

 static int
 echo_loader(struct module *m, int what, void *arg)
 {
   int err = 0;

   switch (what) {
   case MOD_LOAD:                /* kldload */
     sdev = make_dev(&echo_cdevsw,
                     0,
                     UID_ROOT,
                     GID_WHEEL,
                     0600,
                     "echo");
     /* aloocation de memoire noyau pour l'utilisation de ce module */
     /*    malloc(256,M_ECHOBUF,M_WAITOK); */
     MALLOC(echomsg, t_echo *, sizeof(t_echo), M_ECHOBUF, M_WAITOK);
     printf("Peripherique Echo charge.\n");
     break;
   case MOD_UNLOAD:
     destroy_dev(sdev);
     FREE(echomsg,M_ECHOBUF);
     printf("Peripherique Echo decharge.\n");
     break;
   default:
     err = EINVAL;
     break;
   }
   return(err);
 }

 int
 echo_open(dev_t dev, int oflags, int devtype, struct proc *p)
 {
   int err = 0;

   uprintf("Peripherique \"echo\" ouvert avec succes.\n");
   return(err);
 }

 int
 echo_close(dev_t dev, int fflag, int devtype, struct proc *p)
 {
   uprintf("Fermeture du peripherique \"echo.\"\n");
   return(0);
 }

 /*
  * La fonction read prend juste comme parametre
  * le cache qui a ete sauve par l'appel `a echo_write()
  * et le retourne a l'utilisateur pour acces.
  * uio(9)
  */

 int
 echo_read(dev_t dev, struct uio *uio, int ioflag)
 {
   int err = 0;
   int amt;

   /* De quelle taille est cette operation read ?  Aussi grande que l'utilisateur le veut,
      ou aussi grande que les donnees restantes */
   amt = MIN(uio->uio_resid, (echomsg->len - uio->uio_offset > 0) ? echomsg->len - uio->uio_offset : 0);
   if ((err = uiomove(echomsg->msg + uio->uio_offset,amt,uio)) != 0) {
     uprintf("uiomove echoue!\n");
   }

   return err;
 }

 /*
  * echo_write prend un caractere en entree et le sauve
  * dans le cache pour une utilisation ulterieure.
  */

 int
 echo_write(dev_t dev, struct uio *uio, int ioflag)
 {
   int err = 0;

   /* Copie la chaine d'entree de la memoire de l'utilisateur a la memoire du noyau*/
   err = copyin(uio->uio_iov->iov_base, echomsg->msg, MIN(uio->uio_iov->iov_len,BUFFERSIZE));

   /* Maintenant nous avons besoin de terminer la chaine par NULL */
   *(echomsg->msg + MIN(uio->uio_iov->iov_len,BUFFERSIZE)) = 0;
   /* Enregistre la taille */
   echomsg->len = MIN(uio->uio_iov->iov_len,BUFFERSIZE);

   if (err != 0) {
     uprintf("Ecriture echouee: mauvaise adresse!\n");
   }

   count++;
   return(err);
 }

 DEV_MODULE(echo,echo_loader,NULL);

   Pour installer ce pilote, vous devrez d'abord creer un fichier special
   dans votre systeme de fichiers avec une commande comme :

         # mknod /dev/echo c 33 0

   Avec ce pilote charge, vous devriez maintenant etr capable de taper
   quelque chose comme :

         # echo -n "Test Donnees" > /dev/echo
         # cat /dev/echo
         Test Donnees

   Peripheriques reels dans le chapitre suivant.

   Informations additionnelles

     * Dynamic Kernel Linker (KLD) Facility Programming Tutorial - Daemonnews
       October 2000
     * How to Write Kernel Drivers with NEWBUS - Daemonnews July 2000

16.5. Pilotes Reseau

   Les pilotes pour peripherique reseau n'utilisent pas les fichiers speciaux
   pour pouvoir etre acessibles. Leur selection est basee sur d'autres
   decisions faites `a l'interieur du noyau et plutot que d'appeler open(),
   l'utilisation d'un peripherique reseau se fait generalement en se servant
   de l'appel systeme socket(2).

   man ifnet(), peripherique "en boucle", drivers de Bill Paul, etc..

Chapitre 17. Les peripheriques PCI

   Table des matieres

   17.1. Rechercher et rattacher

   17.2. Les ressources du bus

   Ce chapitre traitera des mecanismes de FreeBSD pour ecrire un pilote de
   peripherique pour un peripherique sur bus PCI.

17.1. Rechercher et rattacher

   Informations ici sur comment le code du bus PCI fait un cycle sur les
   peripheriques non rattaches et voir si le nouvellement charge pilote de
   peripherique chargeable dans le noyau (kld) sera rattache `a l'un d'eux.

 /*
  * Simple KLD pour jouer avec les fonctions PCI.
  *
  * Murray Stokely
  */

 #define MIN(a,b) (((a) < (b)) ? (a) : (b))

 #include <sys/types.h>
 #include <sys/module.h>
 #include <sys/systm.h>  /* uprintf */
 #include <sys/errno.h>
 #include <sys/param.h>  /* defines used in kernel.h */
 #include <sys/kernel.h> /* types used in module initialization */
 #include <sys/conf.h>   /* cdevsw struct */
 #include <sys/uio.h>    /* uio struct */
 #include <sys/malloc.h>
 #include <sys/bus.h>    /* structs, prototypes for pci bus stuff */

 #include <pci/pcivar.h> /* For get_pci macros! */

 /* Prototypes des fonctions */
 d_open_t      mypci_open;
 d_close_t     mypci_close;
 d_read_t      mypci_read;
 d_write_t     mypci_write;

 /* Points d'entree du pilote de peripherique caractere */

 static struct cdevsw mypci_cdevsw = {
   mypci_open,
   mypci_close,
   mypci_read,
   mypci_write,
   noioctl,
   nopoll,
   nommap,
   nostrategy,
   "mypci",
   36,                   /* reserved for lkms - /usr/src/sys/conf/majors */
   nodump,
   nopsize,
   D_TTY,
   -1
 };

 /* variables */
 static dev_t sdev;

 /* Nous sommes plus interresses dans la recherche/attachement
 que dans l'ouverture/fermeture/lecture/ecriture a ce point */

 int
 mypci_open(dev_t dev, int oflags, int devtype, struct proc *p)
 {
   int err = 0;

   uprintf("Peripherique \"monpci\" ouvert avec succes.\n");
   return(err);
 }

 int
 mypci_close(dev_t dev, int fflag, int devtype, struct proc *p)
 {
   int err=0;

   uprintf("Peripherique \"monpci.\ "ferme\n");
   return(err);
 }

 int
 mypci_read(dev_t dev, struct uio *uio, int ioflag)
 {
   int err = 0;

   uprintf("lecture dans monpci!\n");
   return err;
 }

 int
 mypci_write(dev_t dev, struct uio *uio, int ioflag)
 {
   int err = 0;

   uprintf("Ecriture dans monpci!\n");
   return(err);
 }

 /* PCI Support Functions */

 /*
  * Retourne la chaine d'identification si ce peripherique est le notre
  */
 static int
 mypci_probe(device_t dev)
 {
   uprintf("MonPCI Probe\n"
           "ID Fabricant: 0x%x\n"
           "ID Peripherique : 0x%x\n",pci_get_vendor(dev),pci_get_device(dev));

   if (pci_get_vendor(dev) == 0x11c1) {
     uprintf("Nous avons le WinModem, recherche reussi!\n");
     return 0;
   }

   return ENXIO;
 }

 /* La fonction Attach n'est appelee que si
 la recherche est reussie*/

 static int
 mypci_attach(device_t dev)
 {
   uprintf("Rattachement de MonPCI pour: ID Peripherique: 0x%x\n",pci_get_vendor(dev));
   sdev = make_dev(&mypci_cdevsw,
                   0,
                   UID_ROOT,
                   GID_WHEEL,
                   0600,
                   "monpci");
   uprintf("Peripherique Monpci charge.\n");
   return ENXIO;
 }

 /* Detach le peripherique. */

 static int
 mypci_detach(device_t dev)
 {
   uprintf("Monpci detache!\n");
   return 0;
 }

 /* Appele lors de l'arret du systeme apres sync. */

 static int
 mypci_shutdown(device_t dev)
 {
   uprintf("Monpci arrete!\n");
   return 0;
 }

 /*
  * routine de suspension du peripherique
  */
 static int
 mypci_suspend(device_t dev)
 {
   uprintf("Monpci suspendu!\n");
   return 0;
 }

 /*
  * routine de reprise du peripherique
  */

 static int
 mypci_resume(device_t dev)
 {
   uprintf("Monpci resume!\n");
   return 0;
 }

 static device_method_t mypci_methods[] = {
         /* Interface Peripherique*/
         DEVMETHOD(device_probe,         mypci_probe),
         DEVMETHOD(device_attach,        mypci_attach),
         DEVMETHOD(device_detach,        mypci_detach),
         DEVMETHOD(device_shutdown,      mypci_shutdown),
         DEVMETHOD(device_suspend,       mypci_suspend),
         DEVMETHOD(device_resume,        mypci_resume),

         { 0, 0 }
 };

 static driver_t mypci_driver = {
         "monpci",
         mypci_methods,
         0,
         /*      sizeof(struct mypci_softc), */
 };

 static devclass_t mypci_devclass;

 DRIVER_MODULE(mypci, pci, mypci_driver, mypci_devclass, 0, 0);

   Informations complementaires

     * PCI Special Interest Group
     * PCI System Architecture, Fourth Edition by Tom Shanley, et al.

17.2. Les ressources du bus

   FreeBSD fournit un mecanisme oriente objet pour demander des ressources du
   bus parent. Pratiquement tous les peripheriques seront un fils membre d'un
   type de bus (PCI, ISA, USB, SCSI, etc) et ces peripheriques necessite des
   ressources issues de leur bus parent (comme des segments de memoire, des
   interruptions or des canaux DMA).

  17.2.1. Registres d'adresse de base

   Pour faire de particulierement utile avec un peripherique PCI, vous aurez
   besoin d'obtenir les registres d'adresse de base (Base Address Registers
   ou BARs) de l'espace de configuration PCI. Les details specifiques au PCI
   sur l'obtention du registre d'adresse de base sont masques dans la
   fonction bus_alloc_resource().

   Par exemple, un pilote typique aura sa fonction attach() similaire `a ceci
   :

     sc->bar0id = 0x10;
     sc->bar0res = bus_alloc_resource(dev, SYS_RES_MEMORY, &(sc->bar0id),
                                   0, ~0, 1, RF_ACTIVE);
     if (sc->bar0res == NULL) {
         uprintf("Allocation memoire du registre PCI de base 0 echouee!\n");
         error = ENXIO;
         goto fail1;
     }

     sc->bar1id = 0x14;
     sc->bar1res = bus_alloc_resource(dev, SYS_RES_MEMORY, &(sc->bar1id),
                                   0, ~0, 1, RF_ACTIVE);
     if (sc->bar1res == NULL) {
         uprintf("Allocation memoire du registre PCI de base 1 echouee!\n");
         error =  ENXIO;
         goto fail2;
     }
     sc->bar0_bt = rman_get_bustag(sc->bar0res);
     sc->bar0_bh = rman_get_bushandle(sc->bar0res);
     sc->bar1_bt = rman_get_bustag(sc->bar1res);
     sc->bar1_bh = rman_get_bushandle(sc->bar1res);


   Des references pour chaque registre d'adresse de base sont gardees dans la
   structure softc afin qu'elle puisse etre utilisee pour ecrire dans le
   peripherique plus tard.

   Ces references peuvent alors etre utilisees pour lire ou ecrire dans les
   registres du peripherique avec les fonctions bus_space_*. Par exemple, un
   pilote peut contenir une fonction raccourci pour lire dans un registre
   specifique `a une carte comme cela :

 uint16_t
 board_read(struct ni_softc *sc, uint16_t address) {
     return bus_space_read_2(sc->bar1_bt, sc->bar1_bh, address);
 }

   De fac,on similaire, une autre peut ecrire dans les registres avec :

 void
 board_write(struct ni_softc *sc, uint16_t address, uint16_t value) {
     bus_space_write_2(sc->bar1_bt, sc->bar1_bh, address, value);
 }

   Ces fonctions existent en versions 8bit, 16bit et 32bit et vous devriez
   utiliser bus_space_{read|write}_{1|2|4} en consequence.

  17.2.2. Les interruptions

   Les interruptions sont alloues `a partir du code oriente objet du bus de
   fac,on similaire aux ressources memoire. D'abord une ressource IRQ doit
   etre allouee `a partir du bus parent, et alors le gestionnaire
   d'interruption doit etre regle pour traiter cet IRQ.

   A nouveau, un exemple de fonction attach() en dit plusqu'un long discours.

 /* Recupere la ressource IRQ */

     sc->irqid = 0x0;
     sc->irqres = bus_alloc_resource(dev, SYS_RES_IRQ, &(sc->irqid),
                                   0, ~0, 1, RF_SHAREABLE | RF_ACTIVE);
     if (sc->irqres == NULL) {
         uprintf("Allocation IRQ echouee!\n");
         error = ENXIO;
         goto fail3;
     }

     /* Maitnenant nous choisissons notre gestionnaire d'interruption */

     error = bus_setup_intr(dev, sc->irqres, INTR_TYPE_MISC,
                            my_handler, sc, &(sc->handler));
     if (error) {
         printf("Ne peut regler l'IRQ\n");
         goto fail4;
     }

     sc->irq_bt = rman_get_bustag(sc->irqres);
     sc->irq_bh = rman_get_bushandle(sc->irqres);

  17.2.3. DMA

   Sur les PC, les peripheriques qui veulent utiliser la gestion de bus DMA
   doivent travailler avec des adresses physiques. C'est un probleme puisque
   FreeBSD utilise une memoire virtuelle et travaille presque exclusivement
   avec des adresses virtuelles. Heureusement, il y a une fonction vtophys()
   pour nous aider.

 #include <vm/vm.h>
 #include <vm/pmap.h>

 #define vtophys(virtual_address) (...)

   La solution est toutefois un peu differente sur Alpha, et ce que nous
   voulons reellement est une fonction appelee vtobus().

 #if defined(__alpha__)
 #define vtobus(va)      alpha_XXX_dmamap((vm_offset_t)va)
 #else
 #define vtobus(va)      vtophys(va)
 #endif

  17.2.4. Desallouer les resources

   Il est tres important de desallouer toutes les ressources qui furent
   allouees pendant attach(). Unsoin tout particulier doit etre pris pour
   desallouer les bonnes choses meme lors d'un echec afin que le systeme
   reste utilisable lorsque votre driver meurt.

Chapitre 18. Controleurs SCSI Common Access Method (CAM) **

   Table des matieres

   18.1. En cours de traduction

18.1. En cours de traduction

   En cours de traduction

Chapitre 19. Peripheriques USB ***

   Table des matieres

   19.1. Introduction

   Ce chapitre a ete ecrit par Nick Hibma. Les modifications pour le manuel
   par Murray Stokely.

19.1. Introduction

   Chapitre `a traduire.

Chapitre 20. NewBus

   Ce chapitre traitera de l'architecture NewBus de FreeBSD.

                           Partie XII. Architectures

   Table des matieres

   21. IA-32

   22. Alpha

   23. IA-64

Chapitre 21. IA-32

   Traite des specificites de l'architecture x86 sous FreeBSD.

Chapitre 22. Alpha

   Traite des specificites de l'architecture Alpha sous FreeBSD.

   Explication des erreurs d'alignements, comment les reparer, comment les
   ignorer.

   Exemple de code assembleur pour FreeBSD/alpha.

Chapitre 23. IA-64

   Traite des specificites de l'architecture IA-64 sous FreeBSD.

                            Partie XIII. Deverminage

   Table des matieres

   24. Truss

Chapitre 24. Truss

   diverses descriptions sur les methodes de deverminage de certains aspects
   du systeme utilisant truss, ktrace, gdb, kgdb, etc

                    Partie XIV. Les couches de compatibilite

   Table des matieres

   25. Linux

Chapitre 25. Linux

   Linux, SVR4, etc

                            Partie XV. Bibligraphie

   Table des matieres

   Bibliographie

Bibliographie

   [1] Dave A Patterson et John L Hennessy. Copyright (c) 1998 Morgan
   Kaufmann Publishers, Inc.. 1-55860-428-6. Morgan Kaufmann Publishers,
   Inc.. Computer Organization and Design. The Hardware / Software Interface.
   1-2.

   [2] W. Richard Stevens. Copyright (c) 1993 Addison Wesley Longman, Inc..
   0-201-56317-7. Addison Wesley Longman, Inc.. Advanced Programming in the
   Unix Environment. 1-2.

   [3] Marshall Kirk McKusick, Keith Bostic, Michael J Karels, et John S
   Quarterman. Copyright (c) 1996 Addison-Wesley Publishing Company, Inc..
   0-201-54979-4. Addison-Wesley Publishing Company, Inc.. The Design and
   Implementation of the 4.4 BSD Operating System. 1-2.

   [4] Aleph One. Phrack 49; "Smashing the Stack for Fun and Profit".

   [5] Chrispin Cowan, Calton Pu, et Dave Maier. StackGuard; Automatic
   Adaptive Detection and Prevention of Buffer-Overflow Attacks.

   [6] Todd Miller et Theo de Raadt. strlcpy and strlcat -- consistent, safe
   string copy and concatenation..
