ex0ns

about
A Computer Science Student's blog, about programming, algorithms, hack and a lot more.

Gestion des processus sur GNU/Linux

01 Jul 2012

D'après Wikipédia (qui lui même cite la norme ISO 9000), un processus est:

L’ensemble d’activités corrélées ou interactives qui transforme des éléments d’entrée en éléments de sortie

Plus clairement, on retrouve quelques lignes plus bas, une autre définition du terme processus:

Un processus est une tâche en train de s’exécuter. On appelle processus l’image de l’état du processeur et de la mémoire au cours de l’exécution d’un programme.

Vous l’aurez compris, un processus est une tache en cours d’exécution sur votre système d’exploitation, on peut citer votre navigateur, serveur graphique (Xorg).

Le noyau Linux fournit des informations à l’utilisateur à travers un système de fichier nommé “proc”, que se situe à la racine : “/proc”, ce dossier contient de nombreux fichiers contenant des informations concernant le noyau (vous pouvez trouver dans ces fichiers des informations sur l’utilisation des différents processeur, la température de l’ordinateur, la vitesse de ventilation).

Mais comme vous l’avez remarqué de nombreux dossiers sont également présents, la plupart d’entre eux ont un nom numérique (entre 1 et 6 chiffres), chacun de ces dossiers correspond à un processus, il porte le PID (Process Identifier) du processus correspondant, pour connaitre le PID d’un processus, il vous suffit d’entrer la commande : “pidof ” .

Ainsi chaque sous dossier du “/proc” est un dossier contenant les informations sur un processus (correspondant au nom du dossier), à partir de là, il est possible de rassembler énormément d’informations sur ce dernier, c’est ce que nous allons faire, à travers un “gestionnaire de processus” codé en C++. Pour la première partie, les connaissances requises sont faibles, nous n’allons que manipuler des flux (fstream, sstream) et dans une seconde partie, nous élaborerons une petite interface graphique à l’aide de Gtkmm, dont le code sera explicité un minimum, mais étant donné qu’il ne s’agit pas du but de cet article, il pourra subsister des zones d’ombre (un article sur gtkmm est prévu, car cette bibliothèque graphique est très sympathique).

Chaque “dossier processus” du “/proc” contient de nombreuses informations relatives au fonctionnement de ce dernier, vous pouvez fouiller un peu dans ces dossiers/fichiers, ils ne vous mordront pas.

Le fichier auquel nous allons nous intéresser est le fichier “/proc/<PID>/status” , il contient le nom, l’id, l’UID (user identifier) et beaucoup d’autres informations qui sont moins intéressantes pour nous, mais utiles à certaines occasions.

Le fichier “status” se compose de la façon suivante :

Nom: valeur

Parfois il y a plusieurs valeurs, mais nous nous intéresserons qu’a la première valeur du nom (pour faciliter la récupération d’informations lors du parsage du fichier). Votre mission, si vous l’acceptez, est de lister tous les processus qui tournent sur le système : nom, PID, et le nom de leur propriétaire (UID).

Voici le code :

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <map>
#include <sys/types.h>
#include <dirent.h>
#include <pwd.h>

int strToInt(std::string value){
    std::istringstream temp(value);
    int returned;
    temp >> returned;
    return returned; // Retourne la valeur si value était un nom "numérique", 0 dans le cas contraire.
}
int main(int argc, char* argv[]){

    std::ifstream subInput; // Ouverture des fichiers /proc/<PID>/status
    std::stringstream fileName; //  
    std::string buffer, name, value; // Name et Value sont des variables que l'on utilise pour parser le fcihier /proc/<PID>/status
    std::map<std::string,std::string> process; // "tableau associatif", on associe chaque propriété du processus à sa valeur
    DIR *dir; 
    struct dirent *subDir;
    dir = opendir("/proc/"); // On ouvre le /proc pour lister les processus
    while(subDir = readdir(dir)){ // tant qu'il y a des sous dossiers
        if(strToInt(subDir->d_name)){ // On vérifie si le nom du dossier est numérique
            fileName.str(""); // Vide le flux du nom du fichier
            fileName << "/proc/" << subDir->d_name << "/status"; // Récupération du status correspondant au processus qu'on lit
            subInput.open(fileName.str().c_str(), std::ios::in); 
            while(!subInput.eof()){ // Lecture de l'intégralité du fichier status du processus
                /* 
                   ce passage est le plus "complexe" du code, en effet, on récupère la ligne du fichier, et on la stocke dans un stringstream,
                   pourquoi ne pas directement lire les valeurs de la ligne dans les variables ?
                   Car comme vous avez pu le constater, une propriété à parfois plusieurs valeurs, il y aurait donc un problème lors de la lecture du fichier.
                   Si quelqu'un à une autre méthode (sans utiliser sscanf ou fscanf) cela m'interesse.
                */
                std::stringstream bufferString; 
                getline(subInput,buffer); 
                bufferString << buffer; 
                bufferString >> name >> value;
                process.insert(std::pair<std::string,std::string>(name,value)); // On associe la propriété à sa valeur
            }
            std::cout << process["Name:"] << " " << process["Pid:"] << " " << getpwuid(strToInt(process["Uid:"]))->pw_name << std::endl;
            /* 
               Affichage du résultat, tout simplement, petite subtilité pour récupérer le nom d'utilisateur à partir de l'UID, je vous revois à la fonction
               http://www.linux-kheops.com/doc/man/manfr/man-html-0.9/man3/getpwuid.3.html
            */
            subInput.close();
            process.clear();
        }
    }
}

Sur pastebin : http://pastebin.com/svk6tY9m

Nous verrons dans la suite, comment faire une interface graphique simple à l'aide de GTKmm en C++.

En espérant avoir été clair !