Chapitre 10 : Les processus
Définition et environnement
Un processus représente à la fois un programme en cours d’exécution et tout son environnement d’exécution (mémoire, état, identification, propriétaire, père …). Voir les cours de Système d’exploitation.
Voici une liste des données d’identification d’un processus :
- Un numéro de processus unique PID : chaque processus Unix est numéroté afin de pouvoir être différencié des autres. Le premier processus lancé par le système est 1 et il s’agit d’un processus appelé généralement init. On utilise le PID quand on travaille avec un processus. Lancer 10 fois le même programme (même nom) donne 10 PID différents.
- Un numéro de processus parent PPID : chaque processus peut lui-même lancer d’autres processus, des processus enfants (child process). Chaque enfant reçoit parmis les informations le PID du processus père qui l’a lancé. Tous les processus ont un PPID sauf le processus 0 qui est un pseudo-processus représentant le démarrage du système (créé le 1init).
- Un numéro d’utilisateur et un numéro de groupe : correspond à l’UID et au GID de l’utilisateur qui a lancé le processus. C’est nécessaire pour que le système sache si le processus à le droit d’accéder à certaines ressources ou non. Les processus enfants héritent de ces informations. Dans certains cas (que nous verrons plus tard) on peut modifier cet état.
- Durée de traitement et priorité : la durée de traitement correspond au temps d’exécution écoulé depuis le dernier réveil du processus. Dans un environnement multitâches, le temps d’exécution est partagé entre les divers processus, et tous ne possèdent pas la même priorité. Les processus de plus haute priorité sont traités en premier. Lorsqu’il est inactif sa priorité augmente afin d’avoir une chance d’être exécuté. Lorsqu’il est actif, sa priorité baisse afin de laisser sa place à un autre. C’est le scheduler du système qui gère les priorités et les temps d’exécution.
- Répertoire de travail actif : A son lancement, le répertoire courant (celui depuis lequel le processus a été lancé) est transmis au processus. C’est ce répertoire qui servira de base pour les chemins relatifs.
- Fichiers ouverts : table des descripteurs des fichiers ouverts. Par défaut au début seuls trois sont présents : 0 1 et 2 (les canaux standards). A chaque ouverture de fichier ou de nouveau canal, la table se remplit. A la fermeture du processus, les descripteurs sont fermés (en principe).
- On trouve d’autres informations comme la taille de la mémoire allouée, la date de lancement du processus, le terminal d’attachement, l’état du processus, UID effectif et Reel ainsi que GID effectif et réel.
Etats d’un processus
Durant sa vie (temps entre le lancement et la sortie) un processus peut passer par divers états ou process state :
- Exécution en mode utilisateur ( user mode )
- Exécution en mode noyau ( kernel mode )
- En attente E/S ( waiting )
- Endormi ( sleeping )
- Prêt à l’exécution ( runnable )
- Endormi dans le swap ( mémoire virtuelle )
- Nouveau processus
- Fin de processus ( Zombie )
Lancement en tâche de fond
En suivant ce que nous avons vu avant, le système étant multi-tâches un certain nombre de processus tournent déjà sur la machine sans que nous le voyons. De même le shell que nous utilisons est lui-même un processus. Quand une commande est saisie, le shell créé un nouveau processus pour l’exécuter, ce processus devient un processus enfant du shell. Jusqu’à présent il fallait attendre la fin de l’exécution d’une commande pour en saisir une autre (sauf à utiliser le ; pour chaîner les commandes).
Rien n’empêche le shell d’attendre le message du processus terminé pour rendre la main : de ce fait la commande une fois lancé, le shell peut autoriser la saisie d’une nouvelle commande sans attendre la fin de l’exécution de la commande précédente. Pour cela il suffit de saisir, après avoir tapé la commande, le ET Commercial « & ». Dans ce cas le shell et la commande lancée fonctionneront en parallèle.
$ ls -R / > ls.txt 2>/dev/null &
[1] 21976
$
[1] Done ls -l -R / > ls.txt 2>/dev/null
$ ls
fic1 fic3 liste ls.txt rep1 users
fic2 fic4 liste2 mypass toto.tar.gz
Juste après la saisie un chiffre apparaît, il est à retenir car il s’agit du PID du nouveau processus lancé. Après une autre saisie une ligne Done indique que le traitement est terminé. La valeur [1] est propre à un shell particulier (ksh).
Quelques remarques sur l’utilisation du lancement en tâche de fond :
- Le processus lancé ne devrait pas attendre de saisie au risque de confusion entre cette commande et le shell lui-même.
- Le processus lancé ne devrait pas afficher de résultats sur l’écran au risque d’avoir des affichages en conflit avec celui du shell (par exemple apparition d’une ligne en milieu de saisie).
- Enfin, quand on quitte le shell, on quitte aussi tous ses fils : dans ce cas ne pas quitter le shell pendant un traitement important.
wait
Lorsqu’un processus est en tâche de fond, il est possible de récupérer et d’attendre la fin de la dernière commande lancée en arrière-plan avec la commande wait [pid]. S’il s’agit d’une autre commande, alors il est important d’avoir noté le PID de celle-ci lorsqu’elle a été lancée.
Liste des processus
La commande ps (process status) permet d’avoir des informations sur les processus en cours. Lancée seule, elle n’affiche que les processus en cours lancés depuis l’utilisateur et la console actuels. Nous détaillerons les colonnes plus loin.
$ ps
PID TTY S TIME CMD
22608 ttyp0 S 0:00.04 -csh (csh)
Pour avoir plus d’informations, on peut utiliser l’option -f.
$ ps -f
UID PID PPID C STIME TTY TIME CMD
oracle 22608 12288 0.0 15:20:09 ttyp0 0:00.05 -csh (csh)
L’option -e donnes des informations sur tous les processus en cours.
$ ps -ef
UID PID PPID C STIME TTY TIME CMD
root 0 0 0.0 Aug 11 ?? 2:26.95 [kernel idle]
root 1 0 0.0 Aug 11 ?? 0:01.87 /sbin/init -a
root 3 1 0.0 Aug 11 ?? 0:00.27 /sbin/kloadsrv
root 51 1 0.0 Aug 11 ?? 1:30.22 /sbin/update
root 165 1 0.0 Aug 11 ?? 0:00.35 /usr/sbin/syslogd
root 169 1 0.0 Aug 11 ?? 0:00.02 /usr/sbin/binlogd
root 229 1 0.0 Aug 11 ?? 0:00.00 /usr/sbin/routed
root 260 1 0.0 Aug 11 ?? 0:01.65 /usr/sbin/rwhod
root 349 1 0.0 Aug 11 ?? 0:00.02 /usr/sbin/portmap
root 351 1 0.0 Aug 11 ?? 0:00.00 /usr/sbin/nfsiod 7
root 354 1 0.0 Aug 11 ?? 0:00.01 /usr/sbin/rpc.statd
root 356 1 0.0 Aug 11 ?? 0:00.01 /usr/sbin/rpc.lockd
root 587 1 0.0 Aug 11 ?? 0:00.23 /usr/sbin/xntpd -gx -l
root 626 1 0.0 Aug 11 ?? 0:00.06 /usr/sbin/snmpd
root 646 1 0.0 Aug 11 ?? 0:00.84 /usr/sbin/inetd
root 654 1 0.0 Aug 11 ?? 0:00.01 /usr/sbin/svrMgt_mib
root 655 1 0.0 Aug 11 ?? 0:00.03 /usr/sbin/svrSystem_mi
root 657 1 0.0 Aug 11 ?? 0:00.03 /usr/sbin/os_mibs
root 659 1 0.0 Aug 11 ?? 0:00.08 /usr/sbin/cpq_mibs
root 704 1 0.0 Aug 11 ?? 0:01.46 /usr/sbin/cron
root 718 1 0.0 Aug 11 ?? 0:00.01 /usr/lbin/lpd
...
L’option -u permet de préciser une liste d’un ou plusieurs utilisateurs séparés par une virgule. L’option -g effectue la même chose mais pour les groupes, -t pour les terminaux et -p pour des PID précis.
$ ps -u oracle
PID TTY S TIME CMD
2308 ?? S 0:02.27 /mor/app/oracle/product/8.1.7/bin/tnslsnr LISTENER -inherit
2311 ?? S 0:00.98 /mor/app/oracle/product/8.1.7/bin/tnslsnr DIVERS -inherit
2334 ?? S 0:00.22 ora_pmon_ORAP
2336 ?? S 0:01.79 ora_dbw0_ORAP
2338 ?? S 0:02.94 ora_lgwr_ORAP
2340 ?? S 0:20.23 ora_ckpt_ORAP
2342 ?? S 0:04.42 ora_smon_ORAP
2344 ?? S 0:00.09 ora_reco_ORAP
2346 ?? S 0:03.11 ora_snp0_ORAP
2348 ?? S 0:02.73 ora_snp1_ORAP
2350 ?? S 0:02.52 ora_snp2_ORAP
2352 ?? S 0:02.69 ora_snp3_ORAP
2354 ?? S 0:00.08 ora_arc0_ORAP
2369 ?? S 0:00.21 ora_pmon_OLAP
2371 ?? S 0:00.22 ora_dbw0_OLAP
...
Enfin l’option -l propose plus d’informations techniques.
$ ps -l
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
80808001 S 75 22608 12288 0.0 44 0 0 424K pause ttyp0 0:00.06 csh
| Colonne | Définition |
|---|---|
UID |
User ID, nom de l’utilisateur |
PID |
Process ID, numéro du processus |
PPID |
Parent Process ID, numéro du processus père |
C |
Facteur de priorité, plus la valeur est grande plus la priorité est élevée |
STIME |
Heure de lancement du processus |
TTY |
Nom du terminal depuis lequel le processu a été lancé. |
TIME |
Durée de traitement du processus |
CMD |
Commande exécutée |
F |
Drapeaux du processus (sort du cadre du cours) |
S |
Etat du processus S (sleeping) R (running) Z (zombie) |
PRI |
Priorité du processus |
NI |
Nice, incrément pour le scheduler |
Arrêt d’un processus / signaux
Lorsqu’un processus tourne en tâche de fond il ne peux pas être arrêté par une quelconque combinaison de touches. Pour cela il faut employer la commande kill. Contrairement à ce que son nom semble indiquer, le rôle de cette commande n’est pas forcément de détruire ou de terminer un processus (récalcitrant ou non), mais d’envoyer des signaux aux processus.
kill [-l] -Num_signal PID [PID2...]
Le signal est l’un des moyens de communication entre les processus. Lorsqu’on envoie un signal à un processus, celui-doit doit l’intercepter et réagir en fonction de celui-ci. Certains signaux peuvent être ignorés, d’autres non. Suivant les Unix on dispose d’un nombre plus ou moins important de signaux. Les signaux sont numérotés et nommés, mais attention si les noms sont généralement communs d’un Unix à l’autre, les numéros ne le sont pas forcément. L’option -l permet d’obtenir la liste des signaux.
Voici ceux qui nous concernent.
| Signal | Rôle |
|---|---|
| 1 (SIGHUP) | Hang Up, est envoyé par le père à tous ses enfants lorsqu’il se termine |
| 2 (SIGINT) | Interruption du processus demandé (touche suppr, Ctrl+C) |
| 3 (SIGQUIT) | Idem SIGINT mais génération d’un Core Dump (fichier de débuggage) |
| 9 (SIGKILL) | Signal ne pouvant être ignoré, force le processus à finir ‘brutalement’. |
| 15 (SIGTERM) | Signal envoyé par défaut par la commande kill. Demande au processus de se terminer normalement. |
$ ps
PID TTY S TIME CMD
22608 ttyp0 S 0:00.04 -csh (csh)
22610 ttyp0 R 0:00.05 ls
$ kill 22610
22610 Terminated
...
$ ps
PID TTY S TIME CMD
22608 ttyp0 S 0:00.04 -csh (csh)
22615 ttyp0 R 0:00.05 ls
$ kill -9 22615
22615 (killed)
nohup
Quand le shell est quitté (exit, ctrl+D, …) nous avons vu que le signal 1 SIGHUP est envoyé aux enfants pour qu’ils se terminent aussi. Lorsqu’un traitement long est lancé en tâche de fond et que l’utilisateur veut quitter le shell, ce traitement sera alors arrêté et il faudra tout recommencer. Le moyen d’éviter cela est de lancer le traitement (processus) avec la commande nohup. Dans ce cas le processus lancé ne réagira plus au signal SIGHUP, et donc le shell peut être quitté, la commande continuera sont exécution.
Par défaut avec nohup (sous sh bash et ksh) les canaux de sortie et d’erreur standards sont redirigés vers un fichier nohup.out, sauf si la redirection est explicitement précisée.
$ nohup ls -lR / &
10206
$ Sending output to nohup.out
$ ls
fic1 fic3 liste ls.txt nohup.out toto.tar.gz
fic2 fic4 liste2 mypass rep1 users
nice et renice
La commande nice permet de lancer une commande avec une priorité plus faible, afin de permettre éventuellement à d’autres processus de tourner plus rapidement.
nice [-valeur] commande [arguments]
nice [-n valeur] commande [arguments]
Les deux syntaxes sont généralement admises, à vérifier avec les manpages. La valeur représenta la priorité du traitement. Pour la seconde syntaxe une valeur positive causera une baisse de priorité, une négative l’augmentation de la priorité (si autorisé). La première syntaxe n’accepte qu’un abaissement de la priorité. La valeur doit être comprise entre 1 et 20. Plus la valeur est élevée et plus le traitement est ralenti.
$ nice -10 ls -lR / >liste 2>/dev/null&
10884
$ ps -l
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
80808001 S 75 10153 10115 0.0 44 0 0 424K pause ttyp4 0:00.09 csh
80808001 S + 75 10822 10153 0.0 44 0 0 192K wait ttyp4 0:00.01 sh
80808001 U N+ 75 10884 10822 28.5 54 10 0 848K aa3b3a9c ttyp4 0:03.32 ls
La commande renice fonctionne un peu comme nice sauf qu’elle permet de modifier la priorité en fonction d’un utilisateur, d’un groupe ou d’un PID. La commande doit donc déjà tourner.
renice [-n prio] [-p] [-g] [-u] ID
La priorité doit être comprise entre -20 et 20. L’utilisateur standard ne peut utiliser que les valeurs entre 0 et 20 permettant de baisser la priorité. L’option -p précise un PID, -g un GID et -u un UID.
time
La commande time mesure les durées d’exécution d’une commande, idéal pour connaître les temps de traitement, et retourne trois valeurs :
- real : durée totale d’exécution de la commande
- User : durée du temps CPU nécessaire pour exécuter le programme
- System : durée du temps CPU nécessaire pour exécuter les commandes liées à l’OS (appels système au sein d’un programme).
Le résultat est sorti par le canal d’erreur standard 2. On peut avoir une indication de la charge de la machine par le calcul Real / (User+System). Si le résultat est inférieur à 10, la machine dispose de bonnes performances, au-delà de 20 la charge de la machine est trop lourdes (performances basses).
$ time ls -lR /home
...
real 4.8
user 0.2
sys 0.5
Droits d’accès étendus
SUID et SGID
Il est possible d’établir des droits d’accès étendus à l’exécution d’une commande. Ces droits d’accès étendus appliqués à une commande permettent à cette commande de s’exécuter avec les droits du propriétaire ou du groupe d’appartenance de la commande, et non plus avec les droits de l’utilisateur l’ayant lancé.
L’exemple le plus simple est le programme passwd permettant de changer son mot de passe. Si la commande était exécutée avec les droits d’un utilisateur classique, passwd ne pourrait pas ouvrir et modifier les fichiers /etc/passwd et /etc/shadow :
$ ls -l /etc/passwd
-rw-r--r-- 1 root system 4010 Jun 6 12:26 /etc/passwd
Nous voyons que ce fichier appartient à root, et que seul root peut y écrire. Un utilisateur simple ne peut lire que son contenu sans interagir. La commande passwd ne devrait donc pas pourvoir modifier les fichiers. Voyons la commande passwd (/bin/passwd ou /usr/bin/passwd) :
$ ls -l /usr/bin/passwd
-rws--x--x 3 root bin 16384 Apr 12 1999 /usr/bin/passwd
Un nouveau droit est apparu : le droit « s » pour les droits de le l’utilisateur root. Ce nouvel attribut permet l’exécution de la commande avec des droits d’accès étendus. Le temps du traitement, le programme est exécuté avec les droits du propriétaire du fichier ou de son groupe d’appartenance. Dans le cas de passwd, il est lancé avec les droits de root le temps de son traitement.
Le droit « s » sur l’utilisateur est appelé le SUID-Bit, et sur le groupe le GUID-Bit
La commande chmod permet de placer les SUID-Bit et GUID-Bit.
chmod u+s commande
chmod g+s commande
Les valeurs octales sont 4000 pour le SUID-Bit et 2000 pour le GUID-Bit.
chmod 4755 commande
chmod 2755 commande
Seul le propriétaire ou l’administrateur peut positionner ce droit. Positionner le SUID-bit ou le SGID-Bit n’a de sens que si les droits d’exécution ont préalablement été établis (attribut x sur le propriétaire ou le groupe). Si ceux-ci ne sont pas présents; le « s » est remplacé par un « S ».
Real / effectif
Dans les données d’identification du processus nous avons vu la présence UID et de GID réels et effectifs. Quand une commande est lancée avec un SUID-Bit ou un SGID-Bit positionné, les droits se trouvent modifiés. Le système conserve les UID et GID d’origine de l’utilisateur ayant lancé la commande (UID et GID réels) transmis par le père, les numéros UID et GID effectifs étant ceux du propriétaire ou du groupe d’appartenance du programme.
Ex : toto (UID=100, GID=100) lance passwd, appartenant à root (UID=1, GID=2) avec le SUID-Bit positionné.
UID réel : 100
GID réel : 100
UID effectif : 1
GID effectif : 100
Si le SGID-Bit était positionné seul :
UID réel : 100
GID réel : 100
UID effectif : 100
GID effectif : 2
Il est à noter que les SUID-Bit et SGID-bit ne sont pas transmis aux enfants d’un processus. Dans ce cas les enfants seront exécutés avec les droits de l’utilisateur ayant lancé la commande de base.
Sticky bit
Le Sticky-bit (bit collant) permet d’affecter une protection contre l’effacement du contenu d’un répertoire.
Imaginons un répertoire /tmp où tous les utilisateurs ont le droit de lire et d’écrire des fichiers.
$ ls -ld /tmp
drwxrwxrwx 6 root system 16384 Aug 14 13:22 tmp
Dans ce répertoire tout le monde peut supprimer des fichiers y compris ceux qui ne lui appartiennent pas (droit w présent partout et pour tous). Si l’utilisateur toto crée un fichier, l’utilisateur titi peut le supprimer même s’il ne lui appartient pas.
Le Sticky-Bit appliqué à un répertoire, ici /tmp, empêche cette manipulation. Si le fichier peut encore être visualisé et modifié, seul son propriétaire (et l’administrateur) pourra le supprimer.
$ chmod u+t /tmp
$ ls -ld /tmp
drwxrwxrwt 6 root system 16384 Aug 14 13:22 tmp
En octal, on utilisera la valeur 1000 (chmod 1777 /tmp)
Bien qu’appliqué à l’utilisateur, le Sticky-bit, représenté par un « t » apparaît au niveau de « others ».
Photo sous licence libre récupérée gratuitement sur freepik.com