I. Introduction. II. But de l'exercice



Documents pareils
Dans le chapitre 1, nous associions aux fichiers ouverts des descripteurs de fichiers par lesquels nous accédions aux fichiers.

Travaux pratiques. Compression en codage de Huffman Organisation d un projet de programmation

Programmation de l'api Video for Linux

Cours de Système : Gestion de Fichiers

Programmation impérative

Compression de Données - Algorithme de Huffman Document de Conception

Analyse de sécurité de logiciels système par typage statique

Le Langage C Version 1.2 c 2002 Florence HENRY Observatoire de Paris Université de Versailles florence.henry@obspm.fr

Brefs rappels sur la pile et le tas (Stack. / Heap) et les pointeurs

Playing with ptrace() for fun and profit

Cours 6 : Tubes anonymes et nommés

Le Network File System de Sun (NFS)

Plan global. Programmation système II. Socket du domaine UNIX. Plan. Socket UNIX, Terminaux, Async IO, Mémoire, ELF.

1. Structure d un programme C. 2. Commentaire: /*..texte */ On utilise aussi le commentaire du C++ qui est valable pour C: 3.

Le prototype de la fonction main()

Chapitre 2. Classes et objets

Seance 2: En respectant la méthode de programmation par contrat, implémentez les autres fonctions de jeu.

GESTION DES FICHIERS C/UNIX

Logiciels de communication avec des périphériques. Jean-Philippe Babau

Centre CPGE TSI - Safi 2010/2011. Algorithmique et programmation :

Programmation système de commandes en C

Bases de programmation. Cours 5. Structurer les données

Le langage C. Séance n 4

Programmation système I Les entrées/sorties

Les chaînes de caractères

Cours d initiation à la programmation en C++ Johann Cuenin

Suivant les langages de programmation, modules plus avancés : modules imbriqués modules paramétrés par des modules (foncteurs)

Le système de gestion des fichiers, les entrées/sorties.

Licence Bio Informatique Année Premiers pas. Exercice 1 Hello World parce qu il faut bien commencer par quelque chose...

Stockage du fichier dans une table mysql:

TP n 2 Concepts de la programmation Objets Master 1 mention IL, semestre 2 Le type Abstrait Pile

I. Introduction aux fonctions : les fonctions standards

IFT Systèmes d exploitation - TP n 1-20%

Manuel d'installation

Cahier des charges. driver WIFI pour chipset Ralink RT2571W. sur hardware ARM7

Cours 14 Les fichiers

Exceptions. 1 Entrées/sorties. Objectif. Manipuler les exceptions ;

Pour signifier qu'une classe fille hérite d'une classe mère, on utilise le mot clé extends class fille extends mère

Arguments d un programme

Introduction à la Programmation Parallèle: MPI

Généralités sur le Langage Java et éléments syntaxiques.

INITIATION A LA PROGRAMMATION

RMI le langage Java XII-1 JMF

TP Service HTTP Serveur Apache Linux Debian

INITIATION AU LANGAGE C SUR PIC DE MICROSHIP

Cours de C. Allocation dynamique. Sébastien Paumier

Création d objet imbriqué sous PowerShell.

Programmation système en C/C++

Projet ISN - dossier réalisé par Randrianarimanana Stéphanie. Titre du projet : Site de rencontre. le nom de notre site de rencontre : Linkymeet

Java Licence Professionnelle CISII,

Utilisation d objets : String et ArrayList

Cours Programmation Système

Les fichiers. Chapitre 4

6 - Le système de gestion de fichiers F. Boyer, UJF-Laboratoire Lig, Fabienne.Boyer@imag.fr

Introduction au langage C

INF2015 Développement de logiciels dans un environnement Agile. Examen intra 20 février :30 à 20:30

Algorithmique et Programmation, IMA

Cours de Programmation Impérative: Zones de mémoires et pointeurs

STS SE. FreeRTOS. Programmation réseau WIFI. Programmation réseau. Socket Tcp. FlyPort smart Wi-Fi module

La programmation des PIC en C. Les fonctions, les interruptions.

Les vulnérabilités du noyau. LECORNET Olivier LEGROS Bruno VIGIER Nicolas Promo 2005

SYSTÈME DE GESTION DE FICHIERS

Conventions d écriture et outils de mise au point

Cours d Algorithmique-Programmation 2 e partie (IAP2): programmation 24 octobre 2007impérative 1 / 44 et. structures de données simples

SYSTÈME DE GESTION DE FICHIERS SGF - DISQUE

Premiers Pas en Programmation Objet : les Classes et les Objets

Cours 1 : Introduction. Langages objets. but du module. contrôle des connaissances. Pourquoi Java? présentation du module. Présentation de Java

Introduction aux buffer overflow, CS335

Programmation par les Objets en Java

1 Mesure de la performance d un système temps réel : la gigue

Cours 1: Java et les objets

Programmation Objet Java Correction

4. Groupement d objets

Chapitre VI- La validation de la composition.

Plan du cours. Historique du langage Nouveautés de Java 7

Session 8: Android File System

Entraînement à l épreuve de QCM 40 mn

Chapitre 10. Les interfaces Comparable et Comparator 1

Programme Compte bancaire (code)

ACTIVITÉ DE PROGRAMMATION

Langage C. Patrick Corde. 22 juin Patrick Corde ( Patrick.Corde@idris.fr ) Langage C 22 juin / 289

Guide d'installation de la base de données ORACLE 10g ( ) pour linux FEDORA CORE 4.

PROJET ALGORITHMIQUE ET PROGRAMMATION II

Programmation C++ (débutant)/instructions for, while et do...while

Gestion de la mémoire

TP3 : Manipulation et implantation de systèmes de fichiers 1

Mon premier rpm. 7 juin Avant de commencer RPM URPMI RPMBUILD... 2

INTRODUCTION A JAVA. Fichier en langage machine Exécutable

Initiation à la programmation de modules du noyau Linux

1.6- Génération de nombres aléatoires

Projet de programmation (IK3) : TP n 1 Correction

Communication par sockets

Travaux Dirigés n 1 : chaînes de caractères

Info0101 Intro. à l'algorithmique et à la programmation. Cours 3. Le langage Java

TP1. Outils Java Eléments de correction

ésylog, direction technique Esylog_PeerBackup outil de sauvegarde individuelle mails & fichiers personnels documentation technique

DE L ALGORITHME AU PROGRAMME INTRO AU LANGAGE C 51

Foucart Digeon SISR1-CH7 Mise en place d'un serveur FTP BTS SIO 08/04/2013. SISR1 CH7 Mise en place d'un serveur FTP. - Page 1 -

Transcription:

Projet M2 LSE SEE : Communication espace noyau / espace utilisateur Table des matières I.Introduction...1 II.But de l'exercice...2 III.Écriture du module...3 A.Squelette du module...3 B.Gestion de l'entrée dans le /proc...4 1.Structure file_operation et fonctions associées :...5 2.Création et destruction de l'entrée dans le /proc...7 IV.Exemple d'exécution du module réalisé :...7 V.Bibliographie...8 I. Introduction Une fois le «cœur» du traceur implémenté, on souhaite pouvoir, depuis l'espace utilisateur : Récupérer la trace ; Envoyer des commandes au traceur : par exemple le mettre en pause, ou encore remettre le traceur à zéro (reset). Il existe de nombreux moyens de communication entre l espace noyau et l'espace utilisateur : interface procfs et sysfs, signaux, sockets netlink, mapping mémoire, etc. [1]. Pour le projet aucun moyen n'est imposé, le choix est libre tant qu'il s'accompagne d'une justification argumentée. Dans ce document on donne un exemple de communication entre l'espace noyau et l'espace utilisateur en créant une entrée dans le /proc. Cela est réalisé via le développement d'un module pour le noyau Linux. II. But de l'exercice Nous souhaitons mettre en œuvre le système suivant : nous allons écrire un module (du code noyau, donc) qui maintient au niveau du noyau une variable avec une valeur donnée à l'initialisation. On souhaite pouvoir, depuis l'espace utilisateur : Recevoir des information sur ce module : on souhaite connaître la valeur de la variable ; Envoyer des commandes à ce module : on souhaite affecter une nouvelle valeur à cette variable. La communication entre l'espace utilisateur et le module se fera via une entrée dans le /proc : /proc/m2lse. Nous allons y créer un fichier (virtuel). Lorsqu'un programme de l'espace utilisateur tel que cat effectuera une lecture de ce fichier, nous renverrons la valeur de la variable. Lorsqu'un programme écrira dans ce fichier, nous affecterons la valeurs écrite à la Illustration II.1: Schéma du fonctionnement du système que l'on souhaite implémenter dans cet exercice 1/5

variable. Le fonctionnement du système est présenté sur l'illustration II.1 ci-contre. L'entrée dans le /proc sera gérée par le module, qui devra implémenter les fonctions de lecture et d'écriture du fichier /proc/m2lse, en plus de maintenir la variable. III. Écriture du module Pour gérer une entrée dans le /proc depuis du code noyau, il existe diverses méthodes. Ici on présente l'utilisation de la structure de données file_operations [2], qui va nous permettre notamment de définir le comportement de l'entrée dans le /proc lors de la lecture et de l'écriture. Pour gérer l'entrée dans le /proc, il nous faut donc : Créer un objet de type file_operations, et les fonctions associées, qui seront exécutée lors de l'ouverture, la lecture, l'écriture, et la fermeture du fichier dans le /proc ; Déclarer à l'initialisation du module la création de l'entrée dans le /proc en spécifiant son nom, les droits associé, et l'objet file_opération précédemment créé. Pour la création de l'entrée dans le /proc et sa gestion via file_operation, rajoutons les headers suivants dans notre module : #include <linux/proc_fs.h> /* pour l'entrée dans le /proc */ #include <linux/fs.h> /* pour file_operation */ #include <linux/string.h> /* pour manipuler les strings lues et écrites */ #include <asm/uaccess.h> /* pour la copie de données entre l'userspace et le kernel */ 1. Structure file_operation et fonctions associées : On déclare notre objet file_operation de manière suivante, en tant que variable globale à notre module : struct file_operations fops_m2lse =.owner = THIS_MODULE,.read = procfile_m2lse_read,.write = procfile_m2lse_write,.open = procfile_m2lse_open,.release = procfile_m2lse_close, ; Cet objet contient des noms de fonctions qui seront exécutés lors de la lecture, l'écriture, l'ouverture et la fermeture de notre fichier dans le /proc. Il reste à écrire ces fonctions dans notre module. Bien entendu, chaque fonction doit respecter un prototype donné. Les fonctions d'ouverture et de fermeture ne font rien de particulier dans notre cas (il s'agit d'un fichier très simple), on les écrit de la sorte : int procfile_m2lse_open(struct inode *inode, struct file *filp) /*Rien de particulier à faire */ int procfile_m2lse_close(struct inode *inode, struct file *filp) /* Rien de particulier à faire non plus */ 2/5

Pour ce qui est des fonctions de lecture et d'écriture, c est là que les choses importantes se passent. On rappelle que lorsqu'on écrit dans le fichier du /proc, on affecte à la variable la valeur écrite, et lorsqu'on lit ce fichier, on renvoie la valeur de la variable. Fonction de lecture : la fonction de lecture d'un objet file_operation prend en paramètre un certain nombre d'arguments, en particulier un buffer de données utilisateur à remplir avec les données qui sont lues, la taille de ce buffer, et un offset indiquant à quel endroit dans le fichier la lecture commence. L'implémentation de cette fonction est la suivante : ssize_t procfile_m2lse_read(struct file *file, char user *buf, size_t size, loff_t *ppos) /* buf est le buffer utilisateur qu'il faut remplir avec les données lues */ char tmp[32]; int ret, bytes_read = 0; /* Si le buffer utilisateur est trop petit on ne lit rien (pas terrible) */ if(size < 32) /* Si l'offset est différent de 0 la lecture à déja eu lieu : on * renvoie 0 pour terminer l'opération. Si l'offset est à 0 on * effectue la lecture, et on décale l'offset */ if((*ppos) == 0) /* 1. Copie dans un buffer au niveau noyau */ bytes_read = sprintf(tmp, "MaVariable vaut %d\n", mavariable); /* 2. Copie des données noyau vers l'espace utilisateur */ ret = copy_to_user(buf, tmp, bytes_read); /* 3. Décalage de l'offset */ *ppos += bytes_read; /* On renvoie byte_read, le nombre d'octets lus (qui vaut * éventuellement 0 dans le cas ou la lecture à déja été effectuée) */ return bytes_read; Cette fonction contient quelques subtilités. Un programme (cat par exemple) effectuant une lecture de l'entrée dans le /proc va déclencher l'exécution de cette fonction. Le système s'attend à recevoir en valeur de retour de cette fonction le nombre d'octets lus. Tant que ce nombre n'est pas égal à 0, cette fonction sera appelée en boucle : c'est ainsi car les buffers utilisateurs à remplir passés en paramètre ont une taille finie, et il faut parfois remplir plusieurs buffers pour stocker l'intégralité d'un fichier de taille supérieur à la taille du buffer. Dans ce genre de cas, l'offset où lire dans le fichier (paramètre ppos) est incrémenté par la fonction de lecture en fonction du nombre d'octets lus, pour savoir à quel endroit recommencer la lecture lors de l'appel suivant. Dans notre cas, nous souhaitons faire lire à cette fonction une chaîne de caractères très courte, du genre «mavariable vaut 42» : on vérifie en début de fonction que le buffer à au moins une taille égale à 32 octets (suffisant pour écrire ce que l'on veut). Si ce n'est pas le cas, on retourne 0 et rien n'est lu. La commande cat utilise des buffers utilisateurs de 4 Ko, largement suffisants pour notre cas. Si le buffer utilisateur est assez grand, on passe à la phase de lecture. On écrit tout 3/5

d'abord dans un buffer temporaire une chaîne de caractères comportant la valeur de la variable mavariable. On copie alors dans le buffer utilisateur la valeur de cette chaîne de caractères : en effet, les espaces mémoires noyaux et utilisateurs sont très distincts sous Linux [3], et il serait dangereux d'écrire directement dans un buffer utilisateur depuis le noyau. On utilise donc la fonction copy_to_user, dont le prototype est le suivant : int copy_to_user(void *dst, const void *src, unsigned int size); Cette fonction copie size octets de données depuis l'adresse src dans l'espace noyau vers l'adresse dst dans l'espace utilisateur. Une fois la copie réalisée on incrémente l'offset avec le nombre d'octets lus. On renvoie alors le nombre d'octets lus. Comme la valeur renvoyée par la fonction de lecture est différente de 0, cette fonction va directement être ré-appelée. Dans ce deuxième appel l'offset sera alors égal à la valeur définie à l'appel précédent, et donc différent de 0 : on utilise cela comme repère pour savoir que l'on est au niveau du deuxième appel : on renvoie alors 0 pour terminer l'opération de lecture. Fonction d'écriture : Cette dernière est un peu plus simple. Lorsque l'on écrit une valeur dans notre entrée du /proc (par exemple via la fonction echo redirigée dans le fichier), cette fonction est lancée. L'implémentation est la suivante : ssize_t procfile_m2lse_write(struct file *file, const char user *buf, size_t size, loff_t *ppos) int val; /* On récupère la valeur écrite et on la convertit en int */ val = simple_strtoul(buf, NULL, 10); /* On affecte cette valeur à mavariable */ mavariable = val; /* On retourne le nombre d'octets écrits */ return size; La fonction d'écriture possède des arguments semblables à la fonction de lecture. Cette fois, le buffer utilisateur contient les données à écrire. Nous n'allons pas réellement écrire ces données dans le fichier, mais plutôt récupérer la valeur à écrire, la convertir en entier puis affecter à mavariable cette valeur. A la fin de la fonction on renvoie le nombre d'octets que la fonction appelante aurait souhaité écrire (size) pour éviter des erreurs. Attention : penser à placer les prototypes des fonctions auxquelles ont fait référence au niveau de la déclaration de l'objet file_operations avant cette déclaration, sans quoi le compilateur risque de retourner une erreur comme quoi ces fonctions n'existent pas! 2. Création et destruction de l'entrée dans le /proc Il nous reste à créer, au lancement du module, le fichier /proc/m2lse. Pour ce faire on déclare en global dans le module un objet de type struct proc_dir_entry : struct proc_dir_entry *proc_file_flashmon; On utilise alors cet objet pour déclarer, dans la fonction d'initialisation du module, la création de l'entrée dans le /proc. On passe de plus en paramètres le nom du fichier, 4/5

ses droits, ainsi que la structure file_operation qui pointe vers les fonction d'accès définies ci-dessus : proc_file_flashmon = proc_create("m2lse", S_IWUGO S_IRUGO, NULL, &fops_m2lse); Il reste enfin à supprimer ce fichier lorsque le module est déchargé. On place un appel à fonction suivante dans la fonction de sortie du module : remove_proc_entry("m2lse", NULL); IV. Exemple d'exécution du module réalisé : Après compilation et transfert du fichier module_m2lse.ko sur la carte, on peut l'exécuter et vérifier son bon fonctionnement : # ls module_m2lse.ko # insmod module_m2lse.ko # ls -l /proc/m2lse -rw-rw-rw- 1 root root 0 Jul 21 13:14 /proc/m2lse # cat /proc/m2lse MaVariable vaut 42 # echo 33 > /proc/m2lse # cat /proc/m2lse MaVariable vaut 33 # rmmod module_m2lse.ko # ls -l /proc/m2lse ls: /proc/m2lse: No such file or directory V. Bibliographie [1] Une page web détaillant différents moyens de communication entre l'espace noyau et l'espace utilisateur, avec des exemples : http://people.ee.ethz.ch/~arkeller/linux/kernel_user_space_howto.html [2] Des informations sur la structure file_operation : http://thesermon.free.fr/file_operations.html [3] Accès à l'espace mémoire utilisateur depuis le noyau : http://www.ibm.com/developerworks/linux/library/l-kernel-memory-access /index.html 5/5