29.2. /proc

Le répertoire /proc est en fait un pseudo-système de fichiers. Les fichiers dans le répertoire /proc sont un miroir du système en cours d'exécution et des processus du noyau, et contiennent des informations et des statistiques sur elles.

bash$ cat /proc/devices
Character devices:
   1 mem
   2 pty
   3 ttyp
   4 ttyS
   5 cua
   7 vcs
  10 misc
  14 sound
  29 fb
  36 netlink
 128 ptm
 136 pts
 162 raw
 254 pcmcia

 Block devices:
   1 ramdisk
   2 fd
   3 ide0
   9 md



bash$ cat /proc/interrupts
           CPU0
   0:      84505          XT-PIC  timer
   1:       3375          XT-PIC  keyboard
   2:          0          XT-PIC  cascade
   5:          1          XT-PIC  soundblaster
   8:          1          XT-PIC  rtc
  12:       4231          XT-PIC  PS/2 Mouse
  14:     109373          XT-PIC  ide0
 NMI:          0
 ERR:          0



bash$ cat /proc/partitions
major minor  #blocks  name     rio rmerge rsect ruse wio wmerge wsect wuse running use aveq

    3     0    3007872 hda 4472 22260 114520 94240 3551 18703 50384 549710 0 111550 644030
    3     1      52416 hda1 27 395 844 960 4 2 14 180 0 800 1140
    3     2          1 hda2 0 0 0 0 0 0 0 0 0 0 0
    3     4     165280 hda4 10 0 20 210 0 0 0 0 0 210 210
    ...



bash$ cat /proc/loadavg
0.13 0.42 0.27 2/44 1119

bash$ cat /proc/apm
1.16 1.2 0x03 0x01 0xff 0x80 -1% -1 ?

bash$ cat /proc/acpi/battery/BAT0/info
present:                 yes
 design capacity:         43200 mWh
 last full capacity:      36640 mWh
 battery technology:      rechargeable
 design voltage:          10800 mV
 design capacity warning: 1832 mWh
 design capacity low:     200 mWh
 capacity granularity 1:  1 mWh
 capacity granularity 2:  1 mWh
 model number:            IBM-02K6897
 serial number:            1133
 battery type:            LION
 OEM info:                Panasonic



bash$ fgrep Mem /proc/meminfo
MemTotal:       515216 kB
 MemFree:        266248 kB
         

Des scripts shells peuvent extraire des données à partir de certains des fichiers de /proc. [117]

FS=iso
grep $FS /proc/filesystems # iso9660
kernel_version=$( awk '{ print $3 }' /proc/version )
CPU=$( awk '/model name/ {print $5}' < /proc/cpuinfo )

if [ "$CPU" = "Pentium(R)" ]
then
  lance_des_commandes
  ...
else
  lance_autres_commandes
  ...
fi



vitesse_cpu=$( fgrep "cpu MHz" /proc/cpuinfo | awk '{print $4}' )
#  La vitesse d'exécution actuelle (en MHz) du CPU de votre machine.
#  Sur un portable, cela peut varier suivant que vous utilisez la batterie
#+ ou le secteur.
#!/bin/bash
# get-commandline.sh
# Obtient les paramètres en ligne de commande d'un processus.

OPTION=cmdline

# Identifie le PID.
pid=$( echo $(pidof "$1") | awk '{ print $1 }' )
# Récupère seulement le premier
#                           ^^^^^^^^^^^^^^^^^^ de plusieurs instances.

echo
echo "ID du processus de (la première instance de) "$1" = $pid"
echo -n "Arguments en ligne de commande : "
cat /proc/"$pid"/"$OPTION" | xargs -0 echo
#   Formate la sortie :        ^^^^^^^^^^^^^^^
#   (Merci pour la correction, Han Holl !)

echo; echo


# Par exemple :
# sh get-commandline.sh xterm
fichier_dev="/proc/bus/usb/devices"
texte="Spd"
USB1="Spd=12"
USB2="Spd=480"


vitesse_bus=$(fgrep -m 1 "$texte" $fichier_dev | awk '{print $9}')
#                 ^^^^ s'arrête après la première correspondance.

if [ "$vitesse_bus" = "$USB1" ]
then
  echo "Port USB 1.1 découvert."
  # Faire quelque chose d'appropriée avec USB 1.1.
fi
[Note]

Note

Il est même possible de contrôler certains périphériques avec des commandes envoyées au répertoire /proc.

          root# echo on > /proc/acpi/ibm/light
          

Ceci active Thinklight sur certains modèles Thinkpad d'IBM/Lenovo. (Cela pourrait ne pas fonctionner sur toutes les distributions Linux.)

Bien sûr, vous devez faire particulièrement attention quand vous écrivez dans /proc.

Le répertoire /proc contient des sous-répertoires avec des noms numériques inhabituels. Chacun de ces noms correspond à un numéro de processus d'un processus en cours d'exécution. À l'intérieur de ces sous-répertoires, il existe un certain nombre de fichiers contenant des informations sur le processus correspondant. Les fichiers stat et status maintiennent des statistiques sur le processus, le fichier cmdline contient les arguments de la ligne de commande avec lesquels le processus a été appelé et le fichier exe est un lien symbolique vers le chemin complet du processus. Il existe encore quelques autres fichiers, mais ceux-ci sont les plus intéressants du point de vue de l'écriture de scripts.

Exemple 29.3. Trouver le processus associé à un PID

#!/bin/bash
# pid-identifier.sh
# Donne le chemin complet du processus associé avec ce pid.

NBARGS=1  # Nombre d'arguments que le script attend.
E_MAUVAISARGS=65
E_MAUVAISPID=66
E_PROCESSUS_INEXISTANT=67
E_SANSDROIT=68
PROCFILE=exe

if [ $# -ne $NBARGS ]
then
  echo "Usage : `basename $0` PID" >&2  # Message d'erreur >stderr.
  exit $E_MAUVAISARGS
fi  

nopid=$( ps ax | grep $1 | awk '{ print $1 }' | grep $1 )
# Cherche le pid dans l'affichage de "ps" car il est le champ #1.
# S'assure aussi qu'il s'agit du bon processus, et non pas du processus appelé
# par ce script.
# Le dernier "grep $1" supprime cette possibilité.
#
#    pidno=$( ps ax | awk '{ print $1 }' | grep $1 )
#    fonctionne aussi comme l'indique Teemu Huovila.

if [ -z "$nopid" ] #  Si, après tous ces filtres, le résultat est une chaîne vide,
then               #+ aucun processus en cours ne correspond au pid donné.
  echo "Aucun processus en cours."
  exit $E_PROCESSUS_INEXISTANT
fi  

# Autrement :
#   if ! ps $1 > /dev/null 2>&1
#   then                # Aucun processus ne correspond au pid donné.
#     echo "Ce processus n'existe pas"
#     exit $E_PROCESSUS_INEXISTANT
#    fi

# Pour simplifier tout cet algorithme, utilisez "pidof".


if [ ! -r "/proc/$1/$PROCFILE" ]  # Vérifiez les droits en lecture.
then
  echo "Processus $1 en cours, mais..."
  echo "Ne peut obtenir le droit de lecture sur /proc/$1/$PROCFILE."
  exit $E_SANSDROIT
    # Un utilisateur standard ne peut accéder à certains fichiers de /proc.
fi  

# Les deux derniers tests peuvent être remplacés par :
#    if ! kill -0 $1 > /dev/null 2>&1 # '0' n'est pas un signal mais
                                      # ceci testera s'il est possible
                                      # d'envoyer un signal au processus.
#    then echo "PID n'existe pas ou vous n'êtes pas son propriétaire" >&2
#    exit $E_MAUVAISPID
#    fi



fichier_exe=$( ls -l /proc/$1 | grep "exe" | awk '{ print $11 }' )
# Ou       fichier_exe=$( ls -l /proc/$1/exe | awk '{print $11}' )
#
#  /proc/pid-number/exe est un lien symbolique
#+ vers le chemin complet du processus appelé.

if [ -e "$fichier_exe" ]  # Si /proc/pid-number/exe existe,
then                      # alors le processus correspondant existe.
  echo "Processus #$1 appelé par $fichier_exe"
else
  echo "Processus inexistant"
fi  


#  Ce script élaboré peut *pratiquement* être remplacé par
#  ps ax | grep $1 | awk '{ print $5 }'
#  Néanmoins, cela ne fonctionnera pas...
#+ parce que le cinquième champ de 'ps' est le argv[0] du processus,
#+ et non pas le chemin vers l'exécutable.
#
#  Néanmoins, une des deux méthodes suivantes devrait fonctionner.
#       find /proc/$1/exe -printf '%l\n'
#       lsof -aFn -p $1 -d txt | sed -ne 's/^n//p'

# Commentaires supplémentaires par Stéphane Chazelas.

exit 0

Exemple 29.4. État de la connexion

#!/bin/bash

NOMPROC=pppd           # démon ppp.
NOMFICHIERPROC=status  # Où chercher.
NONCONNECTE=65
INTERVALLE=2           # Mise à jour toutes les deux secondes.

nopid=$( ps ax | grep -v "ps ax" | grep -v grep | grep $NOMPROC | awk '{ print $1 }' )
# Trouver le numéro de processus de 'pppd', le 'démon ppp'.
# Doit filtrer les lignes de processus générées par la recherche elle-même.
#
#  Néanmoins, comme Oleg Philon l'a indiqué,
#+ ceci pourrait être considérablement simplifié en utilisant "pidof".
#  nopid=$( pidof $NOMPROC )
#
#  Morale de l'histoire :
#+ Quand une séquence de commandes devient trop complexe, cherchez un raccourci.


if [ -z "$pidno" ]   # Si pas de pid, alors le processus ne tourne pas.
then
  echo "Non connecté."
  exit $NONCONNECTE
else
  echo "Connecté."; echo
fi

while [ true ]       # Boucle sans fin, le script peut être amélioré ici.
do

  if [ ! -e "/proc/$pidno/$NOMFICHIERPROC" ]
  #  Quand le processus est en cours d'exécution, alors le fichier "status"
  #+ existe.
  then
    echo "Déconnecté."
    exit $NONCONNECTE
  fi

netstat -s | grep "packets received"  #  Obtenir quelques statistiques de
netstat -s | grep "packets delivered" #+ connexion.


  sleep $INTERVALLE
  echo; echo

done

exit 0

# De cette façon, le script ne se termine qu'avec un Control-C.

#    Exercices :
#    ----------
#    Améliorer le script pour qu'il se termine suite à l'appui sur la touche
#    "q".
#    Rendre le script plus facilement utilisable d'autres façons.

[Avertissement]

Avertissement

En général, il est dangereux d'écrire dans les fichiers de /proc car cela peut corrompre le système de fichiers ou provoquer une erreur fatale.



[117] Certaines commandes système, telles que procinfo, free, vmstat, lsdev, et uptime le font aussi.