A la découverte d Unix Paul Feautrier Paul.Feautrier@ens-lyon.fr. ENS Lyon UNIX-MIM1 1/62
Plan Présentation. Compléments sur les shells. Construction d applications. Système de fichiers. Gestion des processus. Compilation séparée. Eléments de programamtion concurrente. Communications entre processus. A l intérieur d un système de fichier. Développement d applications. UNIX-MIM1 2/62
Histoire des systèmes d exploitation Les premiers ordinateurs n ont aucun logiciel. Assembleurs et compilateurs. Traitement par lot, ordinateur oériphérique, IBSYS. spooling. Multitraitement. IBM OS/360. Temps partagé. Multiprocesseurs. Réseaux : Arpanet, Cyclades, Transpac. Systèmes distribués, courrier électronique, Web. UNIX-MIM1 3/62
Fonctions des systèmes d exploitation Bibliothèques d entrée sortie et de gestion du multitraitement. Supervision et partage de la configuration. Administration, sécurité, fiabilité. UNIX-MIM1 4/62
Histoire d Unix Première version écrite «en perruque» par Thompson et Ritchie (1972). Définition de C. Premier portage. Divergence : System V (Bell Labs) et BSD (Berkeley). Convergence. Unix sur PC : Linux. UNIX-MIM1 5/62
Panorama des systèmes d exploitation actuels Windows : origine DOS, inclusion tardive d un système de fenétrage copié sur celui du MacIntosh. 80 à 90% du marché des PC. Peu sûr et peu fiable. Unix : machines moyennes, ordinateurs personnels (Linux, OS/X), gros serveurs Web, grosses machines pour le calcul scientifique. Systèmes propriétaires. Réservés aux mainframes utilisés pour la gestion. Systèmes spécialisés : temps réel, embarqués, à haute disponibilité, etc. UNIX-MIM1 6/62
Pourquoi Unix? Transparence. Les sources du système sont accessibles. Fiabilité. Sécurité : pas absolue, mais meilleure que celle de Windows. Portabilité. Convivialité. Beaucoup de développements sous Unix se font sur le mode de l open source. UNIX-MIM1 7/62
A quoi sert le shell? init getty login shell - - UNIX-MIM1 8/62
Les shells Comme le shell est un programme ordinaire, il est possible de le réécrire pour le doter de nouvelles fonctionnalités. le shell de Bourne sh, version originale, toujours présent. csh le shell à syntaxe C. Introduction de l historique et du contrôle des travaux. tcsh introduit le concept d édition de la ligne de commande. Bourne again shell bash fait la synthèse de toutes ces améliorations et revient à la syntaxe de sh. Il en existe bien d autres. UNIX-MIM1 9/62
Fonctionnement d un shell Aussi longtemps qu il y a des commandes à lire : Lecture d une commande. Analyse de la commande et détermination du programme à lancer. Lancement du programme. Pendant l exécution du programme, en général le shell se bloque pour en attendre la fin, sauf si le caractère & figure dans la commande. UNIX-MIM1 10/62
Scripts Une liste de commandes enregistrées dans un fichier. Lancement d un script. Le fichier doit avoir le droit d exécution. Variables. $0, $1,... $9. Instructions de contrôle : if, for, while, case. case $v in x )... ;; y?)... ;; * )... ;; esac UNIX-MIM1 11/62
Programmation récursive, I Il suffit relancer le script au cours de sa propre exécution. Attention, il doit toujours y avoir un cas où l appel récursif ne se fait pas, et ce cas doit toujours finir par se produire. Sinon, on provoque une saturation en processus et un blocage du système. Exemple 1 if expr $1 = 0 > /dev/null then echo 1 else m= expr $1-1 n= fact $m expr $1 \* $n fi UNIX-MIM1 12/62
Programmation récursive, II Il est plus astucieux d utiliser la variable $0 dont la valeur est le nom du script. Exemple 2 #!/bin/sh for f in ls $1 do if test -d $1/$f then $0 $1/$f else echo $1/$f fi done UNIX-MIM1 13/62
Trucs et astuces Insérer des données dans un script. Exemple 3 mail pfeautri <<! Ta compilation vient de se terminer.! Créer des fichiers d initialisation. Exemple 4 #Building the starter file. echo "home_dir := \"$HOME\";" > starter echo "pip_executable := \"$HOME/Pip/mpPip/pipMP\";" >> starter echo "application_file := \"$1\":" >> starter echo "control_file := \"$2\";" >> starter echo "machine_description_file := \"$3\":" >> starter #Launching the scheduler mupad starter $HOME/Yaka/Src-mupad/yaka.mupad Construction dynamique de scripts. UNIX-MIM1 14/62
Pourquoi écrire des scripts? En guise d aide mémoire. Pour faire du prototypage rapide. Pour accomplir une tâche complexe mais infréquente. Attention, la programmation par scripts est pleine de pièges. Il n y a pas d outils de mise au point spécifique. UNIX-MIM1 15/62
Le role de C vis-à-vis d Unix C est le langage d écriture du système et de ses accessoires. Beaucoup de compilateurs générent du C (fonction assembleur de haut niveau). C est un langage efficace (moins que Fortran cependant). Il est utlisé pour les bibliothèques de calcul, les solveurs, les serveurs, etc. Mais C ne doit pas être utilisé à tort et à travers : pour écrire un compilateur, utiliser Ocaml. pour du calcul numérique à hautes performances, FORTRAN. pour du calcul algébrique, Maple, MuPAD, Mathematica... pour du traitement de texte, Perl, Awk, sed... UNIX-MIM1 16/62
Sources C. Delannoy : Le Livre de C Premier langage, Eyrolles, 1997. B. Kernigham, D. Ritchie : The C programming Language, Prentice-Hall, 1988. Eviter les traductions. J-M. Rifflet : La programmation sous Unix, Ediscience. De nombreux renseignements, en particulier sur les fonctions de la bibliothèque peuvent etre obtenues à l aide de la commande man : $man 3 printf PRINTF(3) Linux Programmer s Manual PRINTF(3) NAME printf, fprintf, sprintf, snprintf, vprintf, vfprintf, vsprintf, vsnprintf - formatted output conversion SYNOPSIS #include <stdio.h> int printf(const char *format,...); int fprintf(file *stream, const char *format,...); int sprintf(char *str, const char *format,...); int snprintf(char *str, size_t size, const char *format,...);... #include <stdarg.h> UNIX-MIM1 17/62
Instructions de contrôle if (...)... else... ; while (...)... ; for(a ; b ; c) S ; équivalent à : a; while(b) { S; c; } Instruction switch : switch (c) { case a :... case e :... case m ; case n :... default :... } break; break; break; UNIX-MIM1 18/62
Les types de C Types entiers : char short long long long 8 bits 16 bits 32 bits 64 bits Types flottants float double 32 bits 64 bits Il n y a pas de booléens, on utilise un type entier avec la convention faux, toute autre valeur = vrai. Il est inutile de mémoriser cette convention. UNIX-MIM1 19/62
Les opérateurs de C Chaque opérateur a une priorité, mais il vaut mieux fixer l ordre des opérations par des parenthèses. Opérateurs Arithmétiques +, -, *, /, %. Opérent indifféremment sur les int ou les float. Le calcul se fait en flottant si l un au moins des deux opérandes est flottant. Opérateurs de pré et post incrémentation ++, --. Opérateurs de comparaison <, <=, ==,!=, >= >. Noter la comparaison pour égalité, ==. Opérateurs booléens Et &&, Ou, Non!. Opérateurs bit-à-bit Et &, Ou, Non, Ou exclusif ˆ. Opérateurs de décalage <<, >>. UNIX-MIM1 20/62
Opérateurs de C, suite Opérateur d affectation =, +=, etc. Il est légal d écrire : x = y = 0; Opérateur d affectation composé : A[i][j-1][i+j] += 1.0; A[i][j-1][i+j] = A[i][j-1][i+j] + 1.0; L expression conditionelle : u := u > 0? u : -u; permet de calculer une valeur absolue. UNIX-MIM1 21/62
Tableaux Déclaration : float a[10][10]; Usage : a[i][j] = 0.; a[j][i] = a[i][j]; Attention, l indice du premier lment d un tableau est 0. Chaînes de caractères : une chaîne de caractères est un tableau de type char. Comme les chaînes de caractères peuvent être de longueur variable, on utilise le caractère \0 comme terminateur. char keyword[] = "itemize"; char and[10]; and[0] = a ; and[1] = n ; and[2] = d ; and[3] = \0 ; UNIX-MIM1 22/62
Copier une chaîne de caractères char source[81], dest[81]; int i; for(i=0; source[i]!= 0; i++) dest[i] = source[i]; dest[i] = \0 ; Si la chaîne source ne contient pas de \0, ce bout de programme va détruire toute la mémoire et provoquer une erreur! On ne doit pas oublier de placer le \0 de la destination. UNIX-MIM1 23/62
Structures struct iob { int longueur; int index; char buffer[256]; }; struct iob x; struct iob y[12]; struct iob se comporte comme un nouveau type. On accède aux éléments de la structure par la notation pointée : y[3].buffer[112] = z ; Il est possible d utiliser une instruction d affectation pour une structure : y[7] = x; Il n y a pas d instruction d affectation de tableau, sauf s il fait partie d une structure. UNIX-MIM1 24/62
Fonctions float power(float x, int n) { float y; if(n==0) return(1.0); y = power(x, n/2); if(n%2 ==0) return(y*y); else return(x*y*y); } Récursivité. Type de la fonction, liste des arguments avec leur type. Variable locale : y. Instruction return. UNIX-MIM1 25/62
Appel de fonction main() { float result; result = power(3.1415926, 7); printf("3.1415926ˆ7 = %f\n", result); } Role spécial de la fonction main. Transmission des arguments. Fonction de bibliothèque printf. UNIX-MIM1 26/62
Pointeurs int X[10]; int *p; int **q; p = X; q=&p q p X **q 0 1 *(p+3) p[9] UNIX-MIM1 27/62
Copier une chaîne de caractères, version II char source[81], dest[81]; char *p, *q; p=source; q=dest; while((*q++ = *p++)!= \0 ); UNIX-MIM1 28/62
Gestion de la mémoire Un objet ne peut être utilisé que si de la mémoire lui est allouée. Il existe plusieurs méthodes d allocation de la mémoire. Statique : struct iob x; main(...) {... } Automatique : int foo(...) { struct iob y;... } La mémoire est allouée quand la fonction est appelée et libérée quand la fonction se termine. UNIX-MIM1 29/62
Gestion dynamique de la mémoire Dynamique : struct iob *p; p = (struct iob *) malloc(sizeof(struct iob));... free(p); La mémoire est libérée sur ordre du programmeur. UNIX-MIM1 30/62
Chaîne de compilation emacs.c préprocesseur gcc.o ld a.out Préprocesseur : #include <foo.h> #define NELEM 100 Caché à l intérieur du compilateur. Compilateur (gcc ou cc). bibliothèque Editeur de lien, ld, caché à l intérieur du compilateur. UNIX-MIM1 31/62
Primitives Services fournis par le système à l utilisateur. Fonctionnement analogue à celui d une bibliothèque. Mais le système doit refuser les demandes dangereuses : mécanisme d appel spécial, mais camouflé en appel de fonction. #include <time.h> time_t now; if(time(&now)<0) perror("time"); Retourne le nombre de secondes écoulées depuis le 1er Janvier 1970. Question : A quelle date se produira l équivalent du bug de l an 2000 pour Unix? Noter l ordre #include. UNIX-MIM1 32/62
Mécanismes application bibliothèque noyau time()... time() IRET time() {... INT...... return; time(){... return; } barrière de protection UNIX-MIM1 33/62
Exemple #include <time.h> #include <stdio.h> main(void) { time_t heure; char *p; } if (time(&heure) < 0) perror("time"); p = ctime(&heure); puts(p); Contrairement à l usage, la mémoire contenant le résultat de ctime est allouée par ctime et ne peut être libérée. Compilation : $gcc now.c -o now $now UNIX-MIM1 34/62
Index des primitives Entrées/sorties : open, close, read, write, lseek, stat, fstat, chdir,... Gestion des processus : fork, wait, exec, exit,... Communications entre processus : Mode entrées/sorties : tubes pipes et sockets. Mode interruption : signaux. Mode mémoire partagée ; IPC System V. UNIX-MIM1 35/62
Les arguments de main $appl x y/z 23 main(int argc, char *argv[]){... } argv "appl" "x" "y/z" "23" NULL UNIX-MIM1 36/62
Fichiers Fractionner les supports magnétiques. Un disque dur = 30 Goctets. Une page = 2 koctets, soit 15 millions de page par disque. Une photo = 10 Moctets, soit 3 000 photos par disque. Structure d un fichier : longueur vu du système texte \n \n \n\n \n autres structures index indexé UNIX-MIM1 37/62
Répertoires, I Role : mettre de l ordre dans les fichiers ; éviter les collisions de nom. Fichiers du système : immédiatement sous le répertoire racine, /bin, /lib, /usr, etc. Périphériques : /dev, /mnt. Fichiers des usagers : les conventions varient. /home/pfeautri ou /users/prism/pf/paf, etc. Chaque usager a son propre répertoire initial home directory. Il est libre de s organiser comme il veut ensuite. Juste après le login, l usager est dans le répertoire initial ; il peut se déplacer à l aide de la commande cd. UNIX-MIM1 38/62
Répertoires, II Un fichier peut être enregistré dans plusieurs répertoires à l aide de la commande ln. / usr bin home pfeautri Cours Pubs Unix RO oeuvres.tex unix_sld.tex UNIX-MIM1 39/62
Répertoires, III Un répertoire ne contient aucune information sur le fichier. La description du fichier se trouvre dans une structure spéciale inode qui peut être consultée à l aide de la commande stat. 2802 3402 Cours 2802 Pubs 9832 RO 3402. 3402 Unix 8174.. 2802 9832 oeuvres.tex 2744 8174 unix_sld.tex 8256 slides 8256 8256 UNIX-MIM1 40/62
Cycle d utilisation d un fichier #define BUFFSIZE 1024 char buffer[buffsize]; int fd, n; fd = open("foo",...); while (...) { n = read(fd, buffer, BUFFSIZE);... } close(fd); UNIX-MIM1 41/62
Les arguments de open fd = open(nom, flags, droits); Le nom est une chaîne de caractères. Les flags sont une chaîne de bits que l on construit à l aide de l opérateur ou. Le fichier d inclusion fournit des constantes figurées pour soulager la mémoire du programmeur. O_RDONLY ouverture en lecture seule. O_WRONLY écriture seule. O_RDWR. O_APPEND écriture en rallongement. O_CREAT créer le fichier s il n existe pas. O_TRUNC détruire le contenu du fichier s il existe. droits d accès : chaîne de bits (en général en octal), dans l ordre rwxrwxrwx. UNIX-MIM1 42/62
Exemple : un code de copie #include <stdio.h> #define BSIZE 1024 void copy(char *original, char *copie) { int in, out; char buffer[bsize]; int n; in = open(original, O_RDONLY); if(in <0) { perror(original); exit(0); } out = open(copie, O_WRONLY O_CREAT O_TRUNC, 0640); if(out < 0) { perror(copie); exit(0); } while((n = read(in, buffer, BSIZE)) > 0) write(out, buffer, n); close(out); close(in); } UNIX-MIM1 43/62
Positionnement long int pos, delta; pos = lseek(fd, delta, flags); delta SEEK_SET position actuelle delta SEEK_CUR delta SEEK_END trou pos UNIX-MIM1 44/62
Mesurer la taille d un fichier #include <sys/types.h> #include <unistd.h> main(int argc, char *argv[]) { long int taille = 0L; int fd; fd=open(argv[1], O_RDONLY); if(fd <0) { perror(argv[1]); exit(0); } taille = lseek(fd, 0L, SEEK_END); printf("%ld\n", taille); } UNIX-MIM1 45/62
Droits d accès, I owner group others R W X R W X R W X exécuter ou traverser écrire lire 0640 1 1 0 1 0 0 0 0 0 A l ouverture, on confronte la demande (e.g. O_WRONLY), le nom de l utilisateur et les droits d accès. Les outils du système donnent des droits d accès vraisemblables. On peut les changer à l aide de chmod. Les doits d accès doivent être spécifiés au moment de l open qui crée le fichier. On utilise en général la notation octale. Erreur classique : oublier les droits, droits nuls, fichier inaccessible. Que faire? UNIX-MIM1 46/62
Droits d accès, II Attention, les droits d accès des répertoires traversés influent sur les droits d accès au fichier. Pour accéder à /a/b/c il faut traverser /a et /a/b, donc avoir le droit x. Pour créer ou détruire /a/b/c, il faut avoir le droit de modifier /a/b. Faites attention à vos droits d accès!!!!! UNIX-MIM1 47/62
stat, fstat, I Ces deux primitives permettent de consulter le inode d un fichier (rappel : les répertoires ne contiennent aucune information). Technique : le inode contient beaucoup d information, qu il n est pas commode de retourner comme valeur de la fonction. La primitive a donc un argument de plus qui pointe sur une structure réservée par l utilisateur. Il n est pas nécessaire d utiliser malloc : struct stat buffer; if(stat("fichier", &buffer) < 0) { perror("fichier"); exit(0); } UNIX-MIM1 48/62
stat, fstat, II Début de la structure stat : struct stat { dev_t st_dev; /* device */ ino_t st_ino; /* inode */ mode_t st_mode; /* protection */ nlink_t st_nlink /* number of har uid_t st_uid; /* user ID of ow gid_t st_gid; /* group ID of o if(buffer.st_mod & S_IFDIR!= 0)... Le fonctionnement de fstat est le même, mais le fichier doit être ouvert. Il est désigné par son descripteur. Il existe également une commande stat. UNIX-MIM1 49/62
Processus processeur uid gid pid stack ports heap text uid : numéro de l usager, gid : groupe de l usager, pid numéro unique du processus. text : le code, heap : l espace alloué par malloc, stack : l espace des variables locales. UNIX-MIM1 50/62
Processus, pourquoi, comment? Les processus ont été inventés avant les ordinateurs personnels, pour donner l illusion d un PC alors que la machine réelle est trop coûteuse pour être allouée à un seul utilisateur. DOS n a pas de vrais processus. Les processus sont revenus sur les PC (Windows, Mac, Linux) à cause de la facilité de programmation qu ils apportent (traitement des événements imprévisibles dus au réseau). Les processus doivent être isolés les un des autres et du système. Cependant, il doit rester des ports de communication sévérement contrôlés. UNIX-MIM1 51/62
Gestion des processus, I #include <unistd.h> int r; /* original process */ if(fork()==0) { /* copy process */ exit(0); } else { /* original process */ wait(&r); } /* original process */ à UNIX-MIM1 52/62
Gestion des processus, II Le role de fork est de faire une copie du processus courant. Il faut cependant un processus non copié, le processus 1, init. fork() retourne une fois chez l original et une fois chez la copie, avec des valeurs différentes. A part cette valeur les mémoires de l original et de la copie sont identiques (y compris la mémoire cachée portes, etc). UNIX-MIM1 53/62
Gestion des processus, III ==0 copie exit(0) original fork()!=0 original wait(&r); original UNIX-MIM1 54/62
Gestion des processus : exec Il est impossible d en rester là, sans quoi on exécuterait toujours le même programme, ou bien il faudrait compiler tous les programmes en un seul. Il existe une primitive de changement de programme, execve, avec d autres variantes. Le programme en cours est détruit ; il est remplacé par le programme contenu dans le fichier argument. execvp est presque toujours invoqué depuis un processus copie. char *argv[] = {"/home/pfeautri/programme", "debug", NULL}; char *envp[] = {"HOME=/home/pfeautri","EDITOR=emacs",..., NULL}; if(fork()){ if(execve("programme", argv, envp) < 0){ perror("programme"); exit(1); } } else wait(&r);... Le test du résultat de execve est inutile, parce qu on ne revient pas d un execve réussi. Par contre, exit est indispensable. UNIX-MIM1 55/62
Un exemple On peut se demander pourquoi avoir deux primitives fork et exec. Entre le retour du fork et le début de exec, on peut manipuler le contexte du processus copie. Par exemple, on veut faire exécuter depuis un programme C la commande ls, mais on veut récupérer les résultats de ls dans un fichier tmp. On effectue un fork. Dans le processus copie, on ouvre tmp et on s arrange pour qu il soit connecté au port 1. On provoque l exécution de ls. Ce programme écrit ses résultats à travers le port 1, c est-à-dire dans le fichier tmp. Dans le processus original, on attend que ls soit terminé puis on exploite le résultat. UNIX-MIM1 56/62
Le code #include <unistd.h> #include <sys/types.h> #include <wait.h> #include <fcntl.h> #include <sys/stat.h> char *argv[] = {"ls", NULL}; int tmp; struct stat x; main(void){ if(fork() == 0) { tmp = open("tmp", O_WRONLY O_TRUNC O_CREAT, 0600); if(tmp < 0) { perror("tmp"); exit(0); } if(dup2(tmp, 1)<0) perror("dup2"); close(tmp); execve("/bin/ls", argv, NULL); exit(0); } else { wait(null); if(tmp = open("tmp", O_RDONLY)<0) perror("tmp"); /* utilisation du fichier */ close(tmp); } } UNIX-MIM1 57/62
Compilation modulaire, pourquoi? On découpe le programme en modules (= fichiers) qui peuvent être compilés séparémment. Diminue le temps de compilation. En cas d erreur, et si le programme est bien organisé, on ne recompile que le module fautif. Mais il faut figer très tôt les interfaces entre modules. Permet la programmation multi-langage. C-Fortan : les compilateurs de ces deux langages sont en général compatibles. Il suffit pour les faire cohabiter de savoir que les arguments en Fortran sont toujours des pointeurs. C-Assembleur, toujours possible. Amélioration des performances, gestion de dispositifs spéciaux. UNIX-MIM1 58/62
Compilation modulaire, règles en C il n y a pas de transmission d information entre phases de compilation (c.f. Ada, Ocaml). Chaque module doit être complet. Toute variable ou fonction doit être déclarée. Fonction : on donne l en-tête mais pas le corps de la fonction. float power(float x, int n); float power(float, int); Variable : mot clef extern, il n est pas nécessaire de donner les valeurs initiales ou les dimensions des tableaux. Ce schéma entraine de la duplication de code. Assistance du préprocesseur : #include "defs.h" UNIX-MIM1 59/62
Mécanismes import f f(...); export f Tout fichier.o comporte du code binaire incomplet et une table import/export. ld f(...){... } L éditeur de lien fabrique un code binaire où les importations sont satisfaites par les exportations. Les importations non satisfaites sont recherchées dans des bibliothèques. f(...); f(...){... } Il peut signaler des doubles exportations, ou des importations non statisfaites. UNIX-MIM1 60/62
Le préprocesseur, rappels Importation de texte : #include <stdlib.h> #include "defs.h" Définition de constantes : #define BSIZE 1024 Attention, aucun espace mémoire n est réservé pour BSIZE. Définition de macro-instructions : #define max(x,y) ((x) >= (y)? (x) : (y)) Une macro-instruction n est pas une fonction. Compilation conditionelle : #ifdef DEBUG printf("x = %d, y = %d\n", x, y); #endif UNIX-MIM1 61/62
make pi.h cercle.c peri.c surf.c gcc gcc gcc cercle.o peri.o surf.o (ld) gcc cercle L application est représentée par un graphe biparti : les fichiers et les outils qui les fabriquent. En cas de modification, make provoque la recréation du minimum de fichier. UNIX-MIM1 62/62