The Unix and Internet Fundamentals HOWTO by Eric S. Raymond v1.1, 3 Décembre 1998 Ce document décrit les principes fondamentaux des ordinateurs de type PC, des systèmes d'exploitation de type UNIX et d'Internet dans un langage non technique. (Traduction française Philippe Malinge pmal@easynet.fr) ______________________________________________________________________ Table des matières 1. Introduction 1.1 Sujet de ce document 1.2 Ressources rattachées 1.3 Nouvelles versions de ce document 1.4 Réactions et corrections 2. Anatomie de base de votre ordinateur 3. Que se passe-t-il lorsque vous allumez votre ordinateur ? 4. Que se passe-t-il lorsque vous exécutez des programmes à partir du shell? 5. Comment marchent les périphériques d'entrée et les interruptions ? 6. Comment mon ordinateur fait-il plusieurs choses en même temps ? 7. Comment mon ordinateur évite aux processus d'empiéter les uns sur les autres ? 8. Comment mon ordinateur stocke des choses sur le disque ? 8.1 Bas niveau du disque et structure du système de fichiers 8.2 Noms de fichiers et répertoires 8.3 Points de montage 8.4 Comment un fichier est retrouvé ? 8.5 Comment les choses peuvent dégénérer ? 9. Comment fonctionnent les langages d'ordinateur ? 9.1 Langages compilés 9.2 Langages interprétés 9.3 Langages P-code 10. Comment Internet fonctionne ? 10.1 Noms et localisations 10.2 Paquets et routeurs 10.3 TCP et IP 10.4 HTTP, un protocole d'application ______________________________________________________________________ 11.. IInnttrroodduuccttiioonn 11..11.. SSuujjeett ddee ccee ddooccuummeenntt Ce document est conçu pour aider les utilisateurs de Linux et d'Internet qui désirent apprendre en faisant. Bien que ce soit un bon moyen d'acquérir des compétences, quelquefois cela laisse de singulières lacunes dans la connaissance des bases -- lacunes qui peuvent rendre difficile la réflexion créative ou perturber fortement, par manque d'un modèle mental clair sur ce qu'il devrait se passer. J'essaierai de décrire clairement, dans un langage simple, comment tout marche. La présentation sera adaptée aux personnes qui utilisent Unix ou Linux sur du matériel de type PC. Cependant, je ferai ici couramment référence à 'Unix' : ce que je décrirai se retrouvera sur toutes les plates-formes et sur toutes les variantes d'Unix. Je suppose que vous utilisez un PC avec un processeur de type Intel. Les détails diffèrent quelque peu si vous utilisez un processeur Alpha ou PowerPC ou une autre machine Unix, mais les concepts de base restent les mêmes. Je ne voudrais pas répéter les choses, alors vous allez devoir faire attention, mais cela veut dire que vous retiendrez chaque mot que vous lirez. C'est une bonne idée que de tout parcourir rapidement la première fois ; vous devrez y revenir et relire un certain nombre de fois afin de digérer ce que vous avez appris. C'est un document en permanente évolution. Je prévois d'ajouter des chapitres en réponse aux feedbacks, ainsi vous pourrez périodiquement le passer en revue. 11..22.. RReessssoouurrcceess rraattttaacchhééeess Si vous lisez dans l'espoir d'apprendre comment 'hacker', vous devrez lire How To Become A Hacker FAQ . Il y a beaucoup de liens vers d'autres ressources utiles. 11..33.. NNoouuvveelllleess vveerrssiioonnss ddee ccee ddooccuummeenntt Les nouvelles versions de 'Unix and Internet Fundamentals HOWTO' seront postées périodiquement dans comp.os.linux.help et et news.answers . Elles pourront être téléchargées à partir de divers sites Linux WWW ou FTP, y compris la page d'accueil du LDP. Vous pouvez accéder à la dernière version (en anglais) de ce document sur le World Wide Web via l'URL . 11..44.. RRééaaccttiioonnss eett ccoorrrreeccttiioonnss Si vous avez des questions ou des commentaires à propos de ce document, vous pouvez envoyer vos courriers électroniques à Eric S. Raymond, à esr@thyrsus.com. Toutes suggestions ou critiques seront les bienvenues. Seront spécialement appréciés les liens hypertexte vers des explications plus détaillées ou vers des concepts propres. Si vous trouvez des erreurs dans ce document, faites-le moi savoir afin que je puisse les corriger dans la nouvelle version. Merci. 22.. AAnnaattoommiiee ddee bbaassee ddee vvoottrree oorrddiinnaatteeuurr Votre ordinateur possède un processeur à l'intérieur duquel se font réellement les calculs. Il possède une mémoire interne (ce que les gens DOS/Windows désignent par ``RAM'' et que les gens UNIX désignent souvent par ``core''). Le processeur et la mémoire résident sur la _c_a_r_t_e _m_è_r_e qui est le coeur de votre ordinateur. Votre ordinateur possède un écran et un clavier. Il a un (ou des) disque(s) dur(s) et un lecteur de disquettes. L'écran et vos disques ont des _c_a_r_t_e_s _c_o_n_t_r_ô_l_e_u_r que l'on connecte sur la carte mère et qui aident l'ordinateur à piloter ces périphériques externes. Votre clavier est trop simple pour nécessiter une carte séparée ; le contrôleur est intégré dans le châssis du clavier.) Nous décrirons plus tard en détails comment fonctionnent ces périphériques. Pour l'instant, quelques notions de base afin de garder à l'esprit comment ils fonctionnent ensemble : Tous les éléments internes de votre ordinateur sont connectés par un _b_u_s. Physiquement, le bus est ce sur quoi vous connectez vos cartes contrôleur (carte vidéo, contrôleur disque, carte son si vous en avez une). Le bus est l'autoroute empruntée par les données entre votre processeur, votre écran, votre disque et le reste. Le processeur, qui fait tout marcher, ne peut réellement voir tous les éléments directement ; il doit communiquer avec eux via le bus, le seul sous-système qui soit effectivement très rapide, qui accède directement à la mémoire (le core). Afin que les programmes puissent s'exécuter, ils doivent être en mémoire _c_o_r_e. Lorsque votre ordinateur lit un programme ou une donnée sur le disque, il se passe réellement les choses suivantes : le processeur utilise le bus pour envoyer une requête de lecture du disque à votre contrôleur de disque. Quelques instants après, le contrôleur de disque utilise le bus pour signaler à l'ordinateur qu'il a lu la donnée et qu'il l'a mise à un certain endroit de la mémoire. Le processeur peut utiliser le bus pour aller chercher ce qu'il y a à cet endroit de la mémoire. Votre clavier et votre écran communiquent également avec le processeur via le bus mais d'une manière plus simple. Nous exposerons cela plus loin. Pour l'instant vous en savez suffisamment pour comprendre ce qu'il se passe lorsque vous allumez votre ordinateur. 33.. QQuuee ssee ppaassssee--tt--iill lloorrssqquuee vvoouuss aalllluummeezz vvoottrree oorrddiinnaatteeuurr ?? Un ordinateur sans programme qui s'exécute est juste un tas inerte d'électronique. La première chose que doit faire un ordinateur lorsqu'il est allumé est de démarrer un programme spécial appelé _s_y_s_t_è_m_e _d_'_e_x_p_l_o_i_t_a_t_i_o_n. Le travail du système d'exploitation est d'aider les autres programmes de l'ordinateur à travailler, en traitant les détails méprisables du contrôle du matériel de l'ordinateur. Le processus de démarrage du système d'exploitation est appelé _b_o_o_t_i_n_g (originalement c'était _b_o_o_t_s_t_r_a_p_p_i_n_g _(_l_a_ç_a_g_e _d_e_s _c_h_a_u_s_s_u_r_e_s_), allusion à la difficulté d'enfiler soi même ses chaussures `par les lacets'. Votre ordinateur sait comment booter car les instructions de boot sont stockées dans un de ses composants, le composant BIOS (ou Basic Input/Output System). Le composant BIOS dit où aller chercher, à une place fixe sur le disque dur de plus basse adresse (le _d_i_s_q_u_e _d_e _b_o_o_t), un programme spécial appelé _c_h_a_r_g_e_u_r _d_e _b_o_o_t _(_b_o_o_t _l_o_a_d_e_r_) (sous Linux le chargeur de boot est appelé LILO). Le chargeur de boot est chargé en mémoire puis lancé. Le travail du chargeur de boot est de démarrer le système d'exploitation réel. Le chargeur fait cela en allant chercher un _n_o_y_a_u, en le chargeant en mémoire et en le démarrant. Lorsque vous bootez Linux et voyez "LILO" sur l'écran suivi par une succession de points, c'est qu'il charge le noyau. (Chaque point signifie qu'il vient de charger un autre _b_l_o_c _d_u _d_i_s_q_u_e du code du noyau.) (Vous pouvez vous demander pourquoi le BIOS ne charge pas le noyau directement -- pourquoi ces deux étapes du processus avec le chargeur de boot ? C'est que le BIOS n'est pas vraiment intelligent. En fait il est carrément stupide, et Linux ne l'utilise jamais après avoir booté. A l'origine, j'ai programmé sur des PC 8-bits primitifs avec de petits disques : littéralement ils ne pouvaient accéder à suffisamment de disque pour charger le noyau directement. L'étape du chargeur de boot vous permet de démarrer plusieurs systèmes d'exploitation à partir de différents emplacements de votre disque, dans le cas où Unix n'est pas assez bon pour vous.) Une fois que le noyau démarre, il doit chercher autour de lui, trouver le reste du matériel et être prêt pour exécuter des programmes. Il fait cela en non pas en fouillant à des adresses mémoire ordinaires mais plutôt à des _p_o_r_t_s _d_'_E_n_t_r_é_e_/_S_o_r_t_i_e -- des adresses spéciales du bus, sensées avoir une carte contrôleur de périphériques en attente de commandes à cet endroit. Le noyau ne fouille pas au hasard ; il a un ensemble de connaissances qui lui permet de savoir ce qu'il est sensé trouver ici, et comment les contrôleurs répondraient s'ils étaient présents. Ce processus est appelé _E_x_p_l_o_r_a_t_i_o_n _a_u_t_o_m_a_t_i_q_u_e. La plupart des messages que vous voyez au moment du boot sont l'exploration de votre matériel par le noyau à travers les ports d'Entrée/Sortie, le chiffrage de ce qui est disponible et l'adaptation à votre machine. Le noyau Linux est extrêmement bon pour cela, meilleur que la plupart des autres Unix et _t_e_l_l_e_m_e_n_t meilleur que DOS ou Windows. En fait, beaucoup de vieux adeptes de Linux pensent que l'ingéniosité des explorations de Linux lors du boot (qui lui permettent de s'installer relativement simplement) ont été une raison de s'épanouir dans le monde des expériences des Unix libres pour attirer une masse critique d'utilisateurs. Mais rendre le noyau complètement chargé et s'exécutant n'est pas la fin du processus de boot ; c'est juste la première étape (quelquefois appelée _n_i_v_e_a_u _d_'_e_x_é_c_u_t_i_o_n _1 _(_r_u_n _l_e_v_e_l _1_)). L'étape suivante du noyau est de s'assurer que vos disques sont OK. Les systèmes de fichiers sur disques sont des choses fragiles ; s'ils ont été endommagés par une panne matérielle ou par une coupure soudaine d'alimentation électrique, il y a de bonnes raisons de rétablir l'intégrité avant que votre Unix ne puisse aller plus loin. Nous parlerons plus tard de ce que l'on dit à propos de ``comment les systèmes de fichiers peuvent devenir mauvais''. L'étape suivante du noyau est de lancer plusieurs _d_é_m_o_n_s. Un démon est un programme comme un spouleur d'imprimante, un serveur de mail ou un serveur WWW qui se cache en arrière-plan en attendant d'avoir des choses à faire. Ces programmes spéciaux doivent coordonner plusieurs requêtes qui peuvent entrer en conflit. Il y a des démons car il est souvent plus facile d'écrire un programme qui s'exécute constamment et qui sait tout des requêtes, plutôt que d'essayer de s'assurer qu'un troupeau de copies (chacune traitant une requête et toutes s'exécutant en même temps) ne se gêneraient pas mutuellement. La collection particulière de démons que le système démarre peut varier, mais inclura presque toujours un spouleur d'imprimante (un démon garde- barrière de votre imprimante). Une fois que tous les démons ont démarré, nous sommes dans le _n_i_v_e_a_u _d_'_e_x_é_c_u_t_i_o_n _2 _(_r_u_n _l_e_v_e_l _2_). L'étape suivante est la préparation pour les utilisateurs. Le noyau démarre une copie d'un programme appelé getty pour surveiller votre console (et peut être d'autres copies pour surveiller des ports-série entrants) Ce programme est celui duquel jaillit le prompt login sur votre console. Nous sommes maintenant dans le _n_i_v_e_a_u _d_'_e_x_é_c_u_t_i_o_n _3 _(_r_u_n _l_e_v_e_l _3_) et prêts pour votre connexion et l'exécution de vos programmes. Quand vous vous connectez (en donnant un nom et un mot de passe), vous vous identifiez auprès de getty et de l'ordinateur. Il exécute maintenant un programme appelé (assez naturellement) login, qui réalise des tâches ancillaires et démarre un interpréteur de commandes, le _s_h_e_l_l. (Oui getty et login pourraient être un seul et même programme. Ils sont séparés pour des raisons historiques que nous n'expliciterons pas ici.) Dans la section suivante, nous parlerons de ce qui se passe lorsque vous exécutez des programmes à partir du shell. 44.. QQuuee ssee ppaassssee--tt--iill lloorrssqquuee vvoouuss eexxééccuutteezz ddeess pprrooggrraammmmeess àà ppaarrttiirr dduu sshheellll?? Le shell normal vous donne le prompt '$' que vous voyez après vous être connecté (cependant vous pouvez le modifier et mettre autre chose). Nous ne parlerons pas de la syntaxe du shell et des choses faciles que vous pouvez voir sur votre écran ici ; alors que nous l'ordinateur. Après la phase de boot et avant que vous n'exécutiez un programme, vous pouvez penser à votre ordinateur comme étant un zoo de processus qui attendent qu'il se passe quelque chose. Ils attendent des _é_v_é_n_e_m_e_n_t_s. Un événement, ce peut être l'enfoncement d'une touche ou un déplacement de la souris. Ou, si votre machine est connectée à un réseau, un événement peut être un paquet de données venant de ce réseau. Le noyau est un de ces processus. C'en est un spécial, car il contrôle le moment où les autres processus _u_t_i_l_i_s_a_t_e_u_r peuvent s'exécuter, et c'est normalement le seul processus qui accède directement au matériel de la machine. En fait, les processus utilisateurs font des requêtes au noyau lorsqu'ils veulent obtenir une entrée clavier, écrire sur votre écran, lire ou écrire sur votre disque ou juste autre chose que consommer quelques bits en mémoire. Ces requêtes sont appelées _a_p_p_e_l_s _s_y_s_t_è_m_e. Normalement toute Entrée/Sortie passe par le noyau de manière à ce qu'il puisse ordonnancer les opérations et éviter ainsi aux processus de se marcher les uns sur les autres. Quelques processus utilisateur sont autorisés à contourner le noyau, habituellement en ayant accès directement aux ports d'Entrée/Sortie. Les serveurs X (les programmes qui traitent les requêtes graphiques des autres programmes sur la plupart des machines Unix) sont des exemples classiques. Mais nous n'avons pas vu de serveur X pour l'instant ; vous êtes au prompt du shell sur une console en mode caractères. Le shell est juste un processus utilisateur, et non un processus particulièrement spécial. Il attend vos frappes sur les touches du clavier, écoutant (à travers le noyau) le port d'E/S du clavier. Comme le noyau les voit, il les affiche sur votre écran et les passe au shell. Le shell essaie de les interpréter comme étant des commandes. Tapez `ls' suivi de `Enter' afin de lister le contenu d'un répertoire. Le shell applique ses règles internes pour évaluer la commande que vous voulez exécuter dans le fichier `/bin/ls'. Il fait un appel système en demandant au noyau de lancer `/bin/ls' comme un processus _f_i_l_s et donne son accès à l'écran et au clavier à travers le noyau. Le shell se rendort en attendant que 'ls' se termine. Lorsque /bin/ls est terminé, il dit au noyau qu'il a terminé en effectuant un appel système _e_x_i_t. Le noyau réveille le shell et lui dit qu'il peut continuer à s'exécuter. Le shell affiche un autre prompt et attend une autre ligne en entrée. D'autres choses peuvent être faites pendant l'exécution de `ls', cependant (nous supposerons que la liste du répertoire est très longue). Vous pourriez basculer sur une autre console virtuelle, vous connecter, et lancer une jeu de Quake par exemple. Ou bien, supposez que vous êtes connecté à Internet : votre machine peut envoyer ou recevoir des mails pendant que `/bin/ls' s'exécute. 55.. CCoommmmeenntt mmaarrcchheenntt lleess ppéérriipphhéérriiqquueess dd''eennttrrééee eett lleess iinntteerrrruuppttiioonnss ?? Votre clavier est un périphérique très simple ; simple car il génère un petit flux de données très lentement (sur un ordinateur standard). Lorsque vous relâchez une touche, cet événement est signalé par le câble du clavier qui va provoquer une _i_n_t_e_r_r_u_p_t_i_o_n _m_a_t_é_r_i_e_l. C'est au système d'exploitation de surveiller de telles interruptions. Pour chaque type possible d'interruption, il y a un _h_a_n_d_l_e_r _d_'_i_n_t_e_r_r_u_p_t_i_o_n, une partie du système d'exploitation dissimule toutes les données associées (comme la valeur touche enfoncée/touche relâchée) tant qu'elle ne peut être traitée. Ce que le fait le handler d'interruption disque pour votre clavier est de déposer la valeur de la touche dans une zone en bas de la mémoire (core). Ainsi elle sera disponible pour l'inspection lorsque le système d'exploitation passera le contrôle à n'importe quel programme supposé attendre présentement une entrée clavier. Des périphériques d'entrée plus complexes comme les disques travaillent de manière similaire. Précédemment nous faisions référence à un contrôleur de disques utilisant le bus pour signaler qu'une requête disque a bien été exécutée. Que se passe-t-il si ce disque reçoit une interruption ? Le handler de l'interruption disque copie alors la donnée trouvée dans la mémoire, pour une utilisation future par le programme qui en avait fait la demande. Chaque type d'interruption est associé à un _n_i_v_e_a_u _d_e _p_r_i_o_r_i_t_é. Les interruptions de plus basse priorité (comme les évènements clavier) sont traitées après celles de priorité supérieures (comme les tops d'horloge ou les événements disque). Unix a été conçu pour traiter prioritairement les types d'événements qui doivent être traités rapidement afin de conserver une machine sur laquelle les temps de réponse sont sont sans à-coup. Les messages que vous voyez pendant la phase de boot font référence à des numéros d'_I_R_Q. Vous devez être prévenus qu'une des causes les plus courantes de mauvaise configuration de votre matériel est d'avoir deux périphériques qui essaient d'utiliser la même IRQ, sans savoir ce que c'est réellement. La réponse est ici. IRQ est l'abbréviation de "Interrupt ReQuest". Le système d'exploitation a besoin de savoir au démarrage quel numéro d'interruption sera utilisé par chaque périphérique, ainsi il peut associer le handler adéquat pour chacun. Si deux périphériques différents essaient d'utiliser la même IRQ, les interruptions seraient quelquefois distribuées au mauvais handler. Cela est classique au moins au verrouillage du périphérique, et peut parfois déstabiliser le système d'exploitation, qu'il se "désintègre" ou qu'il se crashe. 66.. CCoommmmeenntt mmoonn oorrddiinnaatteeuurr ffaaiitt--iill pplluussiieeuurrss cchhoosseess eenn mmêêmmee tteemmppss ?? En fait, il ne le fait pas. Les ordinateurs ne peuvent traiter qu'une seule tâche (ou _p_r_o_c_e_s_s_u_s) à la fois. Mais un ordinateur peut changer de tâche très rapidement, et duper l'esprit humain en lui faisant croire qu'il fait plusieurs choses en même temps. C'est ce que l'on appelle le _t_e_m_p_s _p_a_r_t_a_g_é. Une des tâches du noyau est de gérer le temps partagé. C'est une partie dédiée à l'_o_r_d_o_n_n_a_n_c_e_u_r qui conserve chez lui toutes les informations sur les autres processus (non noyau) de votre environnement. Chaque 1/60 ème de seconde, une horloge avertit le noyau, générant une interruption horloge. L'ordonnanceur arrête le processus qui s'exécute, le suspend dans l'état, et donne le contrôle à un autre processus. 1/60 ème de seconde peut paraître peu de temps. Mais sur les microprocesseurs actuels c'est assez pour exécuter des dizaines de milliers d'instructions machine, ce qui permet d'effectuer beaucoup de choses. Même si vous avez plusieurs processus, chacun peut accomplir un petit peu sa tâche pendant ses tranches de temps. En pratique, un programme ne dispose pas de sa tranche de temps entière. Si une interruption arrive d'un périphérique d'E/S, le noyau arrêtera en réalité la tâche courante, exécutera le handler d'interruption et retournera à la tâche courante. Une tempête d'interruption de haute priorité peut interdire tout traitement normal ; ce mauvais comportement est appelé _d_é_f_a_i_t_e _(_t_h_r_a_s_h_i_n_g_) et est difficile à provoquer sur les Unix modernes. En fait, la vitesse des programmes est très rarement limitée par le temps machine qu'ils peuvent obtenir (il y a quelques exceptions à cette règle, comme la génération de son ou de graphiques en 3-D. Le plus souvent, les délais sont dus à l'attente, par le programme, des données d'un disque ou d'une connexion réseau. Un système d'exploitation qui peut supporter de manière routinière plusieurs processus est appelé "multitâche". Les systèmes d'exploitation de la famille Unix ont été conçus dès le début pour le multitâche et sont vraiment bons pour ça -- beaucoup plus efficaces que celui de Windows et MAC OS, pour lesquels le multitâche a été introduit a posteriori et qui le traitent plutôt pauvrement. Efficace, multitâche, fiable sont quelques-unes des raisons qui rendent Linux supérieur pour le réseau, les communications et les services WEB. 77.. CCoommmmeenntt mmoonn oorrddiinnaatteeuurr éévviittee aauuxx pprroocceessssuuss dd''eemmppiiéétteerr lleess uunnss ssuurr lleess aauuttrreess ?? L'ordonnanceur du noyau fait attention à séparer les processus dans le temps. Votre système d'exploitation les divise aussi dans l'espace, de telle manière que ces processus n'empiètent pas sur la mémoire de travail des autres. Ces choses que votre système d'exploitation réalise sont appelées _g_e_s_t_i_o_n _d_e _l_a _m_é_m_o_i_r_e. Chaque processus de votre 'troupeau' a besoin de son propre espace mémoire afin de mettre son code et de garder des variables et leur résultat. Vous pouvez imaginer cet ensemble constitué d'un _s_e_g_m_e_n_t _d_e _c_o_d_e accessible en lecture uniquement (contenant les instrucions du processus) et un _s_e_g_m_e_n_t _d_e _d_o_n_n_é_e_s accessible en écriture (contenant toutes les variables du processus). Le segment de données est véritablement propre à chaque processus, mais si deux processus exécutent le même code, Unix s'arrange automatiquement pour qu'ils partagent le même segment de code dans un soucis d'efficacité. L'efficacité est importante car la mémoire est chère. Quelquefois, vous ne disposez pas de suffisamment de mémoire pour faire tenir tous les programmes, spécialement si vous utilisez un gros programme comme un serveur X-WINDOW. Pour contourner cela, Unix utilise une stratégie appelée _m_é_m_o_i_r_e _v_i_r_t_u_e_l_l_e. Cela n'essaie pas de faire tenir tout le code et les données d'un processus en mémoire. Cependant, il garde seulement un espace de travail ; le reste de l'état du processus est laissé dans un endroit spécial sur votre disque : _l_'_e_s_p_a_c_e _d_'_é_c_h_a_n_g_e _(_s_w_a_p _s_p_a_c_e_). Lorsque le processus s'exécute, Unix essaie d'anticiper comment l' espace de travail changera, et ne chargera en mémoire que les morceaux dont il a besoin. Faire cela efficacement est compliqué et délicat, je n'essaierai pas de le décrire ici -- mais cela dépend du fait que le code et les références aux données peuvent arriver en blocs, avec chaque nouveau référençant vraisemblablement un proche ou un ancien. Ainsi, si Unix garde le code ou les données fréquemment (ou récemment) utilisés, vous gagnerez du temps. Notez que dans le passé, le "quelquefois" que nous employons deux paragraphes plus haut était "souvent" voire "toujours", -- la taille de la mémoire était habituellement petite par rapport à la taille des programmes en cours d'exécution, de telle manière que les échanges entre le disque et la mémoire ("swapping") étaient fréquents. La mémoire est beaucoup moins chère de nos jours et même les machines bas de gamme en sont bien dotées. Sur les machines mono-utilisateur avec 64Mo de mémoire, il est possible de faire tourner X-WINDOW et un mélange de programmes sans jamais swapper. Même dans cette situation joyeuse, la part du système d'exploitation appelée le _g_e_s_t_i_o_n_n_a_i_r_e _d_e _m_é_m_o_i_r_e a un important travail à faire. Il doit être sûr que les programmes ne peuvent modifier que leurs segments de mémoire -- ce qui empêche un code erroné ou malicieux dans un programme de ramasser les données dans un autre. Pour faire cela, il conserve une table des segments de données et de code. La table est mise à jour chaque fois qu'un processus demande de la mémoire ou en libère (habituellement plus tard lorsqu'il se termine). Cette table est utilisée pour passer des commandes à une partie spécialisée du matériel sous-jacent appelée un _U_G_M _(_M_M_U_) ou _u_n_i_t_é _d_e _g_e_s_t_i_o_n _m_é_m_o_i_r_e _(_m_e_m_o_r_y _m_a_n_a_g_e_m_e_n_t _u_n_i_t_). Les processeurs modernes disposent de MMUs intégrés. Le MMU a la faculté de mettre des barrières autour de zones mémoire, ainsi une référence en "dehors des clous" sera refusée et générera une interruption spéciale pour être traitée. Si vous avez déjà vu le message Unix qui dit "Segmentation fault", "core dumped" ou quelque chose de similaire, c'est exactement ce qu'il se passe ; un programme en cours d'exécution a tenté d'accéder à de la mémoire en dehors de son segment et a provoqué une interruption fatale. Cela indique un bug dans le code du programme ; le _c_o_r_e _d_u_m_p laisse une information en vue d'un diagnostic à l'attention du programmeur afin qu'il puisse trouver la trace de son erreur. 88.. CCoommmmeenntt mmoonn oorrddiinnaatteeuurr ssttoocckkee ddeess cchhoosseess ssuurr llee ddiissqquuee ?? Sur votre disque dur sous Unix, vous voyez un arbre de répertoires nommés et des fichiers. Normalement vous ne devriez pas à chercher à en savoir plus, mais cela peut s'avérer utile de savoir ce qu'il y a dessous si vous avez un crash disque et besoin d'essayer de nettoyer des fichiers. Malheureusement il n'y a pas de bon moyen de décrire l'organisation du disque en partant du niveau fichier et en descendant, c'est pour cela que je le décrirai en remontant à partir du niveau matériel. 88..11.. BBaass nniivveeaauu dduu ddiissqquuee eett ssttrruuccttuurree dduu ssyyssttèèmmee ddee ffiicchhiieerrss La surface de votre disque , sur laquelle il stocke les données est divisée comme une cible de jeu de fléchettes -- en pistes circulaires qui sont partagées en secteurs. Parce que les pistes de l'extérieur contiennent plus de surface que celles près de l'axe de rotation, au centre du disque, les pistes externes ont plus de secteurs que celles de l'intérieur. Chaque secteur (ou _b_l_o_c _d_i_s_q_u_e) a la même taille, qui est généralement de 1Ko (1024 mots de 8 bits). Chaque bloc disque a une adresse unique ou un _n_u_m_é_r_o _d_e _b_l_o_c _d_i_s_q_u_e. Unix divise le disque en _p_a_r_t_i_t_i_o_n_s _d_i_s_q_u_e. Chaque partition est une succession de blocs qui est utilisée indépendamment des autres partitions, comme un système de fichiers ou un espace d'échange (swap space). La partition ayant le plus petit numéro est souvent traitée spécialement, telle la _p_a_r_t_i_t_i_o_n _d_e _b_o_o_t dans laquelle vous pouvez mettre un noyau pour booter. Chaque partition est soit un _e_s_p_a_c_e _d_e _s_w_a_p (utilisé pour implémenter la ``mémoire virtuelle'') soit un _s_y_s_t_è_m_e _d_e _f_i_c_h_i_e_r_s pour stocker des fichiers. Les partitions de swap sont traitées comme une séquence linéaire de blocs. Les systèmes de fichiers d'un autre coté, ont besoin de relier les noms de fichiers à des séquences de blocs disque. Parce que les fichiers grossissent, diminuent, et changent tout le temps, les blocs de données d'un fichier ne seront pas une séquence linéaire mais pourront être dispersés sur toute la partition (tant que le système d'exploitation pourra trouver un bloc libre). 88..22.. NNoommss ddee ffiicchhiieerrss eett rrééppeerrttooiirreess Dans chaque système de fichiers, la liaison entre les noms et les blocs est réalisée grâce à une structure appelée _i_-_n_o_d_e _(_n_o_e_u_d _d_'_i_n_d_e_x_). Il y en a tout un tas proche de la "base" (numéro de bloc les plus faibles) du système de fichiers (les tout premiers sont utilisés pour des besoins d'intégrité et de label que nous ne décrirons pas ici). Chaque i-node décrit un fichier. Les blocs de données des fichiers sont au dessus des i-nodes (conceptuellement). Chaque i-node contient la liste des numéros des blocs du fichier (réellement c'est une demi-vérité, c'est seulement valable pour les petits fichiers, mais le reste de ces détails ne sont pas importants ici). Notez que l'i-node _n_e _c_o_n_t_i_e_n_t _p_a_s le nom du fichier. Les noms des fichiers résident dans les _s_t_r_u_c_t_u_r_e_s _d_e _r_é_p_e_r_t_o_i_r_e_s. Une structure de répertoire contient juste une table des noms et des numéros d'i-node associés. C'est la raison pour laquelle, sous Unix, un fichier peut avoir plusieurs noms réels (ou _l_i_e_n_s _f_o_r_t_s _(_h_a_r_d _l_i_n_k_s_)) ; Il y a juste plusieurs entrées dans un répertoire qui pointent vers le même i-node. 88..33.. PPooiinnttss ddee mmoonnttaaggee Dans le cas le plus simple, votre système de fichiers Unix tient sur une seule partition disque. Cependant vous verrez que cette disposition sur des petits systèmes Unix n'est pas pratique. Typiquement il est réparti sur plusieurs partitions disque voire sur plusieurs disques physiques. Ainsi par exemple, votre système peut avoir une petite partition où le noyau réside, une un peu plus grande pour les utilitaires du système et une beaucoup plus grosse pour les répertoires des utilisateurs. La seule partition à laquelle vous aurez accès immédiatement après le boot est votre _p_a_r_t_i_t_i_o_n _r_a_c_i_n_e _(_r_o_o_t _p_a_r_t_i_t_i_o_n_), qui est (presque toujours) celle à partir de laquelle vous avez booté. Elle contient le répertoire racine du système de fichiers, le noeud le plus haut à partir duquel tout est raccroché. Les autres partitions du système doivent être attachées à cette racine afin que votre système de fichiers unique ou multi-partition soit accessible. Au milieu du processus de boot, votre Unix rendra ces partitions 'non root' accessibles. Il devra _m_o_n_t_e_r chacune d'elles sur un répertoire de la partition racine. Par exemple, si votre Unix a un répertoire appelé '/usr', c'est probablement un point de montage d'une partition qui contient un tas de programmes installés avec votre Unix mais qui ne sont pas nécessaires durant la phase initiale de boot. 88..44.. CCoommmmeenntt uunn ffiicchhiieerr eesstt rreettrroouuvvéé ?? Maintenant nous pouvons considérer le système de fichiers dans une démarche descendante. Lorsque vous ouvrez un fichier (tel que /home/esr/WWW/ldp/fundamentals.sgml) voici ce qu'il arrive : Votre noyau démarre de la racine de votre système de fichiers Unix (dans la partition root). Il cherche un répertoire appelé `home'. Habituellement `home' est un point de montage d'une grande partition pour les utilisateurs, il descend à l'intérieur. Au sommet de la structure du répertoire de cette partition utilisateur, il va chercher une entrée nommée `esr' et en extraire le numéro d'i-node. Il ira à cette i-node, notez que c'est une structure de répertoire, et retrouvera `WWW'. En exploitant _c_e_t i-node, il ira au sous répertoire correspondant et retrouvera `ldp'. Ce qui lui donnera encore un autre i-node répertoire. En ouvrant ce dernier, il trouvera un numéro d'i- node pour `fundamentals.sgml'. Cet i-node n'est pas un répertoire mais fournit la liste des blocs associés au fichier. 88..55.. CCoommmmeenntt lleess cchhoosseess ppeeuuvveenntt ddééggéénnéérreerr ?? Plus haut, nous avons laissé entendre que les systèmes de fichiers étaient fragiles. Maintenant nous savons que pour accéder à un fichier vous devez parcourir une longue chaîne arbitraire de références à des répertoires et à des inodes. A présent, supposons que votre disque dur possède une zone défectueuse. Si vous êtes chanceux, il détruira quelques données d'un fichier. Si vous êtes malchanceux, il va corrompre une structure de répertoire ou un numéro d'inode et laissera un sous arbre entier de votre système dans l'oubli -- ou, pire, cela a donné une structure corrompue qui pointe par plusieurs chemins au même bloc disque ou inode. Une telle corruption peut s'étendre par des opérations courantes sur les fichiers qui ne se trouvent pas au point d'origine. Heureusement, ce genre de d'imprévu devient de plus en plus rare car les disques sont de plus en plus fiables. Malgré tout, cela veut dire que votre Unix voudra vérifier périodiquement l'intégrité du système de fichiers afin de s'assurer que rien ne cloche. Les Unix modernes font une vérification rapide sur chaque partition au moment du boot, juste avant de les monter. Au bout d'un certain nombre de redémarrages (reboot), la vérification sera plus approfondie et durera quelques minutes. Si tout cela vous parait, comme Unix, terriblement complexe et prédisposé aux défaillances, au contraire, c'est rassurant de savoir que ces vérifications faites au démarrage de la machine, détectent et corrigent les problèmes courants _a_v_a_n_t qu'ils ne deviennent réellement désastreux. D'autres systèmes d'exploitation ne disposent pas de ces fonctionnalités, qui accélèrent un petit peu le démarrage, mais peuvent vous laisser tout 'bousiller' en essayant de récupérer à la main (et en supposant que vous ayez une copie des Utilitaires Norton ou autre à portée de main...). 99.. CCoommmmeenntt ffoonnccttiioonnnneenntt lleess llaannggaaggeess dd''oorrddiinnaatteeuurr ?? Nous avons déjà évoqué ``comment les programmes sont exécutés''. Chaque programme en fin de compte doit exécuter une succession d'octets qui sont les instructions dans le _l_a_n_g_a_g_e _m_a_c_h_i_n_e de votre ordinateur. Les humains ne pratiquent pas très bien le langage machine ; cela est devenu rare, art obscur même parmi les hackers. La plupart du code du noyau d'Unix excepté une petite partie de l'interface avec le matériel est de nos jours écrite dans un _l_a_n_g_a_g_e _d_e _h_a_u_t _n_i_v_e_a_u. (Le terme 'haut niveau' est un héritage du passé afin de le distinguer du 'bas-niveau' des _l_a_n_g_a_g_e_s _a_s_s_e_m_b_l_e_u_r, qui sont de maigres "couches" autour du code machine. Il y plusieurs types différents de langages de haut niveau. Afin de parler d'eux, vous trouverez utile que j'attire votre attention sur le fait que le _c_o_d_e _s_o_u_r_c_e d'un programme (la création humaine, la version éditable) est passé à travers plusieurs types de traductions pour arriver en code machine, que la machine peut effectivement exécuter. 99..11.. LLaannggaaggeess ccoommppiillééss Le type le plus classique de langage est un _l_a_n_g_a_g_e _c_o_m_p_i_l_é. Les langages compilés sont traduits en fichiers exécutables de code machine binaire par un programme spécial appelé (assez logiquement) un _c_o_m_p_i_l_a_t_e_u_r. Lorsque le binaire est généré, vous pouvez l'exécuter directement sans regarder à nouveau dans le code source. (La plupart des logiciels délivrés sous forme de binaires compilés sont faits à partir d'un source auquel vous n'avez pas accès.) Les langages compilés tendent à fournir une excellente performance et ont un accès le plus complet au système d'exploitation, mais il difficile de programmer avec. Le langage C, langage dans lequel chaque Unix est lui-même écrit, est de tous le plus important (avec sa variante C++). FORTRAN est un autre langage compilé qui reste utilisé par de nombreux ingénieurs et scientifiques mais plus vieux et plus primitif. Dans le monde Unix aucun autre langage compilé n'est autant utilisé. En dehors de lui, COBOL est très largement utilisé pour les logiciels de finance et comptabilité. Il y a bien d'autres compilateurs de langages, mais la plupart sont en voie d'extinction ou sont strictement des outils de recherche. Si vous êtes un nouveau développeur Unix qui utilise un langage compilé, il est incontournable que ce soit C ou C++. 99..22.. LLaannggaaggeess iinntteerrpprrééttééss Un _l_a_n_g_a_g_e _i_n_t_e_r_p_r_é_t_é dépend d'un programme interpréteur qui lit le code source et traduit à la volée en calculs et appels système. Le source doit être ré-interprété (et l'interpréteur présent) à chaque fois que le programme est exécuté. Les langages interprétés tendent à être plus lents que les langages compilés, et limitent souvent les accès au système d'exploitation ou au matériel sous-jacent. D'un autre côté, il est plus facile de programmer et ils tolèrent plus d'erreurs de codage que les langages compilés. Quelques utilitaires Unix, incluant le shell et bc(1) et sed(1) et awk(1), sont effectivement des petits langages interprétés. Les BASICs sont généralement interprétés. Ainsi est Tcl. Historiquement, le langage le plus interprété était LISP (une amélioration énorme sur la plupart de ses successeurs). Aujourd'hui, Perl est très largement utilisé et devient résolument plus populaire. 99..33.. LLaannggaaggeess PP--ccooddee Depuis 1990 un type de langage hybride qui utilise la compilation et l'interprétation est devenu incroyablement important. Les langages P- code sont comme des langages compilés dans le sens où le code est traduit dans une forme binaire compacte qui est celle que vous exécutez, mais cette forme n'est pas du code machine. Au lieu de cela, c'est du _p_s_e_u_d_o_-_c_o_d_e (ou _p_-_c_o_d_e), qui est généralement un peu plus simple mais plus puissant qu'un langage machine réel. Lorsque vous exécutez le programme, vous interprétez du p-code. Le p-code peut s'exécuter pratiquement aussi rapidement que du binaire compilé (les interpréteurs de p-code peuvent être relativement simples, petits et rapides). Mais les langages p-code peuvent garder la flexibilité et la puissance d'un bon interpréteur. D'importants langages p-code sont Python et Java. 1100.. CCoommmmeenntt IInntteerrnneett ffoonnccttiioonnnnee ?? Afin de vous aider à comprendre comment Internet fonctionne, nous verrons ce qui se passe lorsque vous effectuez une opération classique -- pointer dans un navigateur ce document à partir du site Web de référence du Projet de Documentation de Linux (Linux Documentation Project). Ce document est : http://sunsite.unc.edu/LDP/HOWTO/Fundamentals.html ce qui veut dire qu'il réside dans le fichier LDP/HOWTO/Fundamentals.html, sous le répertoire exporté World Wide Web de la machine sunsite.unc.edu. 1100..11.. NNoommss eett llooccaalliissaattiioonnss La première chose que votre navigateur doit faire est d'établir une connexion réseau avec la machine sur laquelle se trouve le document. Pour faire cela, il doit tout d'abord trouver la localisation réseau de _l_'_h_ô_t_e sunsite.unc.edu (hôte est un raccourci pour `machine hôte' ou `hôte réseau' ; sunsite.unc.edu est un _n_o_m _d_'_h_ô_t_e _(_h_o_s_t_n_a_m_e_) typique). La localisation correspondante est en fait un nombre appelé _a_d_r_e_s_s_e _I_P (nous expliquerons la partie `IP' de ce terme plus tard). Pour faire cela, votre navigateur sollicite un programme nommé _s_e_r_v_e_u_r _d_e _n_o_m_s. Le serveur de noms peut résider sur votre machine, mais il est plus probable qu'il soit sur une machine de service avec laquelle vous pouvez dialoguer. Lorsque vous abonnez chez un Fournisseur d'Accés à Internet (FAI), une partie de la procédure d'installation décrit certainement la manière d'indiquer à votre logiciel Internet l'adresse IP du serveur de noms du réseau du FAI. Les serveurs de noms sur différentes machines communiquent avec les autres en échangeant et en gardant à jour toutes les informations nécessaires à la résolution de noms d'hôte (en les associant à des adresses IP). Votre serveur de noms doit demander à trois ou quatre sites à travers le réseau afin de résoudre sunsite.unc.edu, mais cela se déroule vraiment rapidement (en moins d'une seconde). Le serveur de noms dira à votre navigateur que l'adresse IP de Sunsite est 152.2.22.81 ; sachant cela, votre machine sera capable d'échanger des bits avec Sunsite directement. 1100..22.. PPaaqquueettss eett rroouutteeuurrss Ce que le navigateur veut faire est d'envoyer une commande au serveur Web sur Sunsite qui a la forme suivante : GET /LDP/HOWTO/Fundamentals.html HTTP/1.0 Que se passe-t-il alors ? La commande est faite de _p_a_q_u_e_t_s ; un bloc de bits comme un télégramme est découpé en trois choses importantes : _l_'_a_d_r_e_s_s_e _s_o_u_r_c_e (l'IP de votre machine), _l_'_a_d_r_e_s_s_e _d_e_s_t_i_n_a_t_i_o_n (152.2.22.81), et le _n_u_m_é_r_o _d_e _s_e_r_v_i_c_e ou _n_u_m_é_r_o _d_e _p_o_r_t (80, dans ce cas) qui indique que c'est une requête World Wide Web. Alors votre machine envoie le paquet par le fil (de la connexion modem avec votre FAI, ou le réseau local) jusqu'à ce qu'il rencontre une machine spécialisée appelée _r_o_u_t_e_u_r. Le routeur possède une carte de l'Internet dans sa mémoire -- pas une complète mais une qui décrit votre voisinage réseau et sait comment aller aux routeurs pour les autres voisinages sur l'Internet. Votre paquet peut passer à travers plusieurs routeurs sur le chemin de sa destination. Les routeurs sont adroits. Ils regardent combien de temps prend un accusé réception pour recevoir un paquet. Ils utilisent cette information pour aiguiller le trafic sur les liens rapides. Ils l'utilisent pour s'apercevoir que d'autres routeurs (ou un câble) sont déconnectés du réseau et modifier le chemin si possible en trouvant une autre route. Il existe une légende urbaine qui dit qu'Internet a été conçu pour survivre a une guerre nucléaire. Ce n'est pas vrai, mais la conception d'Internet est extrêmement bonne en ayant une performance fiable basé sur des couches matérielles d'un monde incertain... C'est directement du au fait que son intelligence est distribuée à travers des milliers de routeurs plutôt qu'à quelques auto-commutateurs massifs (comme le réseau téléphonique). Cela veut dire que les défaillances tendent à être bien localisées et le réseau peut les contourner. Une fois que le paquet est arrivé à destination, la machine utilise le numéro de service pour le fournir au serveur Web. Le serveur Web peut savoir à qui répondre en regardant l'adresse source du paquet. Quand le serveur Web renvoie ce document, il sera coupé en plusieurs paquets. La taille des paquets varie en fonction du média de transmission du réseau et du type de service. 1100..33.. TTCCPP eett IIPP Pour comprendre comment des transmissions de multiples paquets sont réalisées, vous devez savoir que l'Internet utilise actuellement deux protocoles empilés l'un sur l'autre. Le plus bas niveau, _I_P (Internet Protocol), sait comment recevoir des paquets individuels d'une adresse source vers une adresse destination (c'est pourquoi elles sont appelées adresses IP). Cependant, IP n'est pas fiable ; si un paquet est perdu ou jeté, les machines source et destination ne le sauront jamais. Dans le jargon réseau, IP est un protocole _s_a_n_s _c_o_n_n_e_x_i_o_n _(_o_u _m_o_d_e _n_o_n _c_o_n_n_e_c_t_é_) ; l'expéditeur envoie juste un paquet au destinataire et n'attend jamais un accusé de réception. Cependant, IP est rapide et peu coûteux. Quelquefois, rapide, peu coûteux et non fiable c'est OK. Lorsque vous jouez en réseau à Doom ou Quake, chaque balle est représentée par un paquet IP. Si quelques-unes sont perdues, c'est OK. Le niveau supérieur, _T_C_P (Transmission Control Protocol), fournit la fiabilité. Quand deux machine négocient une connexion TCP (ce qu'elles font en utilisant IP), le destinataire doit envoyer des accusés de réception des paquets qu'il reçoit à l'expéditeur. Si l'expéditeur ne reçoit pas un accusé de réception pour un paquet après un certain temps, il renvoie ce paquet. De plus, l'expéditeur donne à chaque paquet TCP un numéro de séquence, que le destinataire peut utiliser pour ré-assembler les paquets dans le cas où il sont arrivés dans le désordre. (Cela peut arriver si les liens réseau se rétablissent ou cassent pendant une connexion.) Les paquets TCP/IP contiennent également un checksum pour permettre la détection de données altérées par de mauvais liens. Ainsi, du point de vue de quelqu'un utilisant TCP/IP et des serveurs de noms, il ressemble à une voie fiable pour faire passer des flux d'octets entre des paires hôte/numéro de services. Les gens qui écrivent des protocoles réseau ne doivent pas se soucier la plupart du temps de la taille des paquets, du ré-assemblage des paquets, de la vérification d'erreurs, le calcul du checksum et la retransmission qui sont au niveau inférieurs. 1100..44.. HHTTTTPP,, uunn pprroottooccoollee dd''aapppplliiccaattiioonn Maintenant revenons à notre exemple. Les navigateurs et les serveurs Web parlent un _p_r_o_t_o_c_o_l_e _d_'_a_p_p_l_i_c_a_t_i_o_n qui est au dessus de TCP/IP, en l'utilisant simplement comme une manière de passer des chaînes d'octets dans les deux sens. Ce protocole est appelé _H_T_T_P (Hyper-Text Transfer Protocol) et nous en avons déjà vu une commande -- la commande GET utilisée ci-dessus. Lorsque la commande GET arrive au serveur Web de sunsite.unc.edu avec comme numéro de service 80, elle sera expédiée à un _d_é_m_o_n _s_e_r_v_e_u_r qui écoute le port 80. La plupart des services Internet sont implémentés par des démons serveurs qui ne font rien d'autre qu'attendre sur des numéros de port, récolter et exécuter les commandes entrantes. Cette conception de l'Internet a une règle qui prime sur les autres, c'est que toutes les parties sont le plus simple possible et humainement accessible. HTTP, et ses compères (comme le Simple Mail Transfer Protocol, _S_M_T_P, qui est utilisé pour transporter du courrier électronique entre des machines) utilisent de simples commandes de texte qui se terminent par un retour chariot. C'est rarement inefficace ; dans certaines circonstances vous pouvez obtenir plus de rapidité en employant un protocole binaire fortement codé. Mais l'expérience a montré que le bénéfice d'avoir des commandes qui sont faciles à décrire et à comprendre l'emportent sur le gain marginal de l'efficacité que l'on peut espérer au prix de choses compliquées et compactes. Par conséquent, ce que le démon serveur vous renvoie via TCP/IP est aussi du texte. Le début de la réponse ressemblera à quelque chose comme (quelques en-têtes ont été supprimés) : HTTP/1.1 200 OK Date: Sat, 10 Oct 1998 18:43:35 GMT Server: Apache/1.2.6 Red Hat Last-Modified: Thu, 27 Aug 1998 17:55:15 GMT Content-Length: 2982 Content-Type: text/html Ces en-têtes seront suivis d'une ligne vide et du texte de la page Web (après que la connexion sera rompue). Votre navigateur affichera simplement cette page. Les en-têtes indiquent -- en particulier, l'en- tête Type de Contenu (Content-Type) -- comment les données reçues sont vraiment du HTML).