Partie 0 - Introduction

Support présentation

La programmation système consiste à écrire des programmes qui interagissent directement avec le système d’exploitation/l'OS (Operating System), ou 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.

Le système d’exploitation est le premier logiciel chargé au démarrage de la machine (boot). Il 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. anciens Windows ; Android historiquement mono-utilisateur côté usage grand public, bien qu’il supporte plusieurs profils/espaces depuis Android 4.2/5.0).

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

  • Par gestion des tâches :

    • Mono-tâche : un seul processus peut s’exécuter à un instant donné (ex. anciens OS comme MS-DOS).

    • Multi-tâche : plusieurs processus peuvent tourner simultanément via du temps partagé. 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, pipes, sockets, etc.

Dans ce cours, nous étudierons des systèmes de type Unix, en particulier GNU/Linux, un système :

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

  • multi-tâche préemptif (le noyau peut reprendre la main à tout moment pour gérer un autre processus).

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 au sein de 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 (glibc), outils système, etc. Mais il lui manquait une pièce maîtresse : un noyau fonctionnel.

C’est ce manque que comble le projet Linux, démarré en 1991 par Linus Torvalds, alors étudiant à l’université d’Helsinki. Inspiré de Minix (OS éducatif) et d’Unix (développé à partir de 1969 à Bell Labs par Ken Thompson, Dennis Ritchie et Brian Kernighan), Linus publie initialement le noyau Linux en 1991 sous une licence personnelle, puis le relicencie sous la GPLv2 (comme GNU), en faisant un logiciel libre et open source.

Image décrite dans le caption.

Mail de Linus Torvalds au groupe Minix 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.

C’est aussi dans le cadre du développement de Linux en open source que Linus Torvalds a créé git en 2005 pour remplacer BitKeeper.

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.

Depuis les années 1990, GNU/Linux a évolué pour s’adapter à de nombreux environnements : ordinateurs de bureau, serveurs, smartphones (Android), objets connectés, supercalculateurs…

Il existe aujourd’hui des centaines de distributions Linux, c’est-à-dire des systèmes complets construits à partir du noyau Linux, 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…

  • Serveur : Debian, AlmaLinux, CentOS Stream, Rocky Linux…

  • Systèmes embarqués : Raspberry Pi OS, OpenWRT, Yocto…

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

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

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.

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 appels système standards (comme fork(), exec(), 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 avec une architecture 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, mais 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) reposent sur ses services.

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 :

  • interfaces homme-machine (connexion ssh/http/…, clavier, souris, écran, capteurs, …),

  • le matériel (serveurs, desktop, mobiles, embarqués),

  • le noyau Linux,

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

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) : 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) : 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 userland / kernel space

Source du tableau.

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 interface officielle entre user space et kernel space (ex. read, write, openat, fork, execve, mmap, ioctl, …).

L’appel provoque un trap (changement de privilège) ; le noyau traite la requête puis renvoie un code de retour et éventuellement errno.

Changer de mode implique sauvegarde/restauration de contexte et effets sur caches/TLB qui peuvent être coûteux en ressources. Il faut donc mieux éviter de multiplier les petits syscalls en regroupant les opérations (readv/writev, sendfile, mmap, …).

Libc

La libc (la bibliothèque standard du système, comme glibc) encapsule souvent les syscalls (ex. open appelle aujourd’hui openat sous-jacent) 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…) 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 supporter 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 (exec)

    • Signaux : communication inter-processus asynchrone

    • Gestion des threads, context switching, états des processus (running, sleeping, zombie…)

  • 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 croit avoir sa propre mémoire

    • 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 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, iptables, nftables)

  • 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, …

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

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

    • Interfaces audio (ALSA, noyau ; PulseAudio ou PipeWire, user space) 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…), il doit passer par les appels système. Ceux-ci sont généralement encapsulés par la bibliothèque standard C (libc), ex. open, read, write, fork, exec.

Exemple simple : afficher le contenu d’un fichier.

  1. L’utilisateur tape dans un terminal :

$ cat fichier.txt
  1. Le shell interprète, crée un nouveau processus (fork), puis remplace son image mémoire par /bin/cat (via exec, voir partie sur les processus).

  2. Le programme cat utilise la libc pour appeler les syscalls appropriés : openat (ouvrir), read (lire), write (écrire), close (fermer).

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

  4. 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.

  5. 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.

  6. Finalement, les données sont affichées à l’écran 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 :

$ # 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()                               = 675349
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()                               = 675349
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 +++