PIVOT_ROOT(2)

BEZEICHNUNG
pivot_root - die Wurzeleinhängung ändern

ÜBERSICHT
int pivot_root(const char *neue_Wurzel, const char *alte_Wurzel);

Hinweis: Es gibt keinen Glibc-Wrapper für diesen Systemaufruf; siehe ANMERKUNGEN.

BESCHREIBUNG
pivot_root() changes the root mount in the mount namespace of the calling process. More precisely, it moves the root mount to the directory put_old and makes new_root the new root mount. The calling process must have the CAP_SYS_ADMIN capability in the user namespace that owns the caller's mount namespace.

pivot_root() changes the root directory and the current working directory of each process or thread in the same mount namespace to new_root if they point to the old root directory. (See also NOTES.) On the other hand, pivot_root() does not change the caller's current working directory (unless it is on the old root directory), and thus it should be followed by a chdir("/") call.

Die folgenden Einschränkungen gelten:

-   Neue_Wurzel und alte_Wurzel müssen Verzeichnisse sein.

-   Die neue_Wurzel und die alte_Wurzel dürfen sich nicht in der gleichen Einhängung wie die aktuelle Wurzel befinden.

-   Die alte_Wurzel muss sich unterhalb der neuen_Wurzel befinden, das heißt, Hinzufügen einer von nicht-negativen Anzahl von /.. zum Pfadnamen, der auf die alte_Wurzel zeigt, muss das gleiche Verzeichnis wie die neue_Wurzel ergeben.

-   Neue_Wurzel muss ein Pfad zu einem Einhängepunkt sein, aber darf nicht "/" sein. Ein Pfad, der nicht bereits ein Einhängepunkt ist, kann umgewandelt werden, indem er auf sich selbst bind-eingehängt wird.

-   Der Ausbreitungstyp von neue_Wurzel und seiner Elterneinhängung dürfen nicht MS_SHARED sein; entsprechend falls alte_Wurzel ein bestehender Einhängepunkt ist, darf sein Ausbreitungstyp nicht MS_SHARED sein. Diese Einschränkungen stellen sicher, dass pivot_root() niemals Änderungen in einen anderen Einhänge-Namensraum ausbreitet.

-   Das aktuelle Wurzelverzeichnis muss ein Einhängepunkt sein.

RÜCKGABEWERT
Bei Erfolg wird Null zurückgegeben. Bei einem Fehler wird -1 zurückgegeben und errno entsprechend gesetzt.

FEHLER
pivot_root() kann jeden der von stat(2) zurückgegebenen Fehler zurückgeben. Zusätzlich kann Folgendes zurückgegeben werden:

EBUSY
    Die neue_Wurzel oder die alte_Wurzel sind in der aktuellen Wurzeleinhängung. (Dieser Fehler deckt den pathologischen Fall ab, wenn die neue_Wurzel "/" ist.)

EINVAL
    neue_Wurzel ist kein Einhängepunkt.

EINVAL
    Die alte_Wurzel ist nicht in oder unterhalb der neuen_Wurzel.

EINVAL
    Das aktuelle Wurzelverzeichnis ist kein Einhängepunkt (wegen eines früher ausgeführten chroot(2)).

EINVAL
    Die aktuelle Wurzel ist auf dem Rootfs (anfänglichen Ramfs-)Dateisystem; siehe ANMERKUNGEN.

EINVAL
    Entweder der Einhängepunkt unter neue_Wurzel oder die Elterneinhängung dieses Einhängepunktes hat den Ausbreitungstyp MS_SHARED.

EINVAL
    alte_Wurzel ist ein Einhängepunkt und der Ausbreitungstyp ist MS_SHARED.

ENOTDIR
    neue_Wurzel oder alte_Wurzel ist kein Verzeichnis.

EPERM
    Der aufrufende Prozess verfügt nicht über die CAP_SYS_ADMIN-Capability.

VERSIONEN
pivot_root() wurde in Linux 2.3.41 eingeführt.

KONFORM ZU
pivot_root() ist Linux-spezifisch und daher nicht portierbar.

ANMERKUNGEN
Glibc stellt keinen Wrapper für diesen Systemaufruf bereit; rufen Sie ihn mittels syscall(2) auf.

Eine Befehlszeilenschnittstelle für diesen Systemaufruf wird durch pivot_root(8) bereitgestellt.

pivot_root() allows the caller to switch to a new root filesystem while at the same time placing the old root mount at a location under new_root from where it can subsequently be unmounted. (The fact that it moves all processes that have a root directory or current working directory on the old root directory to the new root frees the old root directory of users, allowing the old root mount to be unmounted more easily.)

Der typische Anwendungsfall von pivot_root() ist während des Systemstarts, wenn das System ein temporäres Wurzeldateisystem einhängt, zum Beispiel ein initrd(4). Danach wird das reale Wurzeldateisystem eingehängt und eventuell in die aktuelle Wurzel aller relevanten Prozesse und Threads verwandelt. Ein moderner Anwendungsfall ist die Einrichtung eines Wurzeldateisystems während der Erzeugung eines Containers.

The fact that pivot_root() modifies process root and current working directories in the manner noted in DESCRIPTION is necessary in order to prevent kernel threads from keeping the old root mount busy with their root and current working directories, even if they never access the filesystem in any way.

Das Rootfs (anfängliche Ramfs) kann nicht mittels pivot_root erreicht werden. Die in diesem Fall empfohlene Methode zur Änderung des Wurzeldateisystems ist das Löschen sämtlicher Inhalte im Rootfs, das Rootfs mit der neuen Wurzel übereinzuhängen, stdin/stdout/stderr an das neue /dev/console anzuhängen und das neue init(1) auszuführen. Helferprogramme für diesen Prozess existieren: siehe switch_root(8).

  pivot_root(".", ".")

Neue_Wurzel und alte_Wurzel können das gleiche Verzeichnis sein. Die folgende Sequenz erlaubt eine Pivot-Root-Aktion, ohne dass ein temporäres Verzeichnis angelegt und wieder entfernt werden muss:

    chdir(neue_Wurzel);
    pivot_root(".", ".");
    umount2(".", MNT_DETACH);

This sequence succeeds because the pivot_root() call stacks the old root mount point on top of the new root mount point at /. At that point, the calling process's root directory and current working directory refer to the new root mount point (new_root). During the subsequent umount() call, resolution of "." starts with new_root and then moves up the list of mounts stacked at /, with the result that old root mount point is unmounted.

  Geschichtliches
Viele Jahre lang enthielt diese Handbuchseite den folgenden Text:

    pivot_root() kann die aktuelle Wurzel und das aktuelle Arbeitsverzeichnis von Prozessen und Threads ändern, welche das alte Wurzelverzeichnis nutzen, muss dies aber nicht. Der Prozess, welcher pivot_root() aufruft, muss sicherstellen, dass Prozesse mit Wurzel- oder aktuellem Arbeitsverzeichnis in jedem Fall korrekt arbeiten. Ein einfacher Weg hierzu ist die Änderung von Wurzel- und aktuellem Arbeitsverzeichnis auf die neue_Wurzel, bevor pivot_root() aufgerufen wird.

Dieser Text, der geschrieben wurde, bevor, die Implementierung des Systemaufrufs im Kernel überhaupt abgeschlossen war, beabsichtigte seinerzeit möglicherweise, die Benutzer zu warnen, dass sich die Implementation bis zur finalen Veröffentlichung ändern könnte. Jedoch ist das im Abschnitt BESCHREIBUNG angegebene Verhalten seit der Erstveröffentlichung dieses Systemaufrufs konsistent geblieben und wird sich nun nicht ändern.

BEISPIEL

Das untenstehende Programm beschreibt die Verwendung von pivot_root() innerhalb eines Einhängenamensraums, der mit clone(2) erstellt wurde. Nach dem »Pivoten« zu dem im ersten Befehlszeilenargument des Programms benannten Wurzelverzeichnis führt der mit clone(2) erzeugte Kindprozess das in den übrigen Befehlszeilenargumenten benannte Programm aus.

We demonstrate the program by creating a directory that will serve as the new root filesystem and placing a copy of the (statically linked) busybox(1) executable in that directory.

    $ mkdir /tmp/rootfs
    $ ls -id /tmp/rootfs    # Inode-Anzahl des neuen Wurzelverzeichnisses zeigen
    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 /          # Mit der Inode-Anzahl oben vergleichen
    319459 /
    bbsh$ echo 'Hallo Welt'
    Hallo Welt

  Programmquelltext

    /* pivot_root_demo.c */
    #define _GNU_SOURCE
    #include <sched.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/wait.h>
    #include <sys/syscall.h>
    #include <sys/mount.h>
    #include <sys/stat.h>
    #include <limits.h>
    #define errExit(Nachricht)    do { perror(Nachricht); exit(EXIT_FAILURE); \
                            } while (0)
    static int
    pivot_root(const char *neue_Wurzel, const char *alte_Wurzel)
    {
        return syscall(SYS_pivot_root, neue_Wurzel, alte_Wurzel);
    }
    #define STACK_SIZE (1024 * 1024)
    static int              /* Startfunktion für geklontes Kind */
    child(void *arg)
    {
        char **args = arg;
        char *neue_Wurzel = args[0];
        const char *alte_Wurzel = "/altes_Wurzeldateisystem";
        char path[PATH_MAX];
        /* Ensure that 'new_root' and its parent mount don't have
           shared propagation (which would cause pivot_root() to
           return an error), and prevent propagation of mount
           events to the initial mount namespace */
        if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL) == 1)
            errExit("mount-MS_PRIVATE");
        /* Sicherstellen, dass 'neue_Wurzel' ein Einhängepunkt ist */
        if (mount(neue_Wurzel, neue_Wurzel, NULL, MS_BIND, NULL) == -1)
            errExit("mount-MS_BIND");
        /* Ein Verzeichnis anlegen, zu dem die alte Wurzel »pivoted« wird */
        snprintf(path, sizeof(path), "%s/%s", neue_Wurzel, alte_Wurzel);
        if (mkdir(path, 0777) == -1)
            errExit("mkdir");
        /* Und das Wurzeldateisystem »pivoten« */
        if (pivot_root(neue_Wurzel, Pfad) == -1)
            errExit("pivot_root");
        /* Das aktuelle Arbeitsverzeichnis auf »/« ändern */
        if (chdir("/") == -1)
            errExit("chdir");
        /* Die alte Wurzel aushängen und den Einhängepunkt entfernen*/
        if (umount2(put_old, MNT_DETACH) == -1)
            perror("umount2");
        if (rmdir(put_old) == -1)
            perror("rmdir");
        /* Den in argv[1] … angegebenen Befehl ausführen */
        execv(args[1], &args[1]);
        errExit("execv");
    }
    int
    main(int argc, char *argv[])
    {
        /* Einen Kindprozess in einem neuen Einhängenamensraum erzeugen */
        char *stack = malloc(STACK_SIZE);
        if (stack == NULL)
            errExit("malloc");
        if (clone(child, stack + STACK_SIZE,
                    CLONE_NEWNS | SIGCHLD, &argv[1]) == -1)
            errExit("clone");
        /* Elternprozess fällt bis hierher durch; wartet auf Kindprozess */
        if (wait(NULL) == -1)
            errExit("wait");
        exit(EXIT_SUCCESS);
    }

SIEHE AUCH
chdir(2), chroot(2), mount(2), stat(2), initrd(4), mount_namespaces(7), pivot_root(8), switch_root(8)

KOLOPHON
Diese Seite ist Teil der Veröffentlichung 5.03 des Projekts Linux-man-pages. Eine Beschreibung des Projekts, Informationen, wie Fehler gemeldet werden können sowie die aktuelle Version dieser Seite finden sich unter https://www.kernel.org/doc/man-pages/.

ÜBERSETZUNG
Die deutsche Übersetzung dieser Handbuchseite wurde von Mario Blättermann <mario.blaettermann@gmail.com> und Helge Kreutzmann <debian@helgefjell.de> erstellt. Diese Übersetzung ist Freie Dokumentation; lesen Sie die GNU General Public License Version 3 oder neuer bezüglich der Copyright-Bedingungen. Es wird KEINE HAFTUNG übernommen. Wenn Sie Fehler in der Übersetzung dieser Handbuchseite finden, schicken Sie bitte eine E-Mail an <debian-l10n-german@lists.debian.org>.