Book Screen

Embed Size (px)

Citation preview

Programmation Avance sous LinuxMark Mitchell Jerey Oldham Alex Samuel

Traduction : Sbastien Le Ray

Programmation avance sous LinuxPREMIRE DITION : Juin 2001 Copyright c 2001 New Riders Publishing. Ce document peut tre distribu selon les termes et conditions de lOpen Publication License, Version 1, sans ajout (la dernire version de cette licence est disponible sur http://www.opencontent.org/openpub/). ISBN : 0-7357-1043-0 Numro Catalogue de la Bibliothque du Congrs : 00-105343 05 04 03 02 01 7 6 5 4 3 2 1 Interprtation du code : Le nombre deux chires lextrme droite est lanne dimpression du livre ; le nombre un chire lextrme droite est le rang dimpression du livre. Par exemple, le code 01-1 signie que la premire impression du livre a t ralise en 2001.

Marques dposesToutes les marques cites sont proprits de leurs auteurs respectifs. PostScript est une marque dpose par Adobe Systems, Inc. Linux est une marque dpose par Linus Torvalds.

Non-responsabilit et avertissementCe livre est destin fournir des informations sur la Programmation Avance Sous Linux. Un soin particulier t apport sa compltude et sa prcision, nanmoins, aucune garantie nest fournie implicitement. Les informations sont fournies en ltat . Les auteurs, traducteurs et New Riders Publishing ne peuvent tre tenus pour responsables par quiconque de toute perte de donnes ou dommages occasionns par lutilisation des informations prsentes dans ce livre ou par celle des disques ou programmes qui pourraient laccompagner.

TraductionLe plus grand soin a t apport la traduction en Franais de ce livre, toutefois, des erreurs de traduction peuvent avoir t introduites en plus des ventuelles erreurs initialement prsente. Les traducteurs ne peuvent tre tenus pour responsables par quiconque de toute perte de donnes ou dommages occasionns par lutilisation des informations prsentes dans ce livre. La version originale de ce document est disponible sur le site des auteurs http://www. advancedlinuxprogramming.com

ii

Table des matiresI Programmation UNIX Avance avec Linux. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

15 5 7 10 12 14 17 17 28 34 41 41 43 48 50 55 56 62 64 68 80 82

1 Pour commencer 1.1 Lditeur Emacs . . . . . . . . . . . . . . 1.2 Compiler avec GCC . . . . . . . . . . . . 1.3 Automatiser le processus avec GNU Make 1.4 Dboguer avec le dbogueur GNU (GDB) 1.5 Obtenir plus dinformations . . . . . . . .

2 crire des logiciels GNU/Linux de qualit 2.1 Interaction avec lenvironnement dexcution . . . . . . . . . . . . . . . . . . . . 2.2 Crer du code robuste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.3 crire et utiliser des bibliothques . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Processus 3.1 Introduction aux processus 3.2 Crer des processus . . . . . 3.3 Signaux . . . . . . . . . . . 3.4 Fin de processus . . . . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

4 Threads 4.1 Cration de threads . . . . . . . . . . . . . . 4.2 Annulation de thread . . . . . . . . . . . . . . 4.3 Donnes propres un thread . . . . . . . . . 4.4 Synchronisation et sections critiques . . . . . 4.5 Implmentation des threads sous GNU/Linux 4.6 Comparaison processus/threads . . . . . . . . 5 Communication interprocessus 5.1 Mmoire partage . . . . . . 5.2 Smaphores de processus . . . 5.3 Mmoire mappe . . . . . . . 5.4 Tubes . . . . . . . . . . . . . 5.5 Sockets . . . . . . . . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . . iii

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

85 . 86 . 90 . 93 . 98 . 104

II

Matriser Linux

115119 120 120 121 123 126 131 132 135 136 137 145 146 148 151 153 154 155 156 158 159 161 161 163 164 166 167 168 169 171 171 173 174 174 175 179 179

6 Priphriques 6.1 Types de priphriques . . 6.2 Numros de priphrique 6.3 Fichiers de priphriques . 6.4 Priphriques matriels . 6.5 Priphriques spciaux . . 6.6 PTY . . . . . . . . . . . . 6.7 ioctl . . . . . . . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

7 Le systme de chiers /proc 7.1 Obtenir des informations partir 7.2 Rpertoires de processus . . . . . 7.3 Informations sur le matriel . . . 7.4 Informations sur le noyau . . . . 7.5 Lecteurs et systmes de chiers . 7.6 Statistiques systme . . . . . . .

de /proc . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

8 Appels systme Linux 8.1 Utilisation de strace . . . . . . . . . . . . . . . . . . . 8.2 access : Tester les permissions dun chier . . . . . . . 8.3 fcntl : Verrous et oprations sur les chiers . . . . . . 8.4 fsync et fdatasync : purge des tampons disque . . . . . 8.5 getrlimit et setrlimit : limites de ressources . . . . . . 8.6 getrusage : statistiques sur les processus . . . . . . . . 8.7 gettimeofday : heure systme . . . . . . . . . . . . . . 8.8 La famille mlock : verrouillage de la mmoire physique 8.9 mprotect : dnir des permissions mmoire . . . . . . . 8.10 nanosleep : pause en haute prcision . . . . . . . . . . 8.11 readlink : lecture de liens symboliques . . . . . . . . . 8.12 sendle : transferts de donnes rapides . . . . . . . . . 8.13 setitimer : crer des temporisateurs . . . . . . . . . . . 8.14 sysinfo : rcupration de statistiques systme . . . . . 8.15 uname . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 Code assembleur en ligne 9.1 Quand utiliser du code assembleur ? . . . . 9.2 Assembleur en ligne simple . . . . . . . . . 9.3 Syntaxe assembleur avance . . . . . . . . . 9.4 Problmes doptimisation . . . . . . . . . . 9.5 Problmes de maintenance et de portabilit iv

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

10 Scurit 10.1 Utilisateurs et groupes . . . . . . . . . . . . . . 10.2 Identiant de groupe et utilisateur de processus 10.3 Permissions du systme de chiers . . . . . . . 10.4 Identiants rels et eectifs . . . . . . . . . . . 10.5 Authentier les utilisateurs . . . . . . . . . . . 10.6 Autres failles de scurit . . . . . . . . . . . . . 11 Application GNU/Linux 11.1 Prsentation . . . . . . 11.2 Implantation . . . . . 11.3 Modules . . . . . . . . 11.4 Utilisation du serveur 11.5 Pour nir . . . . . . . dIllustration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

181 181 183 184 188 191 194 201 201 202 218 229 232

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

III

Annexes

233

A Autres outils de dveloppement 237 A.1 Analyse statique de programmes . . . . . . . . . . . . . . . . . . . . . . . . . . . 237 A.2 Dtection des erreurs dallocation dynamique . . . . . . . . . . . . . . . . . . . . 238 A.3 Prolage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 246 B E/S B.1 B.2 B.3 B.4 B.5 B.6 de bas niveau Lire et crire des donnes . . . . . . . . . . . stat . . . . . . . . . . . . . . . . . . . . . . . criture et lecture vectorielles . . . . . . . . . Lien avec les fonctions dE/S standards du C Autres oprations sur les chiers . . . . . . . Lire le contenu dun rpertoire . . . . . . . . 257 257 265 267 269 269 270 273

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

C Tableau des signaux

D Ressources en ligne 275 D.1 Informations gnrales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275 D.2 Informations sur les logiciels GNU/Linux . . . . . . . . . . . . . . . . . . . . . . 275 D.3 Autres sites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 276 E Licence Open Publication version 1.0 I. Conditions applicables aux versions modies ou non II. Copyright . . . . . . . . . . . . . . . . . . . . . . . . III. Porte de cette licence . . . . . . . . . . . . . . . . . IV. Conditions applicables aux travaux modis . . . . . V. Bonnes pratiques . . . . . . . . . . . . . . . . . . . . VI. Options possibles . . . . . . . . . . . . . . . . . . . . v 277 277 277 278 278 278 279

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

VII. Annexe la licence Open Publication . . . . . . . . . . . . . . . . . . . . . . . . 279 F Licence Publique Gnrale GNU 281

vi

propos des auteursMark Mitchell a obtenu un bachelor of arts en informatique Harvard en 1994 et un master of science Standford en 1999. Ses recherches se concentrent sur la complexit de calcul et la scurit informatique. Mark a particip activement au dveloppement de la GNU Compiler Collection et sapplique dvelopper des logiciels de qualit. Jerey Oldham a obtenu un bachelor of arts en informatique lUniversit Rice en 1991. Aprs avoir travaill au Center for Research on Parallel Computation, il a obtenu un doctorat en philosophie Standford en 2000. Ses recherches sont centres sur la conception dalgorithmes en particulier les algorithmes de ux et combinatoires. Il travaille sur GCC et des logiciels de calcul scientique. Alex Samuel a t diplm de Harvard en 1995 en physique. Il a travaill en tant quingnieur informatique BBN avant de retourner tudier la physique Caltech et au Standford Linear Accelerator Center. Alex administre le projet Software Carpentry et travaille sur divers autres projets comme les optimisations dans GCC. Mark et Alex ont fond ensemble CodeSourcery LLC en 1999. Jerey a rejoint lentreprise en 2000. Les missions de CodeSourcery sont de fournir des outils de dveloppement pour GNU/Linux et dautres systme dexploitation ; faire de lensemble des outils GNU une suite de qualit commerciale respectant les standards ; et de fournir des services gnraux de conseil et dingnierie. Le site Web de CodeSourcery est disponible ladresse http://www.codesourcery. com

vii

propos des relecteurs techniquesCes relecteurs ont mis disposition leur expertise tout au long du processus de cration du livre Programmation Avance sous Linux. Au fur et mesure de lcriture du livre, ces professionnels ont pass en revue tous les documents du point de vue de leur contenu technique, de leur organisation et de leur enchanement. Leur avis a t critique an de nous assurer que Programmation Avance sous Linux corresponde aux besoins de nos lecteurs avec une information technique de grande qualit. Glenn Becker a beaucoup de diplmes, tous dans le thtre. Il travaille actuellement en tant que producteur en ligne pour SCIFI.COM, la composante en ligne de la chane SCI FI, New York. Chez lui, il utilise Debian GNU/Linux et est obsd par des sujets comme ladministration systme, la scurit, linternationalisation de logiciels et XML. John Dean a obtenu un BSc(Hons) lUniversit de Sheeld en 1974, en sciences thoriques. Lors de son premier cycle Sheeld, John a prouv de lintrt pour linformatique. En 1986, il a obtenu un MSc au Craneld Institute of Science and Technology dans le domaine des commandes et systmes commands. Alors quil travaillait pour Rolls Royces et Associs, John sest engag dans le dveloppement de logiciels de contrle pour linspection assiste par ordinateur des units de production de vapeur nuclaires. Depuis quil a quitt RR&A en 1978, il a travaill pour lindustrie ptrochimique dans le dveloppement et la maintenance de logiciels de contrle de processus. John a travaill en tant que dveloppeur volontaire pour MySQL de 1996 Mai 2000, il a alors rejoint MySQL comme employ plein temps. Le champ de responsabilits de John concerne MySQL sous MS Windows et le dveloppement de nouveaux clients graphiques pour MySQL utilisant le kit de dveloppement Qt de Trolltech, sous Windows et sur les plateformes disposant de X-11..

viii

RemerciementsNous apprcions grandement le travail de pionniers de Richard Stallman, sans qui il ny aurait jamais eu de projet GNU et de Linus Torvalds, sans qui il ny aurait jamais eu de noyau Linux. Sans compter ceux qui ont travaill sur le systme dexploitation GNU/Linux, nous les remercions tous. Nous remercions les facults de Harvard et Rice pour nos premiers cycles et Caltech et Standford pour notre prparation au diplme. Sans tous ceux qui nous ont enseign, nous naurions jamais os enseigner aux autres ! W. Richard Stevens a crit trois livres excellents sur la programmation sous UNIX et nous les avons consults sans retenue. Roland McGrath, Ulrich Drepper et beaucoup dautres ont crit la bibliothque GNU C et la documentation laccompagnant. Robert Brazile et Sam Kendall ont relu les premiers jets de ce livre et ont fait des suggestions pertinentes sur le ton et le contenu. Nos diteurs techniques et relecteurs (en particulier Glenn Becker et John Dean) ont dbusqu nos erreurs, fait des suggestions et nous ont continuellement encourag. Bien sr, sil reste des erreurs, ce nest pas de leur faute ! Merci Ann Quinn, de New Riders, pour la gestion de tous les dtails concernant la publication dun livre ; Laura Loveall, galement de New Riders, de ne pas nous avoir laiss dpasser de trop nos deadlines ; et Stphanie Wall, elle aussi de New Riders, pour avoir t la premire nous encourager crire ce livre !

ix

Dites nous ce que vous en pensez !En tant que lecteur de ce livre, vous tes les critiques et les commentateurs les plus importants. Nous tenons compte de votre opinion et voulons savoir ce que nous faisons bien et ce que nous pourrions mieux faire, dans quels domaines vous aimeriez que nous publiions et tout autre conseil que vous voudriez nous communiquer. En tant quditeur Excutif pour lquipe de Dveloppement Web au sein de New Riders Publishing, jattends vos commentaires. Vous pouvez me contacter par fax, email ou mcrire directement pour me faire savoir ce que vous aimez ou pas dans ce livre mais galement ce que nous pourrions faire pour rendre nos livres plus pertinents. Notez sil vous plat que je ne peux pas vous aider sur des problmes techniques lis au contenu de ce livre, et quen raison du volume important de courrier que je reois, il ne mest pas forcment possible de rpondre tous les messages. Lorsque vous crivez, assurez-vous sil vous plat dinclure le titre et lauteur de ce livre, ainsi que votre nom et votre numro de tlphone ou de fax. Je lirai vos commentaires avec attention et les partagerai avec lauteur et les diteurs qui ont travaill sur ce livre. Fax : Courriel : Adresse : 317-581-4663 [email protected] Stephanie Wall Executive Editor New Riders Publishing 201 West 103rd Street Indianapolis, IN 46290 USA

x

IntroductionGNU/Linux a envahi le monde des ordinateurs comme une tempte. Il fut un temps o les utilisateurs dordinateurs taient obligs de faire leur choix parmi des systmes dexploitation et des applications propritaires. Ils navaient aucun moyen de corriger ou damliorer ces programmes, ne pouvaient pas regarder sous le capot , et taient souvent forcs daccepter des licences restrictives. GNU/Linux et dautres systmes open source ont chang cet tat de faits dsormais, les utilisateurs de PC, les administrateurs et les dveloppeurs peuvent choisir un environnement complet gratuit avec des outils, des applications et laccs au code source. Une grande partie du succs de GNU/Linux est lie sa nature open source. Comme le code source des programmes est disponible pour le public, tout un chacun peut prendre part au dveloppement, que ce soit en corrigeant un petit bogue ou en dveloppant et distribuant une application majeure complte. Cette opportunit a attir des milliers de dveloppeurs comptents de par le monde pour contribuer de nouveaux composants et amliorations pour GNU/Linux, un tel point que les systmes GNU/Linux modernes peuvent rivaliser avec les fonctionnalits de nimporte quel systme propritaire et les distributions incluent des milliers de programmes et dapplications se rpartissant sur plusieurs CD-ROM ou DVD. Le succs de GNU/Linux a galement avalis la philosophie UNIX. La plupart des Interfaces de Programmation dApplication (Application Programming Interfaces, API) introduites dans les UNIX AT&T et BSD survivent dans Linux et constituent les fondations sur lesquelles sont construits les programmes. La philosophie UNIX de faire fonctionner de concert beaucoup de petits programmes orients ligne de commande est le principe dorganisation qui rend GNU/Linux si puissant. Mme lorsque ces programmes sont encapsuls dans des interfaces graphiques simples utiliser, les commandes sous-jacentes sont toujours disponibles pour les utilisateurs conrms et les scripts. Une application GNU/Linux puissante exploite la puissance de ces API et de ces commandes au niveau de son fonctionnement interne. Les API GNU/Linux donnent accs des fonctionnalits sophistiques comme la communication interprocessus, le multithreading et la communication rseau hautes performances. Et beaucoup de problmes peuvent tre rsolus simplement en assemblant des commandes et des programmes existants au moyen de scripts.

GNU et LinuxDo vient le nom GNU/Linux ? Vous avez certainement dj entendu parler de Linux auparavant et vous avez peut-tre entendu parler du Projet GNU. Vous navez peut-tre jamais xi

entendu le nom GNU/Linux, bien que vous soyez probablement familier avec le systme auquel il se rfre. Linux vient de Linus Torvalds, le crateur et lauteur original du noyau1 la base du fonctionnement dun systme GNU/Linux. Le noyau est le programme qui eectue les oprations de base dun systme dexploitation : il contrle et fait linterface avec le matriel, gre lallocation de la mmoire et des autres ressources, permet plusieurs programmes de sexcuter en mme temps, gre le systme de chiers et caetera. Le noyau en lui-mme nore pas de fonctionnalits utiles lutilisateur. Il ne peut mme pas acher une invite pour que celui-ci entre des commandes lmentaires. Il nore aucun moyen de grer ou dditer les chiers, de communiquer avec dautres ordinateurs ou dcrire des programmes. Ces tches requirent lutilisation dune large gamme dautres produits comme les shells de commande, les utilitaires de chiers, les diteurs et les compilateurs. La plupart de ces programmes utilisent leur tour des bibliothques de fonctions comme la bibliothque contenant les fonctions standards du C qui ne sont pas incluses dans le noyau. Sur les systmes GNU/Linux, la plupart de ces programmes sont des logiciels dvelopps dans le cadre du Projet GNU2 . Une grande partie de ces logiciels ont prcd le noyau Linux. Le but du projet GNU est de dvelopper un systme dexploitation de type UNIX qui soit un logiciel libre (daprs le site Web du Projet GNU, http://www.gnu.org). Le noyau Linux et les logiciels du Projet GNU ont prouv quils sont une combinaison puissante. Bien que cette association soit souvent appele Linux par raccourci, le systme complet ne pourrait fonctionner sans les logiciels GNU, pas plus quils ne pourraient fonctionner sans le noyau. Pour cette raison, dans ce livre, nous ferons rfrence au systme complet par le nom GNU/Linux, except lorsque nous parlerons spciquement du noyau Linux.

La licence publique gnrale de GNULes codes sources contenus dans ce livre son couverts par la Licence Publique Gnrale GNU (GNU General Public Licence, GPL), qui est reproduite dans lAnnexe F, Licence Publique Gnrale GNU . Un nombre important de logiciels libres, en particulier ceux pour GNU/Linux, sont couverts par celle-ci. Par exemple, le noyau Linux lui-mme est sous GPL, comme beaucoup dautres programmes et bibliothques GNU que vous trouverez dans les distributions GNU/Linux. Si vous utilisez des sources issues de ce livre, soyez sr davoir bien lu et bien compris les termes de la GPL. Le site Web du Projet GNU comprend une discussion dans le dtail de la GPL (http://www. gnu.org/copyleft/copyleft.fr.html) et des autres licences de logiciels libres. Vous trouverez plus dinformations sur les licences open source sur http://opensource.org/licenses/.

qui est destin ce livre ?Ce livre est destin trois types de lecteurs :1 2

NdT : le terme original kernel est parfois employ. Nous conserverons noyau dans la suite de ce livre. GNU est un acronyme rcursif, il signie GNUs Not UNIX (GNU nest pas UNIX).

xii

Les dveloppeurs ayant dj lexprience de la programmation sous GNU/Linux et voulant en savoir plus sur certaines de ses fonctionnalits et possibilits avances. Vous pouvez tre intress par lcriture de programmes plus sophistiqus avec des fonctionnalits comme le multiprocessing, le multithreading, la communication interprocessus et linteraction avec les priphriques matriels. Vous pouvez vouloir amliorer vos programmes en les rendant plus rapides, plus ables et plus scuriss ou en les concevant de faon ce quils interagissent mieux avec le reste du systme GNU/Linux. Les dveloppeurs ayant de lexprience avec un autre systme de type UNIX intresss par le dveloppement de logiciels pour GNU/Linux. Vous pouvez tre dj familier avec des API standards comme celles de la spcication POSIX. Pour dvelopper des logiciels GNU/Linux, vous devez connatre les particularits du systme, ses limitations, les possibilits supplmentaires quil ore et ses conventions. Les dveloppeurs venant dun systme non-UNIX, comme la plate-forme Win32 de Microsoft. Vous devriez dj connatre les principes permettant dcrire des logiciels de bonne qualit, mais vous avez besoin dapprendre les techniques spciques que les programmes GNU/Linux utilisent pour interagir avec le systme et entre eux. Et vous voulez tre sr que vos programmes sintgrent naturellement au sein du systme GNU/Linux et se comportent selon les attentes des utilisateurs. Ce livre na pas pour but dtre un guide ou une rfrence pour tous les aspects de la programmation GNU/Linux. Au lieu de cela, nous aurons une approche didactique, en introduisant les concepts et les techniques les plus importants et en donnant des exemples sur la faon de les utiliser. La Section 1.5, Obtenir plus dinformations , dans le Chapitre 1, Pour commencer , prsente dautres sources de documentation, o vous pourrez trouver des dtails plus complets sur les dirents aspects de la programmation GNU/Linux. Comme ce livre traite de sujets avancs, nous supposerons que vous tes dj familier avec le langage C et que vous savez comment utiliser les fonctions de la bibliothque standard du C dans vos programmes. Le langage C est le langage le plus utilis dans le dveloppement de logiciels GNU/Linux ; la plupart des commandes et des bibliothques dont traite ce livre, et le noyau Linux lui-mme, sont crits en C. Les informations prsentes dans ce livre sont galement applicables au C++ car il sagit grossirement dun sur-ensemble du C. Mme si vous programmez dans un autre langage, vous trouverez ces informations utiles car les API en langage C et leurs conventions constituent le sabir de GNU/Linux. Si vous avez dj programm sur un autre systme de type UNIX, il y a de bonnes chances que vous sachiez vous servir des fonctions dE/S de bas niveau de Linux (open, read, stat, etc). Elles sont direntes des fonctions dE/S de la bibliothque standard du C (fopen, fprintf, fscanf, etc). Toutes sont utiles dans le cadre de la programmation GNU/Linux et nous utiliserons les deux jeux de fonctions dE/S dans ce livre. Si vous ntes pas familiers avec les fonctions dE/S de bas niveau, allez la n de ce livre et lisez lAnnexe B, E/S de bas niveau , avant de commencer le Chapitre 2, crire des logiciels GNU/Linux de qualit . Ce livre nore pas une introduction gnrale aux systmes GNU/Linux. Nous supposons que vous avez dj une connaissance basique de la faon dinteragir avec un systme GNU/Linux et deectuer des oprations lmentaires dans des environnements en ligne de commande ou xiii

xiv graphiques. Si vous tes nouveau sur GNU/Linux, commencez avec un des nombreux excellents livres dintroduction, comme Inside Linux de Michael Tolber (New Riders Publishing, 2001).

ConventionsCe livre suit quelques conventions typographiques : Un nouveau terme est prsent en italique la premire fois quil apparat. Les listings de programme, les fonctions, les variables et autres termes informatiques sont prsents en police chasse xe par exemple, printf("Hello, World !\bksl \n"). Les noms des commandes, des chiers et des rpertoires sont galement en police chasse xe par exemple, cd /. Lorsque nous montrons des interactions avec un shell de commandes, nous utiliserons % comme invite shell (votre shell est probablement congur pour utiliser une invite dirente). Tout ce qui se trouve aprs linvite est ce que vous tapez, alors que les autres lignes de texte constituent la rponse du systme. Par exemple, dans cette squence :% uname Linux

le systme fournit une invite %. Vous entrez la commande uname. Le systme rpond en achant Linux. Le titre de chaque listing inclut un nom de chier entre parenthses. Si vous saisissez le listing, sauvegardez-le dans un chier portant ce nom. Vous pouvez galement tlcharger les codes sources depuis le site Web3 de Programmation Avance Sous Linux (http:// www.newriders.com ou http://www.advancedlinuxprogramming.com). Nous avons crit ce livre et dvelopp les programmes quil prsente en utilisant la distribution Red Hat 6.2 de GNU/Linux. Cette distribution comprend la version 2.2.14 du noyau Linux, la version 2.1.3 de la bibliothque GNU C et la version EGCS 1.1.2 du compilateur C GNU. Les informations et programmes de ce livre devraient tre valables pour les autres versions et distibutions de GNU/Linux, y compris les sries 2.4 du noyau Linux et les sries 2.2 de la bibliothque GNU C.

3

En anglais.

Premire partie

Programmation UNIX Avance avec Linux

1

Table des Matires1 2 3 4 5 Pour commencer crire des logiciels GNU/Linux de qualit Processus Threads Communication interprocessus 5 17 41 55 85

4

TABLE DES MATIRES

Chapitre 1

Pour commencer Ce chapitre prsente les tapes de base ncessaires la cration dun programmeLinux en C ou C++. En particulier, il explique comment crer et modier un code source C ou C++, compiler ce code et dboguer le rsultat. Si vous tes dj familier avec la programmation sous Linux, vous pouvez aller directement au Chapitre 2, crire des logiciels GNU/Linux de qualit ; lisez attentivement la Section 2.3, crire et utiliser des bibliothques , pour plus dinformations sur la comparaison des ditions de liens statique et dynamique que vous ne connaissez peut-tre pas. Dans la suite de ce livre, nous supposerons que vous tes familier avec le langage de programmation C ou C++ et avec les fonctions les plus courantes de la bibliothque C standard. Les exemples de code source dans ce livre sont en C, except lorsquils montrent une fonctionnalit ou une dicult propre au C++. Nous supposerons galement que vous savez comment eectuer les oprations lmentaires avec le shell de commande Linux, comme crer des rpertoires et copier des chiers. Comme beaucoup de programmeurs Linux ont commenc programmer dans un environnement Windows, nous soulignerons occasionnellement les similitudes et les contrastes entre Windows et Linux.

1.1

Lditeur Emacs

Un diteur est le programme que vous utilisez pour diter le code source. Beaucoup dditeurs dirents sont disponibles sous Linux, mais le plus populaire et celui orant le plus de fonctionnalits est certainement GNU Emacs. Si vous tes familier avec un autre diteur, vous pouvez certainement lutiliser la place. Rien dans le reste du livre ne dpend de lutilisation dEmacs. Si vous navez pas dj un diteur favori sous Linux, vous pouvez continuer avec le mini-didacticiel fourni ici. Si vous aimez Emacs et voulez en savoir plus sur ses fonctionnalits avances, vous pouvez lire un des nombreux livres disponibles sur le sujet. Un excellent didacticiel, Introduction GNU Emacs, a t crit par Debra Cameron, Bill Rosenblatt et Eric Raymond (OReilly 1997). 5

6 propos dEmacs

CHAPITRE 1. POUR COMMENCER

Emacs est beaucoup plus quun simple diteur. Il sagit dun programme incroyablement puissant, tel point que chez CodeSourcery, il est appel aectueusement le Seul Vrai Programme (One True Program), ou simplement OTP pour faire court. Vous pouvez crire et lire vos e-mails depuis Emacs et vous pouvez le personnaliser et ltendre de faon trop vaste pour que nous en parlions ici. Vous pouvez mme surfer sur le Web depuis Emacs !

1.1.1

Ouvrir un chier Source C ou C++

Vous pouvez lancer Emacs en saisissant emacs suivi de la touche Entre dans votre terminal. Lorsque Emacs a dmarr, vous pouvez utiliser les menus situs dans la partie suprieure pour crer un nouveau chier source. Cliquez sur le menu File, slectionnez Open File puis saisissez le nom du chier que vous voulez ouvrir dans le minibuer au bas de lcran1 . Si vous voulez crer un chier source C, utilisez un nom de chier se terminant par .c ou .h. Si vous dsirez crer un chier C++, utilisez un nom de chier se terminant par .cpp, .hpp, .cxx, .hxx, .C ou .H. Lorsque le chier est ouvert, vous pouvez taper comme vous le feriez dans un programme de traitement de texte. Pour sauvegarder le chier, slectionnez lentre Save Buer dans le menu File. Lorsque vous avez termin dutiliser Emacs, vous pouvez choisir loption Exit Emacs dans le menu File. Si vous naimez pas cliquer, vous pouvez utiliser les raccourcis clavier pour ouvrir ou fermer un chier et sortir dEmacs. Pour ouvrir un chier, saisissez C-x C-f (C-x signie de maintenir la touche Control enfonce tout en appuyant sur la touche x). Pour sauvegarder un chier, saisissez C-x C-s. Pour sortir dEmacs, saisissez simplement C-x C-c. Si vous voulez devenir un peu plus familier avec Emacs, slectionnez lentre Emacs Tutorial dans le menu Help. Le didacticiel vous propose quantit dastuces sur lutilisation ecace dEmacs.

1.1.2

Formatage automatique

Si vous tes un habitu de la programmation dans un Environnement de Dveloppement Intgr (Integrated Development Evironment, IDE), vous tes habitu lassistance au formatage fourni par lditeur. Emacs peut vous orir le mme type de fonctionnalit. Si vous ouvrez un chier C ou C++, Emacs devine quil contient du code, pas simplement du texte ordinaire. Si vous appuyez sur la touche Tab sur une ligne blanche, Emacs dplace le curseur au point dindentation appropri. Si vous appuyez sur la touche Tab sur une ligne contenant dj du texte, Emacs indente le texte. Donc, par exemple, supposons que vous ayez saisi ce qui suit :int main () { printf ( " Hello , world \ n " ) ; }

Si vous pressez la touche Tab sur la ligne de lappel printf, Emacs reformatera votre code comme suit :1

Si vous nutilisez pas un systme X Window, vous devrez appuyer sur F10 pour accder aux menus.

1.2. COMPILER AVEC GCCint main () { printf ( " Hello , world \ n " ) ; }

7

Remarquez comment la ligne a t correctement indente. En utilisant Emacs, vous verrez comment il peut vous aider eectuer toutes sortes de tches de formatage compliques. Si vous tes ambitieux, vous pouvez programmer Emacs pour eectuer littralement tout formatage que vous pourriez imaginer. Des gens ont utilis ces fonctionnalits pour implmenter des modications dEmacs pour diter peu prs nimporte quelle sorte de documents, implmenter des jeux2 et des interfaces vers des bases de donnes.

1.1.3

Coloration syntaxique

En plus de formater votre code, Emacs peut faciliter la lecture du code C et C++ en colorant les dirents lments de sa syntaxe. Par exemple, Emacs peut colorer les mots cls dune certaine faon, les types intgrs comme int dune autre et les commentaires dune autre encore. Utiliser des couleurs facilite la dtection de certaines erreurs de syntaxe courantes La faon la plus simple dactiver la coloration est dditer le chier ~/.emacs et dy insrer la chane suivante :( global - font - lock - mode t )

Sauvegardez le chier, sortez dEmacs et redmarrez-le. Ouvrez un chier C ou C++ et admirez ! Vous pouvez avoir remarqu que la chane que vous avez insr dans votre .emacs ressemble du code LISP. Cest parce-quil sagit de code LISP ! La plus grande partie dEmacs est crite en LISP. Vous pouvez ajouter des fonctionnalits Emacs en crivant en LISP.

1.2

Compiler avec GCC

Un compilateur transforme un code source lisible par un humain en code objet lisible par la machine qui peut tre excut. Les compilateurs de choix disponibles sur les systmes Linux font tous partie de la GNU Compiler Collection, plus communment appele GCC3 . GCC inclut galement des compilateurs C, C++, Java, Objective-C, Fortran et Chill. Ce livre se concentre plus particulirement sur la programmation C et C++. Supposons que vous ayez un projet comme celui du Listing 1.2 avec un chier source C++ (reciprocal.cpp) et un chier source C (main.c) comme dans le Listing 1.1. Ces deux chiers sont supposs tre compils puis lis entre eux pour produire un programme appel reciprocal4 . Ce programme calcule linverse dun entier. Listing 1.1 (main.c) Fichier source C1 2 3

# include < stdio .h >

Essayez la commande M-x dunnet si vous voulez jouer un jeu daventures en mode texte lancienne. Pour plus dinformations sur GCC, visitez http://gcc.gnu.org/. 4 Sous Windows, les excutables portent habituellement des noms se terminant en .exe. Les programmes Linux par contre, nont habituellement pas dextension. Donc, lquivalent Windows de ce programme sappellerait probablement reciprocal.exe ; la version Linux est tout simplement reciprocal.

82 3 4 5 6 7 8 9 10 11 12

CHAPITRE 1. POUR COMMENCER# include < stdlib .h > # include " reciprocal . hpp " int main ( int argc , char ** argv ) { int i ; i = atoi ( argv [1]) ; printf ( " L inverse de % d est % g \ n " , i , reciprocal ( i ) ) ; return 0; }

Listing 1.2 (reciprocal.cpp) Fichier source C++1 2 3 4 5 6 7 8

# include < cassert > # include " reciprocal . hpp " double reciprocal ( int i ) { // i doit tre diffrent de zro assert ( i != 0) ; return 1.0/ i ; }

Il y a galement un chier dentte appel reciprocal.hpp (voir Listing 1.3). Listing 1.3 (reciprocal.hpp) Fichier dentte1 2 3 4 5 6 7 8 9

# ifdef __cplusplus extern " C " { # endif extern double reciprocal ( int i ) ; # ifdef __cplusplus } # endif

La premire tape est de traduire le code C et C++ en code objet.

1.2.1

Compiler un chier source isol

Le nom du compilateur C est gcc. Pour compiler un chier source C, utilisez loption -c. Donc par exemple, cette commande compile le chier source main.c :% gcc -c main.c

Le chier objet rsultant est appel main.o. Le compilateur C++ sappelle g++. Son mode opratoire est trs similaire gcc ; la compilation de reciprocal.cpp seectue via la commande suivante :% g++ -c reciprocal.cpp

Loption -c indique g++ de ne compiler le chier que sous forme dun chier objet ; sans cela, g++ tenterait de lier le programme an de produire un excutable. Une fois cette commande saisie, vous obtenez un chier objet appel reciprocal.o. Vous aurez probablement besoin de quelques autres options pour compiler un programme dune taille raisonnable. Loption -I est utilise pour indiquer GCC o rechercher les chiers

1.2. COMPILER AVEC GCC

9

dentte. Par dfaut, GCC cherche dans le rpertoire courant et dans les rpertoires o les enttes des bibliothques standards sont installs. Si vous avez besoin dinclure des chiers dentte situs un autre endroit, vous aurez besoin de loption -I. Par exemple, supposons que votre projet ait un rpertoire appel src, pour les chiers source, et un autre appel include. Vous compileriez reciprocal.cpp comme ceci pour indiquer g++ quil doit utiliser en plus le rpertoire include pour trouver reciprocal.hpp :% g++ -c -I ../include reciprocal.cpp

Parfois, vous pourriez vouloir dnir des macros au niveau de la ligne de commande. Par exemple, dans du code de production, vous ne voudriez pas du surcot de lassertion prsente dans reciprocal.cpp ; elle nest l que pour vous aider dboguer votre programme. Vous dsactivez la vrication en dnissant la macro NDEBUG. Vous pourriez ajouter un #define explicite dans reciprocal.cpp, mais cela ncessiterait de modier la source elle-mme. Il est plus simple de dnir NDEBUG sur la ligne de commande, comme ceci :% g++ -c -D NDEBUG reciprocal.cpp

Si vous aviez voulu donner une valeur particulire NDEBUG, vous auriez pu saisir quelque chose de ce genre :% g++ -c -D NDEBUG=3 reciprocal.cpp

Si vous tiez rellement en train de compiler du code de production, vous voudriez probablement que GCC optimise le code an quil sexcute aussi rapidement que possible. Vous pouvez le faire en utilisant loption en ligne de commande -O2 (GCC a plusieurs niveaux doptimisation ; le second niveau convient pour la plupart des programmes). Par exemple, ce qui suit compile reciprocal.cpp avec les optimisations actives :% g++ -c -O2 reciprocal.cpp

Notez que le fait de compiler avec les optimisations peut rendre votre programme plus dicile dboguer avec un dbogueur (voyez la Section 1.4, Dboguer avec le dbogueur GNU (GDB) ). De plus, dans certaines circonstances, compiler avec les optimisations peut rvler des bogues qui napparaissaient pas auparavant. Vous pouvez passer un certain nombre dautres options gcc et g++. Le meilleur moyen den obtenir une liste complte est de consulter la documentation en ligne. Vous pouvez le faire en saisissant ceci linvite de commandes :% info gcc

1.2.2

Lier les chiers objet

Maintenant que vous avez compil main.c et reciprocal.cpp, vous devez les lier. Vous devriez toujours utiliser g++ pour lier un programme qui contient du code C++, mme sil contient galement du code C. Si votre programme ne contient que du code C, vous devriez utiliser gcc la place. Comme ce programme contient la fois du code C et du code C++, vous devriez utiliser g++, comme ceci :

10% g++ -o reciprocal main.o reciprocal.o

CHAPITRE 1. POUR COMMENCER

Loption -o donne le nom du chier gnrer lissue de ltape ddition de liens. Vous pouvez maintenant lancer reciprocal comme ceci :% ./reciprocal 7 Linverse de 7 est 0.142857

Comme vous pouvez le voir, g++ a automatiquement inclus les bibliothques dexcution C standards contenant limplmentation de printf. Si vous aviez eu besoin de lier une autre bibliothque (comme un kit de dveloppement dinterfaces utilisateur), vous auriez indiqu la bibliothque avec loption -l. Sous Linux, les noms des bibliothques commencent quasiment toujours par lib. Par exemple, la bibliothque du Module dAuthentication Enchable (Pluggable Authentication Module, PAM) est appele libpam.a. Pour inclure libpam.a lors de ldition de liens, vous utiliserez une commande de ce type :% g++ -o reciprocal main.o reciprocal.o -lpam

Le compilateur ajoutera automatiquement le prxe lib et le suxe .a. Comme avec les chiers dentte, lditeur de liens recherche les bibliothques dans certains emplacements standards, ce qui inclut les rpertoires /lib et /usr/lib qui contiennent les bibliothques systme standards. Si vous voulez que lditeur de liens cherche en plus dans dautres rpertoires, vous devez utiliser loption -L, qui est lquivalent de loption -I dont nous avons parl plus tt. Vous pouvez utiliser cette commande pour indiquer lditeur de liens de rechercher les bibliothques dans le rpertoire /usr/local/lib/pam avant de les rechercher dans les emplacements habituels :% g++ -o reciprocal main.o reciprocal.o -L/usr/local/lib/pam -lpam

Bien que vous nayez pas utiliser loption -I pour que le prprocesseur eectue ses recherches dans le rpertoire courant, vous devez utiliser loption -L pour que lditeur de liens le fasse. Par exemple, vous devrez utiliser ce qui suit pour indiquer lditeur de liens de rechercher la bibliothque test dans le rpertoire courant :% gcc -o app app.o -L. -ltest

1.3

Automatiser le processus avec GNU Make

Si vous tes habitu la programmation pour le systme dexploitation Windows, vous avez probablement lhabitude de travailler avec un Environnement de Dveloppement Intgr (IDE). Vous ajoutez les chiers votre projet puis lIDE compile ce projet automatiquement. Bien que des IDE soient disponibles pour Linux, ce livre nen traite pas. Au lieu de cela, il vous montre comment vous servir de GNU Make pour recompiler votre code automatiquement, comme le font en fait la majorit des programmeurs Linux. Lide de base derrire make est simple. Vous indiquez make quelles cibles vous dsirez compiler puis donnez des rgles expliquant comment les compiler. Vous pouvez galement spcier des dpendances qui indiquent quand une cible particulire doit tre recompile.

1.3. AUTOMATISER LE PROCESSUS AVEC GNU MAKE

11

Dans notre projet exemple reciprocal, il y a trois cibles videntes : reciprocal.o, main.o et reciprocal lui-mme. Vous avez dj lesprit les rgles ncessaires la compilation de ces cibles sous forme des lignes de commande donnes prcdemment. Les dpendances ncessitent un minimum de rexion. Il est clair que reciprocal dpend de reciprocal.o et main.o car vous ne pouvez pas passer ltape ddition de liens avant davoir compil chacun des chiers objets. Les chiers objets doivent tre recompils chaque fois que le chier source correspondant est modi. Il y a encore une subtilit : une modication de reciprocal.hpp doit entraner la recompilation des deux chiers objets car les deux chiers source incluent ce chier dentte. En plus des cibles videntes, il devrait toujours y avoir une cible clean. Cette cible supprime tous les chiers objets gnrs an de pouvoir recommencer sur des bases saines. La rgle pour cette cible utilise la commande rm pour supprimer les chiers. Vous pouvez fournir toutes ces informations make en les plaant dans un chier nomm Makefile. Voici ce quil contient :reciprocal : main . o reciprocal . o g ++ $ ( CFLAGS ) -o reciprocal main . o reciprocal . o main . o : main . c reciprocal . hpp gcc $ ( CFLAGS ) -c main . c reciprocal . o : reciprocal . cpp reciprocal . hpp g ++ $ ( CFLAGS ) -c reciprocal . cpp clean : rm -f *. o reciprocal

Vous pouvez voir que les cibles sont listes sur la gauche, suivies de deux-points puis des dpendances. La rgle pour la construction dune cible est place sur la ligne suivante (ignorez le $(CFLAGS) pour linstant). La ligne dcrivant la rgle doit commencer par un caractre de tabulation ou make ne sy retrouvera pas. Si vous ditez votre Makefile dans Emacs, Emacs vous assistera dans le formatage. Si vous supprimez les chiers objets que vous avez dj cr et que vous tapez simplement :% make

sur la ligne de commande, vous obtiendrez la sortie suivante :% make gcc -c main.c g++ -c reciprocal.cpp g++ -o reciprocal main.o reciprocal.o

Vous constatez que make a automatiquement compil les chiers objet puis les a lis. Si vous modiez maintenant main.c dune faon quelconque puis saisissez make de nouveau, vous obtiendrez la sortie suivante :% make gcc -c main.c g++ -o reciprocal main.o reciprocal.o

Vous constatez que make recompile main.o et rdite les liens, il ne recompile pas reciprocal.cpp car aucune des dpendances de reciprocal.o na chang.

12

CHAPITRE 1. POUR COMMENCER

$(CFLAGS) est une variable de make. Vous pouvez dnir cette variable soit dans le Makefile lui-mme soit sur la ligne de commande. GNU make substituera la variable par sa valeur lorsquil excutera la rgle. Donc, par exemple, pour recompiler avec les optimisations actives, vous procderiez de la faon suivante :% make clean rm -f *.o reciprocal % make CFLAGS=-O2 gcc -O2 -c main.c g++ -O2 -c reciprocal.cpp g++ -O2 -o reciprocal main.o reciprocal.o

Notez que le drapeau -O2 a t insr la place de $(CFLAGS) dans les rgles. Dans cette section, nous navons prsent que les capacits les plus basiques de make. Vous pourrez en apprendre plus grce la commande suivante :% info make

Dans ce manuel, vous trouverez des informations sur la faon de rendre un Makefile plus simple maintenir, comment rduire le nombre de rgles crire et comment calculer automatiquement les dpendances. Vous pouvez galement trouver plus dinformations dans GNU, Autoconf, Automake et Libtool de Gary V. Vaughan, Ben Ellitson, Tom Tromey et Ian Lance Taylor (New Riders Publishing, 2000).

1.4

Dboguer avec le dbogueur GNU (GDB)

Le dbogueur est le programme que vous utilisez pour trouver pourquoi votre programme ne se comporte pas comme vous pensez quil le devrait. Vous y aurez souvent recours5 . Le dbogueur GNU (GNU debugger, GDB) est le dbogueur utilis par la plupart des programmeurs Linux. Vous pouvez utiliser GDB pour excuter votre code pas pas, poser des points darrt et examiner les valeurs des variables locales.

1.4.1

Compiler avec les informations de dbogage

Pour utiliser GDB, vous devez compiler en activant les informations de dbogage. Pour cela, ajoutez loption -g sur la ligne de commande de compilation. Si vous utilisez un Makefile comme nous lavons expliqu plus haut, vous pouvez vous contenter de positionner CFLAGS -g lors de lexcution de make, comme ceci :% make gcc -g g++ -g g++ -g CFLAGS=-g -c main.c -c reciprocal.cpp -o reciprocal main.o reciprocal.o

Lorsque vous compilez avec -g, le compilateur inclut des informations supplmentaires dans les chiers objets et les excutables. Le dbogueur utilise ces informations pour savoir quelle adresse correspond quelle ligne et dans quel chier source, acher les valeurs des variables et ctera.5

. . . moins que votre programme ne fonctionne toujours du premier coup.

1.4. DBOGUER AVEC LE DBOGUEUR GNU (GDB)

13

1.4.2

Lancer GDB

Vous pouvez dmarrer gdb en saisissant :% gdb reciprocal

Lorsque GDB dmarre, il ache linvite :(gdb)

La premire tape est de lancer votre programme au sein du dbogueur. Entrez simplement la commande run et les arguments du programme. Essayez de lancer le programme sans aucun argument, comme ceci :(gdb) run Starting program: reciprocal Program received signal SIGSEGV, Segmentation fault. __strtol_internal (nptr=0x0, endptr=0x0, base=10, group=0) at strtol.c:287 287 strtol.c: No such file or directory. (gdb)

Le problme est quil ny a aucun code de contrle derreur dans main. Le programme attend un argument, mais dans ce cas, il nen a reu aucun. Le message SIGSEGV indique un plantage du programme. GDB sait que le plantage a eu lieu dans une fonction appele __strtol_internal. Cette fonction fait partie de la bibliothque standard, et les sources ne sont pas installes ce qui explique le message No such le or directory (Fichier ou rpertoire inexistant). Vous pouvez observer la pile en utilisant la commande where :(gdb) where #0 __strtol_internal (nptr=0x0, endptr=0x0, base=10, group=0) at strtol.c:287 #1 0x40096fb6 in atoi (nptr=0x0) at ../stdlib/stdlib.h:251 #2 0x804863e in main (argc=1, argv=0xbffff5e4) at main.c:8

Vous pouvez voir daprs cet extrait que main a appel la fonction atoi avec un pointeurNULL ce qui est la source de lerreur.

Vous pouvez remonter de deux niveaux dans la pile jusqu atteindre main en utilisant la commande up :(gdb) up 2 #2 0x804863e in main (argc=1, argv=0xbffff5e4) at main.c:8 8 i = atoi (argv[1]);

Notez que GDB est capable de trouver le chier source main.c et quil ache la ligne contenant lappel de fonction erron. Vous pouvez inspecter la valeurs des variables en utilisant la commande print :(gdb) print argv[1] $2 = 0x0

Cela conrme que le problme vient dun pointeur NULL pass atoi. Vous pouvez placer un point darrt en utilisant la commande break :

14(gdb) break main Breakpoint 1 at 0x804862e: file main.c, line 8.

CHAPITRE 1. POUR COMMENCER

Cette commande place un point darrt sur la premire ligne de main6 . Essayez maintenant de relancer le programme avec un argument, comme ceci :(gdb) run 7 Starting program: reciprocal 7 Breakpoint 1, main (argc=2, argv=0xbffff5e4) at main.c:8 8 i = atoi (argv[1])

Vous remarquez que le dbogueur sest arrt au niveau du point darrt. Vous pouvez passer linstruction se trouvant aprs lappel atoi en utilisant la commande next :9 gdb) next printf ("Linverse de %d est %g\n", i, reciprocal (i));

Si vous voulez voir ce qui se passe lintrieur de la fonction reciprocal, utilisez la commande step, comme ceci :(gdb) step reciprocal (i=7) at reciprocal.cpp:6 6 assert (i != 0);

Vous tes maintenant au sein de la fonction reciprocal. Vous pouvez trouver plus commode dexcuter gdb au sein dEmacs plutt que de le lancer directement depuis la ligne de commande. Utilisez la commande M-x gdb pour dmarrer gdb dans une fentre Emacs. Si vous stoppez au niveau dun point darrt, Emacs ouvre automatiquement le chier source appropri. Il est plus facile de se rendre compte de ce qui se passe en visualisant le chier dans son ensemble plutt quune seule ligne.

1.5

Obtenir plus dinformations

Quasiment toutes les distributions Linux disposent dune masse importante de documentation. Vous pourriez apprendre la plupart des choses dont nous allons parler dans ce livre simplement en lisant la documentation de votre distribution Linux (bien que cela vous prendrait probablement plus de temps). La documentation nest cependant pas toujours trs bien organise, donc la partie la plus subtile est de trouver ce dont vous avez besoin. La documentation date quelquefois un peu, aussi, prenez tout ce que vous y trouvez avec un certain recul. Si le systme ne se comporte pas comme le dit une page de manuel, cest peut-tre parce que celle-ci est obsolte. Pour vous aider naviguer, voici les sources dinformation les plus utiles sur la programmation avance sous Linux.Certaines personnes ont fait la remarque que break main (NdT. littralement casser main ) est amusant car vous ne vous en servez en fait uniquement lorsque main a dj un problme.6

1.5. OBTENIR PLUS DINFORMATIONS

15

1.5.1

Pages de manuel

Les distributions Linux incluent des pages de manuel pour les commandes les plus courantes, les appels systme et les fonctions de la bibliothque standard. Les pages de manuel sont divises en sections numrotes ; pour les programmeurs, les plus importantes sont celles-ci : (1) Commandes utilisateur (2) Appels systme (3) Fonctions de la bibliothque standard (8) Commandes systme/dadministration Les numros indiquent les sections des pages de manuel. Les pages de manuel de Linux sont installes sur votre systme ; utilisez la commande man pour y accder. Pour accder une page de manuel, invoquez simplement man nom, o nom est un nom de commande ou de fonction. Dans un petit nombre de cas, le mme nom apparat dans plusieurs sections ; vous pouvez indiquer explicitement la section en plaant son numro devant le nom. Par exemple, si vous saisissez la commande suivante, vous obtiendrez la page de manuel pour la commande sleep (dans la section 1 des pages de manuel Linux) :% man sleep

Pour visualiser la page de manuel de la fonction sleep de la bibliothque standard, utilisez cette commande :% man 3 sleep

Chaque page de manuel comprend un rsum sur une ligne de la commande ou fonction. La commande whatis nom liste toutes les pages de manuel (de toutes les sections) pour une commande ou une fonction correspondant nom. Si vous ntes pas sr de la commande ou fonction utiliser, vous pouvez eectuer une recherche par mot-cl sur les rsums via man -k mot-cl. Les pages de manuel contiennent des informations trs utiles et devraient tre le premier endroit vers lequel vous orientez vos recherches. La page de manuel dune commande dcrit ses options en ligne de commande et leurs arguments, ses entres et sorties, ses codes derreur, sa conguration et ce quelle fait. La page de manuel dun appel systme ou dune fonction de bibliothque dcrit les paramtres et valeurs de retour, liste les codes derreur et les eets de bord et spcie le chier dentte inclure si vous utilisez la fonction.

1.5.2

Info

Le systme de documentation Info contient des informations plus dtailles pour beaucoup de composants fondamentaux du systme GNU/Linux et quelques autres programmes. Les pages Info sont des documents hypertextes, similaires aux pages Web. Pour lancer le navigateur texte Info, tapez simplement info linvite de commande. Vous obtiendrez un menu avec les documents Info prsents sur votre systme (appuyez sur Ctrl+H pour acher les touches permettant de naviguer au sein dun document Info). Parmi les documents Info les plus utiles, on trouve :

16

CHAPITRE 1. POUR COMMENCER

gcc Le compilateur gcc libc La bibliothque C GNU, avec beaucoup dappels systme gdb Le dbogueur GNU emacs Lditeur de texte Emacs info Le systme Info lui-mme Presque tous les outils de programmation standards sous Linux (y compris ld, lditeur de liens ; as, lassembleur et gprof, le proler) sont accompagns de pages Info trs utiles. Vous pouvez accder directement un document Info en particulier en indiquant le nom de la page sur la ligne de commandes :% info libc

Si vous programmez la plupart du temps sous Emacs, vous pouvez accder au navigateur Info intgr en appuyant sur M-x info ou C-h i.

1.5.3

Fichiers dentte

Vous pouvez en apprendre beaucoup sur les fonctions systme disponibles et comment les utiliser en observant les chiers dentte. Ils sont placs dans /usr/include et /usr/include/sys. Si vous obtenez des erreurs de compilation lors de lutilisation dun appel systme, par exemple, regardez le chier dentte correspondant pour vrier que la signature de la fonction est la mme que celle prsente sur la page de manuel. Sur les systmes Linux, beaucoup de dtails obscurs sur le fonctionnement des appels systmes apparaissent dans les chiers dentte situs dans les rpertoires /usr/include/bits, /usr/include/asm et /usr/include/linux. Ainsi, le chier /usr/include/bits/signum.h dnit les valeurs numriques des signaux (dcrits dans la Section 3.3, Signaux du Chapitre 3, Processus ). Ces chiers dentte constituent une bonne lecture pour les esprits curieux. Ne les incluez pas directement dans vos programmes, cependant ; utilisez toujours les chiers dentte de /usr/include ou ceux mentionns dans la page de manuel de la fonction que vous utilisez.

1.5.4

Code source

Nous sommes dans lOpen Source, non ? Le juge en dernier ressort de la faon dont doit fonctionner le systme est le code source, et par chance pour les programmeurs Linux, ce code source est disponible librement. Il y a des chances pour que votre systme Linux comprenne tout le code source du systme et des programmes fournis ; si ce nest pas le cas, vous avez le droit, selon les termes de la Licence Publique Gnrale GNU, de les demander au distributeur (le code source nest toutefois pas forcment install. Consultez la documentation de votre distribution pour savoir comment linstaller). Le code source du noyau Linux lui-mme est habituellement stock sous /usr/src/linux. Si ce livre vous laisse sur votre faim concernant les dtails sur le fonctionnement des processus, de la mmoire partage et des priphriques systme, vous pouvez toujours apprendre directement partir du code. La plupart des fonctions dcrites dans ce livre sont implmentes dans la bibliothque C GNU ; consultez la documentation de votre distribution pour connatre lemplacement du code source de la bibliothque C.

Chapitre 2

crire des logiciels GNU/Linux de qualite chapitre prsente quelques techniques de base utilises par la plupart des programmeurs GNU/Linux. En suivant grossirement les indications que nous allons prsenter, vous serez mme dcrire des programmes qui fonctionnent correctement au sein de lenvironnement GNU/Linux et correspondent ce quattendent les utilisateurs au niveau de leur faon de fonctionner.

C

2.1

Interaction avec lenvironnement dexcution

Lorsque vous avez tudi pour la premire fois le langage C ou C++, vous avez appris que la fonction spciale main est le point dentre principal pour un programme. Lorsque le systme dexploitation excute votre programme, il ore un certain nombre de fonctionnalits qui aident le programme communiquer avec le systme dexploitation et lutilisateur. Vous avez probablement entendu parler des deux paramtres de main, habituellement appels argc et argv, qui reoivent les entres de votre programme. Vous avez appris que stdin et stdout (ou les ux cin et cout en C++) fournissent une entre et une sortie via la console. Ces fonctionnalits sont fournies par les langages C et C++, et elles interagissent avec le systme dune certaine faon. GNU/Linux fournit en plus dautres moyens dinteragir avec lenvironnement dexcution.

2.1.1

La liste darguments

Vous lancez un programme depuis linvite de commandes en saisissant le nom du programme. ventuellement, vous pouvez passer plus dinformations au programme en ajoutant un ou plusieurs mots aprs le nom du programme, spars par des espaces. Ce sont des arguments de ligne de commande (vous pouvez passer un argument contenant des espaces en le plaant entre guillemets). Plus gnralement, on appelle cela la liste darguments du programme car ils ne viennent pas ncessairement de la ligne de commande. Dans le Chapitre 3, Processus , 17

18

CHAPITRE 2. CRIRE DES LOGICIELS GNU/LINUX DE QUALIT

vous verrez un autre moyen dinvoquer un programme, avec lequel un programme peut indiquer directement la liste darguments dun autre programme. Lorsquun programme est invoqu depuis la ligne de commande, la liste darguments contient toute la ligne de commande, y compris le nom du programme et tout argument qui aurait pu lui tre pass. Supposons, par exemple, que vous invoquiez la commande ls depuis une invite de commandes pour acher le contenu du rpertoire racine et les tailles de chiers correspondantes au moyen de cette commande :% ls -s /

La liste darguments que le programme ls reoit est compose de trois lments. Le premier est le nom du programme lui-mme, saisi sur la ligne de commande, savoir ls. Les second et troisime lment sont les deux arguments de ligne de commande, -s et /. La fonction main de votre programme peut accder la liste darguments via ses paramtres argc et argv (si vous ne les utilisez pas, vous pouvez simplement les omettre). Le premier paramtre, argc, est un entier qui indique le nombre dlments dans la liste. Le second paramtre, argv, est un tableau de pointeurs sur des caractres. La taille du tableau est argc, et les lments du tableau pointent vers les lments de la liste darguments, qui sont des chanes termines par zro. Utiliser des arguments de ligne de commande consiste examiner le contenu de argc et argv. Si vous ntes pas intress par le nom du programme, noubliez pas dignorer le premier lment. Le Listing 2.1 montre lutilisation de argv et argc. Listing 2.1 (arglist.c) Utiliser argc et argv1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

# include < stdio .h > int main ( int argc , char * argv []) { printf ( " Le nom de ce programme est % s .\ n " , argv [0]) ; printf ( " Ce programme a t invoqu avec % d arguments .\ n " , argc - 1) ; /* A -t - on spcifi des arguments sur la ligne de commande ? */ if ( argc > 1) { /* Oui , les afficher . */ int i ; printf ( " Les arguments sont :\ n " ) ; for ( i = 1; i < argc ; ++ i ) printf ( " % s \ n " , argv [ i ]) ; } return 0; }

2.1.2

Conventions de la ligne de commande GNU/Linux

Presque tous les programmes GNU/Linux obissent un ensemble de conventions concernant linterprtation des arguments de la ligne de commande. Les arguments attendus par un programme sont classs en deux catgories : les options (ou drapeaux 1 ) et les autres arguments. Les options modient le comportement du programme, alors que les autres arguments fournissent des entres (par exemple, les noms des chiers dentre).1

NdT. ags en anglais

2.1. INTERACTION AVEC LENVIRONNEMENT DEXCUTION

19

Les options peuvent prendre deux formes : Les options courtes sont formes dun seul tiret et dun caractre isol (habituellement une lettre en majuscule ou en minuscule). Elles sont plus rapides saisir. Les options longues sont formes de deux tirets suivis dun nom compos de lettres majuscules, minuscules et de tirets. Les options longues sont plus faciles retenir et lire (dans les scripts shell par exemple). Gnralement, un programme propose une version courte et une version longue pour la plupart des options quil prend en charge, la premire pour la brivet et la seconde pour la lisibilit. Par exemple, la plupart des programmes acceptent les options -h et help et les traitent de faon identique. Normalement, lorsquun programme est invoqu depuis la ligne de commande, les options suivent immdiatement le nom du programme. Certaines options attendent un argument immdiatement leur suite. Beaucoup de programmes, par exemple, acceptent loption output foo pour indiquer que les sorties du programme doivent tre rediriges vers un chier appel foo. Aprs les options, il peut y avoir dautres arguments de ligne de commande, typiquement les chiers ou les donnes dentre. Par exemple, la commande ls -s / ache le contenu du rpertoire racine. Loption -s modie le comportement par dfaut de ls en lui demandant dacher la taille (en kilooctets) de chaque entre. Largument / indique ls quel rpertoire lister. Loption size est synonyme de -s, donc la commande aurait pu tre invoque sous la forme ls size /. Les Standards de Codage GNU dressent la liste des noms doptions en ligne de commande couramment utiliss. Si vous avez lintention de proposer des options identiques, il est conseill dutiliser les noms prconiss dans les standards de codage. Votre programme se comportera de faon similaire aux autres et sera donc plus simple prendre en main pour les utilisateurs. Vous pouvez consulter les grandes lignes des Standards de Codage GNU propos des options en ligne de commandes via la commande suivante depuis une invite de commande sur la plupart des systmes GNU/Linux :% info "(standards)User Interfaces"

2.1.3

Utiliser getopt_long

Lanalyse des options de la ligne de commande est une corve. Heureusement, la bibliothque GNU C fournit une fonction que vous pouvez utiliser dans les programmes C et C++ pour vous faciliter la tche (quoiquelle reste toujours quelque peu ennuyeuse). Cette fonction, getopt_long, interprte la fois les options courtes et longues. Si vous utilisez cette fonction, incluez le chier den-tte . Supposons par exemple que vous criviez un programme acceptant les trois options du Tableau 2.1. Le programme doit par ailleurs accepter zro ou plusieurs arguments supplmentaires, qui sont les noms de chiers dentre. Pour utiliser getopt_long, vous devez fournir deux structures de donnes. La premire est une chane contenant les options courtes valables, chacune sur une lettre. Une option qui requiert un argument est suivie par deux-points. Pour notre programme, la chane ho :v indique que les options valides sont -h, -o et -v, la seconde devant tre suivie dun argument.

20

CHAPITRE 2. CRIRE DES LOGICIELS GNU/LINUX DE QUALIT

Forme Courte -h -o nom fichier -v

Tab. 2.1 Exemple dOptions pour un Programme Forme Longue Fonction help Ache laide-mmoire et quitte output nom fichier Indique le nom du chier de sortie verbose Ache des messages dtaills

Pour indiquer les options longues disponibles, vous devez construire un tableau dlments struct option. Chaque lment correspond une option longue et dispose de quatre champs. Gnralement, le premier champ est le nom de loption longue (sous forme dune chane de caractres, sans les deux tirets) ; le second est 1 si loption prend un argument, 0 sinon ; le troisime est NULL et le quatrime est un caractre qui indique loption courte synonyme de loption longue. Tous les champs du dernier lment doivent tre zro. Vous pouvez construire le tableau comme ceci :const struct option long_options [] = { { " help " , 0 , NULL , h } , { " output " , 1 , NULL , o } , { " verbose " , 0 , NULL , v } , { NULL , 0 , NULL , 0 } };

Vous invoquez la fonction getopt_long en lui passant les arguments argc et argv de main , la chane de caractres dcrivant les options courtes et le tableau dlments struct option dcrivant les options longues. chaque fois que vous appelez getopt_long, il nanalyse quune seule option et renvoie la lettre de loption courte pour cette option ou -1 sil ny a plus doption analyser. Typiquement, vous appelez getopt_long dans une boucle, pour traiter toutes les options que lutilisateur a spci et en les grant au sein dune structure switch. Si getopt_long rencontre une option invalide (une option que vous navez pas indique comme tant une option courte ou longue valide), il ache un message derreur et renvoie le caractre ? (un point dinterrogation). La plupart des programmes sinterrompent dans ce cas, ventuellement aprs avoir ach des informations sur lutilisation de la commande. Lorsque le traitement dune option requiert un argument, la variable globale optarg pointe vers le texte constituant cet argument. Une fois que getopt_long a ni danalyser toutes les options, la variable globale optind contient lindex (dans argv) du premier argument qui nest pas une option. Le Listing 2.2 montre un exemple dutilisation de getopt_long pour le traitement des arguments. Listing 2.2 (getopt_long.c) Utilisation de getopt_long1 2 3 4 5 6 7 8

# include < getopt .h > # include < stdio .h > # include < stdlib .h > /* Nom du programme . */ const char * program_name ; /* Envoie les informations sur l utilisation de la commande vers STREAM ( typiquement stdout ou stderr ) et quitte le programme avec EXIT_CODE . Ne retourne jamais . */

2.1. INTERACTION AVEC LENVIRONNEMENT DEXCUTION9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70

21

void print_usage ( FILE * stream , int exit_code ) { fprintf ( stream , " Utilisation : % s options [ fichierentre ...]\ n " , program_name ) ; fprintf ( stream , " -h -- help Affiche ce message .\ n " " -o -- output filename Redirige la sortie vers un fichier .\ n " " -v -- verbose Affiche des messages dtaills .\ n " ) ; exit ( exit_code ) ; } /* Point d entre du programme . ARGC contient le nombre d lments de la liste d arguments ; ARGV est un tableau de pointeurs vers ceux - ci . */ int main ( int argc , char * argv []) { int next_option ; /* Chane listant les lettres valides pour les options courtes . */ const char * const short_options = " ho : v " ; /* Tableau dcrivant les options longues valides . */ const struct option long_options [] = { { " help " , 0 , NULL , h } , { " output " , 1 , NULL , o } , { " verbose " , 0 , NULL , v } , /* Requis la fin du tableau . */ { NULL , 0 , NULL , 0 } }; /* Nom du fichier vers lequel rediriger les sorties , ou NULL pour la sortie standard . */ const char * o u t p u t _ fi l e n a m e = NULL ; /* Indique si l on doit afficher les messages dtaills . */ int verbose = 0; /* Mmorise le nom du programme , afin de l intgrer aux messages . Le nom est contenu dans argv [0]. */ program_name = argv [0]; do { next_option = getopt_long ( argc , argv , short_options , long_options , NULL ) ; switch ( next_option ) { case h : /* -h or -- help */ /* L utilisateur a demand l aide - mmoire . L affiche sur la sortie standard et quitte avec le code de sortie 0 ( fin normale ) . */ print_usage ( stdout , 0) ; case o : /* -o ou -- output */ /* Cette option prend un argument , le nom du fichier de sortie . */ o u t pu t _ f i l e na m e = optarg ; break ; case v : /* -v ou -- verbose */ verbose = 1; break ; case ? : /* L utilisateur a saisi une option invalide . */ /* Affiche l aide - mmoire sur le flux d erreur et sort avec le code de sortie un ( indiquant une fin anormale ) . */ print_usage ( stderr , 1) ; case -1: /* Fin des options . */ break ; default : /* Quelque chose d autre : inattendu . */ abort () ; } } while ( next_option != -1) ; /* Fin des options . OPTIND pointe vers le premier argument qui n est pas une option . des fins de dmonstration , nous les affichons si l option verbose est spcifie . */

2271 72 73 74 75 76 77 78

CHAPITRE 2. CRIRE DES LOGICIELS GNU/LINUX DE QUALITif ( verbose ) { int i ; for ( i = optind ; i < argc ; ++ i ) printf ( " Argument : % s \ n " , argv [ i ]) ; } /* Le programme principal se place ici . */ return 0; }

Lutilisation de getopt_long peut sembler ncessiter beaucoup de travail, mais crire le code ncessaire lanalyse des options de la ligne de commandes vous-mme vous prendrait encore plus longtemps. La fonction getopt_long est trs sophistique et permet une grande exibilit dans la spcication des types doptions acceptes. Cependant, il est bon de se tenir lcart des fonctionnalits les plus avances et de conserver la structure doptions basiques dcrite ici.

2.1.4

E/S standards

La bibliothque standard du C fournit des ux dentre et de sortie standards (stdin et stdout respectivement). Il sont utiliss par printf, scanf et dautres fonctions de la bibliothque. Dans la tradition UNIX, lutilisation de lentre et de la sortie standard est frquente pour les programmes GNU/Linux. Cela permet lenchanement de plusieurs programmes au moyen des pipes2 et de la redirection des entres et sorties (consultez la page de manuel de votre shell pour savoir comment les utiliser). La bibliothque C fournit galement stderr, le ux derreurs standard. Il est dusage que les programmes envoient les messages derreur et davertissement vers la sortie des erreurs standard plutt que vers la sortie standard. Cela permet aux utilisateurs de sparer les messages normaux des messages derreur, par exemple, en redirigeant la sortie standard vers un chier tout en laissant les erreurs sacher sur la console. La fonction fprintf peut tre utilise pour crire sur stderr, par exemple :% fprintf ( stderr , " Erreur : ... " ) ;

Ces trois ux sont galement accessibles via les commandes dE/S UNIX de bas niveau (read, write, etc), par le biais des descripteurs de chiers. Les descripteurs de chiers sont 0 pour stdin, 1 pour stdout et 2 pour stderr. Lors de lappel dun programme, il peut tre utile de rediriger la fois la sortie standard et la sortie des erreurs vers un chier ou un pipe. La syntaxe utiliser dire selon les shells ; la voici pour les shells de type Bourne (y compris bash, le shell par dfaut sur la plupart des distributions GNU/Linux) :% programme > fichier_sortie.txt 2>&1 % programme 2>&1 | filtre

La syntaxe 2>&1 indique que le descripteur de chiers 2 (stderr) doit tre fusionn avec le descripteur de chiers 1 (stdout). Notez que 2>&1 doit tre plac aprs une redirection vers un chier (premier exemple) mais avant une redirection vers un pipe (second exemple). Notez que stdout est buerise. Les donnes crites sur stdout ne sont pas envoyes vers la console (ou un autre dispositif si lon utilise la redirection) avant que le tampon ne soit plein,2

NdT. appels aussi parfois tubes ou canaux.

2.1. INTERACTION AVEC LENVIRONNEMENT DEXCUTION

23

que le programme ne se termine normalement ou que stdout soit ferm. Vous pouvez purger explicitement le tampon de la faon suivante :fflush ( stdout ) ;

Par contre, stderr nest pas buerise ; les donnes crites sur stderr sont envoyes directement vers la console3 . Cela peut conduire des rsultats quelque peu surprenants. Par exemple, cette boucle nache pas un point toutes les secondes ; au lieu de cela, les points sont placs dans le tampon, et ils sont achs par groupe lorsque le tampon est plein.while (1) { printf ( " . " ) ; sleep (1) ; }

Avec cette boucle, par contre, les points sont achs au rythme dun par seconde :while (1) { fprintf ( stderr , " . " ) ; sleep (1) ; }

2.1.5

Codes de sortie de programme

Lorsquun programme se termine, il indique son tat au moyen dun code de sortie. Le code de sortie est un entier court ; par convention, un code de sortie zro indique une n normale, tandis quun code dirent de zro signale quune erreur est survenue. Certains programmes utilisent des codes de sortie dirents de zro varis pour distinguer les direntes erreurs. Avec la plupart des shells, il est possible dobtenir le code de sortie du dernier programme excut en utilisant la variable spciale $ ?. Voici un exemple dans lequel la commande ls est invoque deux fois et son code de sortie est ach aprs chaque invocation. Dans le premier cas, ls se termine correctement et renvoie le code de sortie 0. Dans le second cas, ls rencontre une erreur (car le chier spci sur la ligne de commande nexiste pas) et renvoie donc un code de sortie dirent de 0.% ls / bin coda etc lib misc nfs proc boot dev home lost+found mnt opt root % echo $? 0 % ls fichierinexistant ls: fichierinexistant: Aucun fichier ou rpertoire de ce type % echo $? 1

Un programme C ou C++ donne son code de sortie en le retournant depuis la fonction main. Il y a dautres mthodes pour fournir un code de sortie et des codes de sortie spciaux sont assigns aux programmes qui se terminent de faon anormale (sur un signal). Ils sont traits de manire plus approfondie dans le Chapitre 3.3 En C++, la mme distinction sapplique cout et cerr, respectivement. Notez que le token endl purge un ux en plus dy envoyer un caractre de nouvelle ligne ; si vous ne voulez pas purger le ux (pour des raisons de performances par exemple), utilisez une constante de nouvelle ligne, n, la place.

24

CHAPITRE 2. CRIRE DES LOGICIELS GNU/LINUX DE QUALIT

2.1.6

Lenvironnement

GNU/Linux fournit tout programme sexcutant un environnement. Lenvironnement est une collection de paires variable/valeur. Les variables denvironnement et leurs valeurs sont des chanes de caractres. Par convention, les variables denvironnement sont en majuscules dimprimerie. Vous tes probablement dj familier avec quelques variables denvironnement courantes. Par exemple : USER contient votre nom dutilisateur. HOME contient le chemin de votre rpertoire personnel. PATH contient une liste de rpertoires spars par deux-points dans lesquels Linux recherche les commandes que vous invoquez. DISPLAY contient le nom et le numro dachage du serveur X Window sur lequel apparaissent les fentres des programmes graphiques X Window. Votre shell, comme nimporte quel autre programme, dispose dun environnement. Les shells fournissent des mthodes pour examiner et modier lenvironnement directement. Pour acher lenvironnement courant de votre shell, invoquez le programme printenv. Tous les shells nutilisent pas la mme syntaxe pour la manipulation des variables denvironnement ; voici la syntaxe pour les shells de type Bourne : Le shell cre automatiquement une variable shell pour chaque variable denvironnement quil trouve, an que vous puissiez accder aux valeurs des variables denvironnement en utilisant la syntaxe $nomvar. Par exemple :% echo $USER samuel % echo $HOME /home/samuel

Vous pouvez utiliser la commande export pour exporter une variable shell vers lenvironnement. Par exemple, pour positionner la variable denvironnement EDITOR, vous utiliserez ceci :% EDITOR=emacs % export EDITOR

Ou, pour faire plus court :% export EDITOR=emacs

Dans un programme, vous pouvez accder une variable denvironnement au moyen de la fonction getenv de . Cette fonction accepte le nom dune variable et renvoie la valeur correspondante sous forme dune chane de caractres ou NULL si cette variable nest pas dnie dans lenvironnement. Pour positionner ou supprimer une variable denvironnement, utilisez les fonctions setenv et unsetenv, respectivement. numrer toutes les variables de lenvironnement est un petit peu plus subtil. Pour cela, vous devez accder une variable globale spciale appele environ, qui est dnie dans la bibliothque C GNU. Cette variable, de type char**, est un tableau termin par NULL de pointeurs vers des chanes de caractres. Chaque chane contient une variable denvironnement, sous la forme VARIABLE=valeur.

2.1. INTERACTION AVEC LENVIRONNEMENT DEXCUTION

25

Le programme du Listing 2.3, par exemple, ache tout lenvironnement en bouclant sur le tableau environ. Listing 2.3 (print-env.c) Acher lEnvironnement dExcution1 2 3 4 5 6 7 8 9 10

# include < stdio .h > /* La variable ENVIRON contient l environnement . */ extern char ** environ ; int main () { char ** var ; for ( var = environ ; * var != NULL ; ++ var ) printf ( " % s \ n " , * var ) ; return 0; }

Ne modiez pas environ vous-mme ; utilisez plutt les fonctions setenv et getenv. Lorsquun nouveau programme est lanc, il hrite dune copie de lenvironnement du programme qui la invoqu (le shell, sil a t invoqu de faon interactive). Donc, par exemple, les programmes que vous lancez depuis le shell peuvent examiner les valeurs des variables denvironnement que vous positionnez dans le shell. Les variables denvironnement sont couramment utilises pour passer des paramtres de conguration aux programmes. Supposons, par exemple, que vous criviez un programme qui se connecte un serveur Internet pour obtenir des informations. Vous pourriez crire le programme de faon ce que le nom du serveur soit saisi sur la ligne de commande. Cependant, supposons que le nom du serveur ne soit pas quelque chose que les utilisateurs changent trs souvent. Vous pouvez utiliser une variable denvironnement spciale disons SERVER_NAME pour spcier le nom du serveur ; si cette variable nexiste pas, une valeur par dfaut est utilise. Une partie de votre programme pourrait ressembler au Listing 2.4. Listing 2.4 (client.c) Extrait dun Programme Client Rseau1 2 3 4 5 6 7 8 9 10 11 12 13

# include < stdio .h > # include < stdlib .h > int main () { char * server_name = getenv ( " SERVER_NAME " ) ; if ( server_name == NULL ) /* La variable SERVER_NAME n est pas dfinie . Utilisation de la valeur par dfaut . */ server_name = " server . my - company . com " ; printf ( " Accs au serveur % s \ n " , server_name ) ; /* Accder au serveur ici ... */ return 0; }

Supposons que ce programme sappelle client. En admettant que vous nayez pas dni la variable SERVER_NAME, la valeur par dfaut pour le nom du serveur est utilise :% client Accs au serveur server.my-company.com

Mais il est facile de spcier un serveur dirent :% export SERVER_NAME=backup-server.elsewhere.net % client Accs au serveur backup-server.elsewhere.net

26

CHAPITRE 2. CRIRE DES LOGICIELS GNU/LINUX DE QUALIT

2.1.7

Utilisation de chiers temporaires

Parfois, un programme a besoin de crer un chier temporaire, pour stocker un gros volume de donnes temporairement ou passer des informations un autre programme. Sur les systmes GNU/Linux, les chiers temporaires sont stocks dans le rpertoire /tmp. Lors de lutilisation de chiers temporaires, vous devez viter les piges suivants : Plus dune copie de votre programme peuvent tre lances simultanment (par le mme utilisateur ou par des utilisateurs dirents). Les copies devraient utiliser des noms de chiers temporaires dirents an dviter les collisions. Les permissions du chier devraient tre dnies de faon viter quun utilisateur non autoris puisse altrer la manire dont sexcute le programme en modiant ou remplaant le chier temporaire. Les noms des chiers temporaires devraient tre gnrs de faon imprvisible de lextrieur ; autrement, un attaquant pourrait exploiter le dlai entre le test dexistence du nom de chier et louverture du nouveau chier temporaire. GNU/Linux fournit des fonctions, mkstemp et tmpfile, qui soccupent de ces problmes votre place (en plus de fonctions qui ne le font pas). Le choix de la fonction dpend de lutilisation que vous aurez du chier, savoir le passer un autre programme ou utiliser les fonctions dE/S UNIX (open, write, etc.) ou les fonctions de ux dE/S de la bibliothque C (fopen, fprintf, etc.). Utilisation de mkstemp La fonction mkstemp cre un nom de chier temporaire partir dun modle de nom de chier, cre le chier avec les permissions adquates an que seul lutilisateur courant puisse y accder, et ouvre le chier en lecture/criture. Le modle de nom de chier est une chane de caractres se terminant par "XXXXXX" (six X majuscules) ; mkstemp remplace les X par des caractres an que le nom de chier soit unique. La valeur de retour est un descripteur de chier ; utilisez les fonctions de la famille de write pour crire dans le chier temporaire. Les chiers temporaires crs par mkstemp ne sont pas eacs automatiquement. Cest vous de supprimer le chier lorsque vous nen avez plus besoin (les programmeurs devraient tre attentifs supprimer les chiers temporaires ; dans le cas contraire, le systme de chiers /tmp pourrait se remplir, rendant le systme inutilisable). Si le chier temporaire nest destin qu tre utilis par le programme et ne sera pas transmis un autre programme, cest une bonne ide dappeler unlink sur le chier temporaire immdiatement. La fonction unlink supprime lentre de rpertoire correspondant un chier, mais comme le systme tient jour un dcompte du nombre de rfrences sur chaque chier, un chier nest pas eac tant quil reste un descripteur de chier ouvert pour ce chier. Comme Linux ferme les descripteurs de chiers quand un programme se termine, le chier temporaire sera eac mme si votre programme se termine de manire anormale. Les deux fonctions du Listing 2.5 prsentent lutilisation de mkstemp. Utilises ensemble, ces fonctions facilitent lcriture dun tampon mmoire vers un chier temporaire (an que la mmoire puisse tre libre ou rutilise) et sa relecture ultrieure.

2.1. INTERACTION AVEC LENVIRONNEMENT DEXCUTION Listing 2.5 (temp_le.c) Utiliser mkstemp1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47

27

# include < stdlib .h > # include < unistd .h > /* Handle sur un fichier temporaire cr avec w r i te _ t e m p _ fi l e . Avec cette implmentation , il s agit d un descripteur de fichier . */ typedef int t e m p _ f i l e _ h a n d l e ; /* crit LENGTH octets de BUFFER dans un fichier temporaire . Unlink est appel immdiatement sur le fichier temporaire . Renvoie un handle sur le fichier temporaire . */ t e m p _ f i l e _ h a n d l e w r i t e _t e m p _ f il e ( char * buffer , size_t length ) { /* Cre le nom du fichier et le fichier . XXXXXX sera remplac par des caractres donnant un nom de fichier unique . */ char temp_filename [] = " / tmp / temp_file . XXXXXX " ; int fd = mkstemp ( temp_filename ) ; /* Appelle unlink immdiatement afin que le fichier soit supprim ds que le descripteur sera ferm . */ unlink ( temp_filename ) ; /* crit le nombre d octets dans le fichier avant tout . */ write ( fd , & length , sizeof ( length ) ) ; /* crit des donnes proprement dites . */ write ( fd , buffer , length ) ; /* Utilise le descripteur de fichier comme handle sur le fichier temporaire . */ return fd ; } /* Lit le contenu du fichier temporaire TEMP_FILE cr avec w r i te _ t e m p _ fi l e . La valeur de retour est un tampon nouvellement allou avec ce contenu , que l appelant doit librer avec free . * LENGTH est renseign avec la taille du contenu , en octets . Le fichier temporaire est supprim . */ char * re ad _t emp _f il e ( t e m p _ f i l e _ h a n d l e temp_file , size_t * length ) { char * buffer ; /* Le handle sur TEMP_FILE est le descripteur du fichier temporaire . */ int fd = temp_file ; /* Se place au dbut du fichier . */ lseek ( fd , 0 , SEEK_SET ) ; /* Lit les donnes depuis le fichier temporaire . */ read ( fd , length , sizeof (* length ) ) ; /* Alloue un buffer et lit les donnes . */ buffer = ( char *) malloc (* length ) ; read ( fd , buffer , * length ) ; /* Ferme le descripteur de fichier ce qui provoque la suppression du fichier temporaire . */ close ( fd ) ; return buffer ; }

Utilisation de tmple Si vous utilisez les fonctions dE/S de la bibliothque C et navez pas besoin de passer le chier temporaire un autre programme, vous pouvez utiliser la fonction tmpfile. Elle cre et ouvre un chier temporaire, et renvoie un pointeur de chier. Le chier temporaire a dj t trait par unlink, comme dans lexemple prcdent, an dtre supprim automatiquement lorsque le pointeur sur le chier est ferm (avec fclose) ou lorsque le programme se termine.

28

CHAPITRE 2. CRIRE DES LOGICIELS GNU/LINUX DE QUALIT

GNU/Linux propose diverses autres fonctions pour gnrer des chiers temporaires et des noms de chiers temporaires, par exemple, mktemp, tmpnam et tempnam. Nutilisez pas ces fonctions, cependant, car elles sourent des problmes de abilit et de scurit mentionns plus haut.

2.2

Crer du code robuste

crire des programmes sexcutant correctement dans des conditions dutilisation normales est dur ; crire des programmes qui se comportent avec lgance dans des conditions derreur lest encore plus. Cette section propose quelques techniques de codage pour trouver les bogues plus tt et pour dtecter et traiter les problmes dans un programme en cours dexcution. Les exemples de code prsents plus loin dans ce livre nincluent dlibrment pas de code de vrication derreur ou de rcupration sur erreur car cela risquerait dalourdir le code et de masquer la fonctionnalit prsente. Cependant, lexemple nal du Chapitre 11, Application GNU/Linux dIllustration , est l pour montrer comment utiliser ces techniques pour produire des applications robustes.

2.2.1

Utiliser assert

Un bon objectif conserver lesprit en permanence lorsque lon code des programmes est que des bogues ou des erreurs inattendues devraient conduire un crash du programme, ds que possible. Cela vous aidera trouver les bogues plus tt dans les cycles de dveloppement et de tests. Il est dicile de reprer les dysfonctionnements qui ne se signalent pas deux-mmes et napparaissent pas av