Partie 0 - Introduction

Support présentation

La programmation système consiste à écrire des programmes qui interagissent directement avec le système d’exploitation (ou OS, Operating System), ou qui en font partie. Contrairement aux applications classiques, ces programmes manipulent les ressources matérielles et logicielles de bas niveau : mémoire, processus, fichiers, réseau, etc.

Dans ce cours, nous aborderons en particulier les systèmes Unix/Linux.

Qu’est-ce qu’un système d’exploitation ?

Un système d’exploitation (OS) est un ensemble de logiciels qui contrôlent l’utilisation des ressources matérielles d’un ordinateur, tout en fournissant une interface standard aux logiciels applicatifs.

Que vous soyez sous GNU/Linux, Windows, macOS, Android ou autre, l’OS est responsable de :

  • la gestion du processeur (CPU) et des processus ;

  • la gestion de la mémoire (allocation, protection, partage) ;

  • l’accès aux périphériques (clavier, souris, disque, etc.) ;

  • la gestion du système de fichiers (stockage, droits d’accès) ;

  • la gestion du réseau ;

  • la communication entre logiciels et matériel.

Au démarrage de la machine (boot), le micrologiciel (BIOS/UEFI) lance un chargeur d’amorçage (ex. GRUB), qui charge le noyau du système d’exploitation en mémoire. Le noyau démarre ensuite les processus nécessaires au fonctionnement du système : gestionnaire de sessions, environnement graphique, etc.

Les OS sont présents sur tous les types d’ordinateurs : ordinateurs personnels, serveurs, téléphones, supercalculateurs, systèmes embarqués, wearables (vêtements/accessoires connectés), etc.

Types de systèmes d’exploitation

Les OS peuvent être classés selon deux critères principaux :

  • Par nombre d’utilisateurs :

    • Mono-utilisateur : un seul utilisateur à la fois (ex. MS-DOS, Windows 95/98) ;

    • Multi-utilisateur : plusieurs utilisateurs peuvent se connecter en même temps (ex. Linux, Windows récents, BSD, macOS).

  • Par gestion des tâches :

    • Monotâche : un programme doit se terminer avant qu’un autre puisse être lancé (ex. anciens OS comme MS-DOS) ;

    • Multitâche : plusieurs processus peuvent s’exécuter en apparence simultanément (ou réellement, sur plusieurs cœurs) grâce au temps partagé : le processeur alterne très rapidement entre les processus, qui semblent ainsi s’exécuter en même temps. L’OS doit alors :

      • partager équitablement les ressources ;

      • protéger chaque processus de l’accès mémoire des autres ;

      • permettre à des processus de communiquer via des zones mémoire partagées, des tubes (pipes), des sockets, etc. (vus dans les parties sur les processus et les sockets).

GNU/Linux, le système étudié dans ce cours, est un système de type Unix :

  • multi-utilisateur (peu abordé dans ce cours) ;

  • multitâche préemptif (le noyau, cœur de l’OS présenté plus bas, peut reprendre la main à tout moment pour gérer un autre processus).

Unix

Unix est une famille de systèmes d’exploitation apparue à la fin des années 1960 qui a profondément influencé la conception des systèmes modernes, tant par ses choix techniques que par sa philosophie.

Unix est développé à partir de 1969 au sein des Bell Labs (AT&T), principalement par Ken Thompson et Dennis Ritchie, rejoints ensuite par Brian Kernighan.

_images/Ken_Thompson_2019.jpg

Ken Thompson

_images/Dennis_Ritchie_2011.jpg

Dennis Ritchie

_images/kernighan-brian-2018-oct.jpg

Brian Kernighan

Dennis Ritchie y développe également le langage C, qui permettra à Unix d’être largement portable, ce qui était exceptionnel à l’époque.

Unix repose sur plusieurs principes clés, souvent regroupés sous le nom de philosophie Unix, comme « Écrivez des programmes qui font une seule chose mais qui le font bien » ou « Concevez pour la simplicité ; n’ajoutez de la complexité que par obligation ».

Ces choix ont permis à Unix d’être à la fois flexible, puissant et durable.

Même si Unix est aujourd’hui moins répandu sous sa forme originale, son influence est majeure, que ce soit sur les systèmes BSD, Linux ou macOS.

Unix constitue ainsi la base conceptuelle sur laquelle s’appuient la majorité des systèmes d’exploitation modernes, en particulier GNU/Linux.

Historique de GNU/Linux

Le système GNU/Linux est l’union de deux projets complémentaires : le projet GNU et le noyau Linux.

Le projet GNU (GNU’s Not Unix) a été lancé en 1983 par Richard Stallman, puis soutenu à partir de 1985 par la Free Software Foundation (FSF), avec pour objectif de créer un système d’exploitation libre et compatible Unix. GNU fournissait déjà de nombreux composants essentiels : éditeurs, shell, compilateur (GCC), bibliothèque standard du C (glibc, voir la section Libc plus bas), outils système, etc. Mais il lui manquait une pièce maîtresse : un noyau fonctionnel.

_images/The_GNU_logo.png

Logo GNU

_images/Richard_Stallman_at_LibrePlanet_2019.jpg

Richard Stallman

C’est ce manque que comble le projet Linux, démarré en 1991 par Linus Torvalds, alors étudiant à l’université d’Helsinki. Il publie d’abord ce noyau, inspiré de Minix (OS éducatif) et d’Unix, sous une licence personnelle, puis le place sous la GPLv2 (comme GNU), ce qui en fait un logiciel libre et open source.

Capture du message de Linus Torvalds annonçant son projet de système d'exploitation.

Message de Linus Torvalds sur le groupe Usenet comp.os.minix (25 août 1991) présentant son OS comme « un hobby qui ne sera jamais aussi gros et professionnel que GNU ».

Rapidement, la communauté s’empare du projet, améliore le noyau, l’intègre aux outils GNU et crée un système libre complet : GNU/Linux.

En 2005, pour remplacer BitKeeper, Linus Torvalds crée aussi Git afin de gérer le développement du noyau.

Note

Techniquement, Linux désigne uniquement le noyau. L’appellation GNU/Linux souligne que la majorité des outils système provient du projet GNU. Toutefois, dans l’usage courant, le terme Linux est souvent utilisé pour désigner l’ensemble du système.

_images/Tux.svg.png

Tux, mascotte Linux

_images/Linus_Torvalds.jpeg

Linus Torvalds

Depuis les années 1990, Linux (le noyau) s’est adapté à de nombreux environnements : ordinateurs de bureau, serveurs, smartphones (Android), objets connectés, supercalculateurs, etc.

Il existe aujourd’hui des centaines de distributions Linux, c’est-à-dire des systèmes complets construits à partir du noyau Linux, généralement des outils GNU, et d’un ensemble de logiciels préconfigurés selon les besoins :

  • Bureau : Ubuntu, Linux Mint, Fedora, Pop!_OS, Manjaro, Elementary OS, etc.

  • Serveur : Debian, AlmaLinux, CentOS Stream, Rocky Linux, etc.

  • Systèmes embarqués : Raspberry Pi OS, OpenWRT, Poky (Yocto), etc.

  • Sécurité / Pentest : Kali Linux, BlackArch, Parrot OS, etc.

  • Minimalistes ou spécialisés : Arch Linux, Alpine Linux, NixOS, Tails, etc.

Partie de la liste des différentes distributions Linux.

Source de l’image.

Chaque distribution a ses spécificités (gestionnaire de paquets, outils d’administration, cycle de mise à jour), mais toutes reposent sur la même base : le noyau Linux et une interface conforme aux standards POSIX (voir la section suivante).

Interface POSIX

Pour faciliter le développement d’applications portables entre différents systèmes Unix, une norme appelée POSIX (Portable Operating System Interface) a été définie par l'IEEE (Institute of Electrical and Electronics Engineers).

POSIX spécifie un ensemble d’interfaces standardisées que les systèmes d’exploitation de type Unix doivent implémenter. Ces interfaces couvrent :

  • les fonctions d’accès aux services du système, souvent des appels système (comme fork, execve, open, read, write, etc.) ;

  • les API de gestion des fichiers, des processus, des signaux, des permissions, etc. ;

  • certains utilitaires en ligne de commande (ls, cp, grep, etc.).

En suivant POSIX, un programme écrit pour un OS de type Unix (comme Linux) peut souvent être compilé et exécuté sur un autre (macOS, BSD, Solaris), avec peu ou pas de modifications.

Linux/glibc implémente largement les interfaces POSIX, bien que le noyau Linux ne soit pas officiellement certifié POSIX. En pratique, la compatibilité est excellente pour la programmation système portable.

Le noyau Linux

Le noyau Linux (Linux Kernel) est le cœur du système d’exploitation. Il est responsable de la gestion directe des ressources matérielles et des fonctions critiques du système. Tous les autres composants logiciels (services, interfaces graphiques, applications) s’appuient sur lui.

Architecture

Voici un schéma général de l’architecture de Linux :

Schéma d'ensemble : matériels, noyau Linux et logiciels.

Source de l’image.

De gauche à droite :

  • les interfaces homme-machine (connexion SSH/HTTP, clavier, souris, écran, capteurs, etc.) ;

  • le matériel (serveurs, ordinateurs de bureau, mobiles, systèmes embarqués) ;

  • le noyau Linux ;

  • puis les logiciels (serveur web, environnement de bureau, outils, etc.).

Espace noyau et espace utilisateur

L'espace noyau (kernel space) et l'espace utilisateur (user space) sont deux domaines d’exécution imposés par le processeur pour garantir l’isolation et la sécurité.

  • Espace noyau (ring 0 sur architecture x86) : le noyau Linux et ses pilotes. Accès direct au matériel, à la mémoire physique et aux instructions privilégiées.

  • Espace utilisateur (ring 3 sur architecture x86) : les applications et la plupart des services. Pas d’accès direct au matériel ; toute opération sensible doit demander un service au noyau via un appel système.

Séparation espace utilisateur (userland/user mode) / espace noyau (kernel space)

Source du tableau.

Le tableau se lit de haut en bas : en mode utilisateur (User mode), les applications appellent les fonctions de la bibliothèque standard du C (C standard library, ex. glibc) ; celles-ci passent en mode noyau (Kernel mode) par l’interface des appels système (System Call Interface), puis le noyau pilote le matériel via ses sous-systèmes et ses pilotes.

Pourquoi cette séparation ?

  • Isolation & sécurité : limiter l’impact d’un bug ou d’un code malveillant.

  • Stabilité : le crash d’une application n’affecte pas le noyau.

  • Multiplexage : partage équitable des ressources (CPU, mémoire, E/S).

Les appels système (syscalls) sont l’interface officielle entre l’espace utilisateur et l’espace noyau (ex. read, write, openat, fork, execve, mmap, ioctl, etc.).

L’appel provoque un trap (changement de privilège) ; le noyau traite la requête puis renvoie une valeur (négative en cas d’erreur). La fonction de la libc qui enveloppe l’appel renvoie alors -1 et place le code d’erreur dans errno (variable globale qui contient le code de la dernière erreur).

Chaque changement de mode impose de sauvegarder puis de restaurer le contexte et perturbe les caches (et la TLB), ce qui coûte du temps. Il vaut donc mieux éviter de multiplier les petits appels système, en regroupant les opérations (readv/writev, sendfile, mmap, etc.).

Libc

La libc (la bibliothèque standard du C, comme glibc) encapsule souvent les appels système (ex. la fonction open utilise aujourd’hui l’appel système openat) et fournit de nombreuses fonctions purement utilisateur (ex. printf). L’API, largement alignée sur POSIX, est stable depuis des décennies. Elle peut être utilisée de manière fiable, indépendamment de la version du langage C (à partir de l’ANSI C, voir normes C).

Carte du noyau (Kernel map)

Le noyau Linux est un noyau monolithique : toutes les fonctions principales (réseau, mémoire, systèmes de fichiers, etc.) s’exécutent dans l’espace noyau. Cela le rend performant mais plus complexe à maintenir. D’autres systèmes (comme Minix ou QNX) utilisent un micro-noyau, où seuls les composants essentiels sont dans le noyau, le reste étant en espace utilisateur.

Le noyau Linux est modulaire : il peut charger dynamiquement des modules pour prendre en charge de nouveaux matériels ou systèmes de fichiers, sans nécessiter de redémarrage. Ces modules s’intègrent dans l’un des sous-systèmes principaux décrits ci-dessous :

Carte des composants du noyau Linux (processus, mémoire, stockage, réseau, interfaces, etc.).

Source de l’image.

  • System - système général, regroupe des fonctions de base permettant le bon fonctionnement du noyau :

    • Interface système et gestion du démarrage

    • Gestion du matériel générique

    • Accès aux périphériques via des pilotes de bus (USB, PCI, etc.)

    • Modèle de périphérique unifié (device model) utilisé pour l’abstraction matérielle

  • Processing - gestion des processus, responsable du multiplexage du processeur entre plusieurs processus :

    • Ordonnancement (scheduler) : décide quel processus s’exécute et quand

    • Création de processus (fork, clone) et exécution de nouveaux programmes (execve)

    • Signaux : communication inter-processus asynchrone

    • Gestion des threads, changement de contexte (context switching), états des processus (running, sleeping, zombie, etc.)

  • Memory - gestion de la mémoire, gère l’espace mémoire alloué à chaque processus et les mécanismes de protection et partage :

    • Mémoire virtuelle : chaque processus dispose de son propre espace d’adressage virtuel

    • Pagination (paging), segmentation, swapping

    • Allocation dynamique (kmalloc, vmalloc)

    • mmap, cache, accès direct à la mémoire (DMA), zones partagées

  • Storage - stockage, pour l’accès et la gestion des données persistantes :

    • Systèmes de fichiers : ext4, Btrfs, XFS, FAT, NTFS, etc.

    • Abstraction VFS (Virtual File System) pour manipuler différents types de systèmes de fichiers via une interface uniforme

    • Gestion des blocs de disque, partitions, buffers et caches disque

    • Contrôle d’accès aux fichiers et aux périphériques de type bloc (disques, SSD)

  • Networking - réseau, gestion de la pile réseau du système et de la communication entre machines :

    • Pile TCP/IP, IPv4, IPv6

    • Sockets réseau (interface utilisée par les applications)

    • Interfaces réseau physiques (Ethernet, Wi-Fi, etc.) et virtuelles (loopback, bridge, VLAN)

    • Pare-feux et filtrage (Netfilter, nf_tables ; configurés depuis l’espace utilisateur avec iptables ou nft)

  • Human Interface - interface homme-machine, gestion des interactions avec l’utilisateur via des périphériques ou interfaces graphiques :

    • Entrées/sorties classiques : terminaux (TTY), consoles virtuelles, clavier, souris, etc.

    • Sous-systèmes d’entrée/sortie : evdev, input, framebuffer

    • Prise en charge indirecte des interfaces graphiques via des serveurs (X11, Wayland, etc.)

    • Interfaces audio (ALSA, noyau ; PulseAudio ou PipeWire, espace utilisateur) et vidéo (DRM/KMS)

Parcours d’un appel système (exemple)

Lorsqu’un programme utilisateur souhaite interagir avec le matériel ou une ressource système (fichier, mémoire, périphérique, etc.), il doit passer par les appels système. Ceux-ci sont généralement encapsulés par la bibliothèque standard du C (libc), ex. open, read, write, fork, execve.

Exemple simple : afficher le contenu d’un fichier.

  1. L’utilisateur tape dans un terminal :

    $ cat fichier.txt
    
  2. Le shell (l’interpréteur de commandes, ex. bash) interprète la commande et crée un processus fils (fork). Ce fils remplace ensuite son image mémoire par le programme /usr/bin/cat (execve, voir partie sur les processus).

  3. Le programme cat utilise la libc pour appeler les appels système appropriés : openat (ouvrir), read (lire), write (écrire), close (fermer). Pour ouvrir le fichier :

  4. La fonction open de la libc prépare les arguments de l’appel système openat, puis effectue une instruction spéciale du processeur pour passer en mode noyau.

  5. Le noyau reçoit la requête, vérifie les droits d’accès, localise le fichier sur disque, alloue des structures internes, et retourne un descripteur de fichier (un entier) au programme.

  6. Le programme peut ensuite appeler read(fd, buffer, ...), qui suit le même chemin : libc → syscall → noyau → lecture disque → données copiées en mémoire utilisateur.

  7. Finalement, les données sont écrites sur la sortie standard (descripteur 1, en général le terminal) via write(1, buffer, ...).

Tout au long de ce processus :

  • Le changement de mode (utilisateur → noyau → utilisateur) est sécurisé et contrôlé.

  • Le noyau protège l’intégrité du système (droits d’accès, mémoire, périphériques).

  • La libc fournit une couche compatible POSIX, rendant les programmes portables entre systèmes Unix-like.

La commande strace (man 1 strace) permet de voir tous les appels système effectués par un programme. Le chiffre dans man 1 strace indique la section du manuel : 1 pour les commandes, 2 pour les appels système, 3 pour les fonctions de bibliothèque. strace n’est pas toujours installé (sudo apt install strace sous Debian/Ubuntu) ; pour refaire l’exemple, placez-vous dans un dossier où vous avez le droit d’écrire.

Quelques points pour lire les traces ci-dessous :

  • le début de chaque trace (execve, brk, mmap, mprotect, arch_prctl, etc., jusqu’à l’ouverture de locale-archive) correspond au chargement dynamique de la libc et peut être ignoré ; les lignes utiles sont surlignées ;

  • pour echo "coucou" > mon_fichier.txt, c’est le shell qui ouvre mon_fichier.txt pour la redirection, avant de lancer le programme : echo reçoit un descripteur 1 déjà ouvert sur le fichier (newfstatat(1, ...S_IFREG...)) et on ne voit aucun openat de ce fichier. strace exécute ici le programme /usr/bin/echo, et non la commande interne echo du shell.

$ # création d'un fichier "mon_fichier.txt" contenant "coucou"
$ strace echo "coucou" > mon_fichier.txt
execve("/usr/bin/echo", ["echo", "coucou"], 0x7fff5d65ac68 /* 51 vars */) = 0
brk(NULL)                               = 0x64905b15a000
arch_prctl(0x3001 /* ARCH_??? */, 0x7fffb7736ec0) = -1 EINVAL (Argument invalide)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x78b85ed32000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (Aucun fichier ou dossier de ce nom)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=84980, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 84980, PROT_READ, MAP_PRIVATE, 3, 0) = 0x78b85ed1d000
close(3)                                = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\237\2\0\0\0\0\0"..., 832) = 832
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
pread64(3, "\4\0\0\0 \0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0"..., 48, 848) = 48
pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\325\31p\226\367\t\200\30)\261\30\257\33|\366c"..., 68, 896) = 68
newfstatat(3, "", {st_mode=S_IFREG|0755, st_size=2220400, ...}, AT_EMPTY_PATH) = 0
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
mmap(NULL, 2264656, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x78b85ea00000
mprotect(0x78b85ea28000, 2023424, PROT_NONE) = 0
mmap(0x78b85ea28000, 1658880, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x28000) = 0x78b85ea28000
mmap(0x78b85ebbd000, 360448, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1bd000) = 0x78b85ebbd000
mmap(0x78b85ec16000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x215000) = 0x78b85ec16000
mmap(0x78b85ec1c000, 52816, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x78b85ec1c000
close(3)                                = 0
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x78b85ed1a000
arch_prctl(ARCH_SET_FS, 0x78b85ed1a740) = 0
set_tid_address(0x78b85ed1aa10)         = 143268
set_robust_list(0x78b85ed1aa20, 24)     = 0
rseq(0x78b85ed1b0e0, 0x20, 0, 0x53053053) = 0
mprotect(0x78b85ec16000, 16384, PROT_READ) = 0
mprotect(0x649046522000, 4096, PROT_READ) = 0
mprotect(0x78b85ed6c000, 8192, PROT_READ) = 0
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
munmap(0x78b85ed1d000, 84980)           = 0
getrandom("\x26\xf7\x43\x5b\x5e\xcf\xc5\x85", 8, GRND_NONBLOCK) = 8
brk(NULL)                               = 0x64905b15a000
brk(0x64905b17b000)                     = 0x64905b17b000
openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=8321104, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 8321104, PROT_READ, MAP_PRIVATE, 3, 0) = 0x78b85e200000
close(3)                                = 0
newfstatat(1, "", {st_mode=S_IFREG|0644, st_size=0, ...}, AT_EMPTY_PATH) = 0
write(1, "coucou\n", 7)                 = 7
close(1)                                = 0
close(2)                                = 0
exit_group(0)                           = ?
+++ exited with 0 +++

$ # affichage du contenu de "mon_fichier.txt"
$ strace cat mon_fichier.txt
execve("/usr/bin/cat", ["cat", "mon_fichier.txt"], 0x7ffcc6c196a8 /* 51 vars */) = 0
brk(NULL)                               = 0x5d897b08d000
arch_prctl(0x3001 /* ARCH_??? */, 0x7ffe72c4b4a0) = -1 EINVAL (Argument invalide)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x77925d787000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (Aucun fichier ou dossier de ce nom)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=84980, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 84980, PROT_READ, MAP_PRIVATE, 3, 0) = 0x77925d772000
close(3)                                = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\237\2\0\0\0\0\0"..., 832) = 832
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
pread64(3, "\4\0\0\0 \0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0"..., 48, 848) = 48
pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\325\31p\226\367\t\200\30)\261\30\257\33|\366c"..., 68, 896) = 68
newfstatat(3, "", {st_mode=S_IFREG|0755, st_size=2220400, ...}, AT_EMPTY_PATH) = 0
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
mmap(NULL, 2264656, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x77925d400000
mprotect(0x77925d428000, 2023424, PROT_NONE) = 0
mmap(0x77925d428000, 1658880, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x28000) = 0x77925d428000
mmap(0x77925d5bd000, 360448, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1bd000) = 0x77925d5bd000
mmap(0x77925d616000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x215000) = 0x77925d616000
mmap(0x77925d61c000, 52816, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x77925d61c000
close(3)                                = 0
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x77925d76f000
arch_prctl(ARCH_SET_FS, 0x77925d76f740) = 0
set_tid_address(0x77925d76fa10)         = 143742
set_robust_list(0x77925d76fa20, 24)     = 0
rseq(0x77925d7700e0, 0x20, 0, 0x53053053) = 0
mprotect(0x77925d616000, 16384, PROT_READ) = 0
mprotect(0x5d8954952000, 4096, PROT_READ) = 0
mprotect(0x77925d7c1000, 8192, PROT_READ) = 0
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
munmap(0x77925d772000, 84980)           = 0
getrandom("\x93\x5c\x64\x89\x5c\x16\xfd\x30", 8, GRND_NONBLOCK) = 8
brk(NULL)                               = 0x5d897b08d000
brk(0x5d897b0ae000)                     = 0x5d897b0ae000
openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=8321104, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 8321104, PROT_READ, MAP_PRIVATE, 3, 0) = 0x77925cc00000
close(3)                                = 0
newfstatat(1, "", {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0x5), ...}, AT_EMPTY_PATH) = 0
openat(AT_FDCWD, "mon_fichier.txt", O_RDONLY) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=7, ...}, AT_EMPTY_PATH) = 0
fadvise64(3, 0, 0, POSIX_FADV_SEQUENTIAL) = 0
mmap(NULL, 139264, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x77925d74d000
read(3, "coucou\n", 131072)             = 7
write(1, "coucou\n", 7coucou
)                 = 7
read(3, "", 131072)                     = 0
munmap(0x77925d74d000, 139264)          = 0
close(3)                                = 0
close(1)                                = 0
close(2)                                = 0
exit_group(0)                           = ?
+++ exited with 0 +++


$ # suppression de "mon_fichier.txt"
$ strace rm mon_fichier.txt
execve("/usr/bin/rm", ["rm", "mon_fichier.txt"], 0x7ffdf281ae78 /* 51 vars */) = 0
brk(NULL)                               = 0x5bf7537ce000
arch_prctl(0x3001 /* ARCH_??? */, 0x7ffdb2ea77c0) = -1 EINVAL (Argument invalide)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f15cad80000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (Aucun fichier ou dossier de ce nom)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=84980, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 84980, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f15cad6b000
close(3)                                = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\237\2\0\0\0\0\0"..., 832) = 832
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
pread64(3, "\4\0\0\0 \0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0"..., 48, 848) = 48
pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\325\31p\226\367\t\200\30)\261\30\257\33|\366c"..., 68, 896) = 68
newfstatat(3, "", {st_mode=S_IFREG|0755, st_size=2220400, ...}, AT_EMPTY_PATH) = 0
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
mmap(NULL, 2264656, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f15caa00000
mprotect(0x7f15caa28000, 2023424, PROT_NONE) = 0
mmap(0x7f15caa28000, 1658880, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x28000) = 0x7f15caa28000
mmap(0x7f15cabbd000, 360448, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1bd000) = 0x7f15cabbd000
mmap(0x7f15cac16000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x215000) = 0x7f15cac16000
mmap(0x7f15cac1c000, 52816, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f15cac1c000
close(3)                                = 0
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f15cad68000
arch_prctl(ARCH_SET_FS, 0x7f15cad68740) = 0
set_tid_address(0x7f15cad68a10)         = 144131
set_robust_list(0x7f15cad68a20, 24)     = 0
rseq(0x7f15cad690e0, 0x20, 0, 0x53053053) = 0
mprotect(0x7f15cac16000, 16384, PROT_READ) = 0
mprotect(0x5bf722fdd000, 4096, PROT_READ) = 0
mprotect(0x7f15cadba000, 8192, PROT_READ) = 0
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
munmap(0x7f15cad6b000, 84980)           = 0
getrandom("\x7b\x26\xf4\x6f\xb8\x86\xf8\x19", 8, GRND_NONBLOCK) = 8
brk(NULL)                               = 0x5bf7537ce000
brk(0x5bf7537ef000)                     = 0x5bf7537ef000
openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=8321104, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 8321104, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f15ca200000
close(3)                                = 0
ioctl(0, TCGETS, {B38400 opost isig icanon echo ...}) = 0
newfstatat(AT_FDCWD, "mon_fichier.txt", {st_mode=S_IFREG|0644, st_size=7, ...}, AT_SYMLINK_NOFOLLOW) = 0
geteuid()                               = 1000
newfstatat(AT_FDCWD, "mon_fichier.txt", {st_mode=S_IFREG|0644, st_size=7, ...}, AT_SYMLINK_NOFOLLOW) = 0
faccessat2(AT_FDCWD, "mon_fichier.txt", W_OK, AT_EACCESS) = 0
unlinkat(AT_FDCWD, "mon_fichier.txt", 0) = 0
lseek(0, 0, SEEK_CUR)                   = -1 ESPIPE (Repérage non permis)
close(0)                                = 0
close(1)                                = 0
close(2)                                = 0
exit_group(0)                           = ?
+++ exited with 0 +++

$ # tentative de suppression de "mon_fichier.txt" qui n'existe plus
$ strace rm mon_fichier.txt
execve("/usr/bin/rm", ["rm", "mon_fichier.txt"], 0x7fff34b05ae8 /* 51 vars */) = 0
brk(NULL)                               = 0x5f7afddc7000
arch_prctl(0x3001 /* ARCH_??? */, 0x7ffe10685440) = -1 EINVAL (Argument invalide)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7e287bf8d000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (Aucun fichier ou dossier de ce nom)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=84980, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 84980, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7e287bf78000
close(3)                                = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\237\2\0\0\0\0\0"..., 832) = 832
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
pread64(3, "\4\0\0\0 \0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0"..., 48, 848) = 48
pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\325\31p\226\367\t\200\30)\261\30\257\33|\366c"..., 68, 896) = 68
newfstatat(3, "", {st_mode=S_IFREG|0755, st_size=2220400, ...}, AT_EMPTY_PATH) = 0
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
mmap(NULL, 2264656, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7e287bc00000
mprotect(0x7e287bc28000, 2023424, PROT_NONE) = 0
mmap(0x7e287bc28000, 1658880, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x28000) = 0x7e287bc28000
mmap(0x7e287bdbd000, 360448, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1bd000) = 0x7e287bdbd000
mmap(0x7e287be16000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x215000) = 0x7e287be16000
mmap(0x7e287be1c000, 52816, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7e287be1c000
close(3)                                = 0
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7e287bf75000
arch_prctl(ARCH_SET_FS, 0x7e287bf75740) = 0
set_tid_address(0x7e287bf75a10)         = 144475
set_robust_list(0x7e287bf75a20, 24)     = 0
rseq(0x7e287bf760e0, 0x20, 0, 0x53053053) = 0
mprotect(0x7e287be16000, 16384, PROT_READ) = 0
mprotect(0x5f7aebd67000, 4096, PROT_READ) = 0
mprotect(0x7e287bfc7000, 8192, PROT_READ) = 0
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
munmap(0x7e287bf78000, 84980)           = 0
getrandom("\x2c\x10\x0b\x61\x3c\xf8\x49\x2f", 8, GRND_NONBLOCK) = 8
brk(NULL)                               = 0x5f7afddc7000
brk(0x5f7afdde8000)                     = 0x5f7afdde8000
openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=8321104, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 8321104, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7e287b400000
close(3)                                = 0
ioctl(0, TCGETS, {B38400 opost isig icanon echo ...}) = 0
newfstatat(AT_FDCWD, "mon_fichier.txt", 0x5f7afddc9778, AT_SYMLINK_NOFOLLOW) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
geteuid()                               = 1000
newfstatat(AT_FDCWD, "mon_fichier.txt", 0x7ffe106852a0, AT_SYMLINK_NOFOLLOW) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
openat(AT_FDCWD, "/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=2996, ...}, AT_EMPTY_PATH) = 0
read(3, "# Locale name alias data base.\n#"..., 4096) = 2996
read(3, "", 4096)                       = 0
close(3)                                = 0
openat(AT_FDCWD, "/usr/share/locale/fr_FR.UTF-8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
openat(AT_FDCWD, "/usr/share/locale/fr_FR.utf8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
openat(AT_FDCWD, "/usr/share/locale/fr_FR/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
openat(AT_FDCWD, "/usr/share/locale/fr.UTF-8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
openat(AT_FDCWD, "/usr/share/locale/fr.utf8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
openat(AT_FDCWD, "/usr/share/locale/fr/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
openat(AT_FDCWD, "/usr/share/locale-langpack/fr_FR.UTF-8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
openat(AT_FDCWD, "/usr/share/locale-langpack/fr_FR.utf8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
openat(AT_FDCWD, "/usr/share/locale-langpack/fr_FR/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
openat(AT_FDCWD, "/usr/share/locale-langpack/fr.UTF-8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
openat(AT_FDCWD, "/usr/share/locale-langpack/fr.utf8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
openat(AT_FDCWD, "/usr/share/locale-langpack/fr/LC_MESSAGES/coreutils.mo", O_RDONLY) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=387786, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 387786, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7e287bf16000
close(3)                                = 0
openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/gconv/gconv-modules.cache", O_RDONLY) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=27002, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 27002, PROT_READ, MAP_SHARED, 3, 0) = 0x7e287bf86000
close(3)                                = 0
futex(0x7e287be1ba6c, FUTEX_WAKE_PRIVATE, 2147483647) = 0
write(2, "rm: ", 4rm: )                     = 4
write(2, "impossible de supprimer 'mon_fic"..., 41impossible de supprimer 'mon_fichier.txt') = 41
openat(AT_FDCWD, "/usr/share/locale/fr_FR.UTF-8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
openat(AT_FDCWD, "/usr/share/locale/fr_FR.utf8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
openat(AT_FDCWD, "/usr/share/locale/fr_FR/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
openat(AT_FDCWD, "/usr/share/locale/fr.UTF-8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
openat(AT_FDCWD, "/usr/share/locale/fr.utf8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
openat(AT_FDCWD, "/usr/share/locale/fr/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
openat(AT_FDCWD, "/usr/share/locale-langpack/fr_FR.UTF-8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
openat(AT_FDCWD, "/usr/share/locale-langpack/fr_FR.utf8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
openat(AT_FDCWD, "/usr/share/locale-langpack/fr_FR/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
openat(AT_FDCWD, "/usr/share/locale-langpack/fr.UTF-8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
openat(AT_FDCWD, "/usr/share/locale-langpack/fr.utf8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (Aucun fichier ou dossier de ce nom)
openat(AT_FDCWD, "/usr/share/locale-langpack/fr/LC_MESSAGES/libc.mo", O_RDONLY) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=150600, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 150600, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7e287bef1000
close(3)                                = 0
write(2, ": Aucun fichier ou dossier de ce"..., 36: Aucun fichier ou dossier de ce nom) = 36
write(2, "\n", 1
)                       = 1
lseek(0, 0, SEEK_CUR)                   = -1 ESPIPE (Repérage non permis)
close(0)                                = 0
close(1)                                = 0
close(2)                                = 0
exit_group(1)                           = ?
+++ exited with 1 +++