#include <sys/syscall.h> /* Définition des constantes SYS_* */ #include <unistd.h> int syscall(SYS_pivot_root, const char *new_root, const char *put_old);
Note: la glibc ne fournit pas d'enveloppe pour pivot_root(), nécessitant l'utilisation de syscall(2).
pivot_root() change le répertoire racine et le répertoire de travail de chaque processus ou de chaque thread du même espace de noms de montage en new_root s'ils pointent vers l'ancien répertoire de montage (voir aussi les NOTES). D'un autre côté, pivot_root() ne modifie pas le répertoire de travail de l'appelant (sauf s'il est sur l'ancien répertoire racine), ainsi, il doit être suivi d'un appel chdir("/").
Les restrictions suivantes s'appliquent :
pivot_root() permet à un appelant de passer à un nouveau système de fichiers racine tout en mettant l'ancien montage racine dans new_root, d'où il peut être démonté (le fait de déplacer tous les processus ayant un répertoire racine ou actuel dans le répertoire racine vers une nouvelle racine libère l'ancienne racine des utilisateurs, permettant de démonter plus facilement l'ancien montage racine).
L'utilisation typique de pivot_root() est durant le démarrage du système, lorsque le système monte un système de fichiers temporaire (par exemple un initrd(4)) puis monte le véritable système de fichiers et le transforme éventuellement en racine pour tous les processus et threads concernés. Une utilisation moderne consiste à définir un système de fichiers racine pendant la création d'un conteneur.
Le fait que pivot_root() modifie les répertoires racine et de travail du processus comme indiqué dans la DESCRIPTION est nécessaire afin d'empêcher les threads du noyau d'occuper l'ancien montage racine avec leurs répertoires racine et de travail, même s'ils n'accèdent jamais au système de fichiers en aucune manière.
Le rootfs (initial ramfs) ne peut pas être pivot_root()é. La méthode recommandée pour modifier le système de fichiers racine dans ce cas consiste à tout effacer sur le rootfs, monter par-dessus la nouvelle racine, rattacher stdin/stdout/stderr au nouveau /dev/console et exécuter le nouvel init(1). Il existe des programmes d'aide pour ce processus ; voir switch_root(8).
chdir(new_root); pivot_root(".", "."); umount2(".", MNT_DETACH);
Cette séquence réussit parce que l'appel pivot_root() place le point de montage racine au sommet du nouveau point de montage racine sur /. Alors, le répertoire racine et celui de travail du processus appelant se rapportent au nouveau point de montage racine (new_root). Lors de l'appel umount() suivant, la résolution de I"." commence par new_root puis monte la liste des points de montage empilés dans /, d'où il résulte que l'ancien point de montage est démonté.
pivot_root() peut changer ou non les répertoires racine et de travail en cours de tous les processus et threads qui utilisaient l'ancien répertoire racine. L'appelant de pivot_root() doit s'assurer que les processus ayant pour racine ou répertoire de travail l'ancien répertoire se comportent correctement. Le meilleur moyen est de modifier leur répertoire de travail et répertoire racine pour new_root avant d'invoquer pivot_root().
Ce texte, écrit avant même la finalisation de l'implémentation de l'appel système dans le noyau, visait sans doute à avertir les utilisateurs à ce moment là que l'implémentation pourrait changer avant la publication définitive. Toutefois, le comportement indiqué dans DESCRIPTION est resté valable depuis la première implémentation de cet appel système et il ne changera pas maintenant.
Nous montrons le programme en créant un répertoire qui servira de nouveau système de fichiers racine et en mettant une copie de l'exécutable busybox(1) (liée statiquement) dans ce répertoire.
$ mkdir /tmp/rootfs $ ls -id /tmp/rootfs # Numéro d’inœud dans le nouveau répertoire racine 319459 /tmp/rootfs $ cp $(which busybox) /tmp/rootfs $ PS1='bbsh$ ' sudo ./pivot_root_demo /tmp/rootfs /busybox sh bbsh$ PATH=/ bbsh$ busybox ln busybox ln bbsh$ ln busybox echo bbsh$ ln busybox ls bbsh$ ls busybox echo ln ls bbsh$ ls -id / # Comparaison avec le numéro d’inœud au-dessus 319459 / bbsh$ echo 'hello world' hello world
/* pivot_root_demo.c */
#define _GNU_SOURCE
#include <err.h>
#include <limits.h>
#include <sched.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/wait.h>
#include <unistd.h>
static int
pivot_root(const char *new_root, const char *put_old)
{
return syscall(SYS_pivot_root, new_root, put_old);
}
#define STACK_SIZE (1024 * 1024)
static int /* Fonction de démarrage pour l’enfant cloné */
child(void *arg)
{
char path[PATH_MAX];
char **args = arg;
char *new_root = args[0];
const char *put_old = "/oldrootfs";
/* S'assurer que 'new_root' et son point de montage parent
n’aient pas une propagation partagée (ce qui ferait renvoyer une
erreur à pivot_root()) et empêcher la propagation des événements
de montage dans l'espace de noms de montage initial. */
if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL) == -1)
err(EXIT_FAILURE, "mount-MS_PRIVATE");
/* S'assurer que 'new_root' soit un point de montage. */
if (mount(new_root, new_root, NULL, MS_BIND, NULL) == -1)
err(EXIT_FAILURE, "mount-MS_BIND");
/* Créer le répertoire où l'ancienne racine sera envoyée. */
snprintf(path, sizeof(path), "%s/%s", new_root, put_old);
if (mkdir(path, 0777) == -1)
err(EXIT_FAILURE, "mkdir");
/* Et changer de système de fichiers racine. */
if (pivot_root(new_root, path) == -1)
err(EXIT_FAILURE, "pivot_root");
/* Déplacer le répertoire de travail dans "/". */
if (chdir("/") == -1)
err(EXIT_FAILURE, "chdir");
/* Démonter l'ancienne racine et supprimer le point de montage. */
if (umount2(put_old, MNT_DETACH) == -1)
perror("umount2");
if (rmdir(put_old) == -1)
perror("rmdir");
/* Exécuter la commande indiquée dans argv[1]... */
execv(args[1], &args[1]);
err(EXIT_FAILURE, "execv");
}
int
main(int argc, char *argv[])
{
char *stack;
/* Créer un processus enfant dans un nouvel espace de noms de montage. */
stack = mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
if (stack == MAP_FAILED)
err(EXIT_FAILURE, "mmap");
if (clone(child, stack + STACK_SIZE,
CLONE_NEWNS | SIGCHLD, &argv[1]) == -1)
err(EXIT_FAILURE, "clone");
/* Le parent arrive ici ; attendre l'enfant. */
if (wait(NULL) == -1)
err(EXIT_FAILURE, "wait");
exit(EXIT_SUCCESS);
}
Cette traduction est une documentation libre ; veuillez vous reporter à la GNU General Public License version 3 concernant les conditions de copie et de distribution. Il n'y a aucune RESPONSABILITÉ LÉGALE.
Si vous découvrez un bogue dans la traduction de cette page de manuel, veuillez envoyer un message à