pivot_root(2) System Calls Manual pivot_root(2) BEZEICHNUNG pivot_root - die Wurzeleinhangung andern BIBLIOTHEK Standard-C-Bibliothek (libc, -lc) UBERSICHT #include /* Definition der SYS_*-Konstanten */ #include int syscall(SYS_pivot_root, const char *neue_Wurzel, const char *alte_Wurzel); Hinweis: Glibc stellt keinen Wrapper fur pivot_root() bereit; rufen Sie ihn mittels syscall(2) auf. BESCHREIBUNG pivot_root() andert die Einhangewurzel im Einhangenamensraum des aufrufenden Prozesses. Genauer ausgedruckt verschiebt es die Einhangewurzel in das Verzeichnis alte_Wurzel und macht neue_Wurzel zur neuen Einhangewurzel. Der aufrufende Prozess muss in dem Benutzer-Namensraum, zu dem der Einhangenamensraum des Aufrufenden gehort, uber die CAP_SYS_ADMIN-Capability verfugen. pivot_root() andert das Wurzelverzeichnis und das aktuelle Arbeitsverzeichnis jedes Prozesses oder Threads im gleichen Namensraum in neue_Wurzel, falls diese auf das alte Verzeichnis zeigen (siehe auch ANMERKUNGEN). Andererseits andert pivot_root() das aktuelle Arbeitsverzeichnis des Aufrufenden nicht (es sei denn, es ist das alte Wurzelverzeichnis), daher sollte darauf ein Aufruf von chdir("/") folgen. Die folgenden Einschrankungen gelten: o Neue_Wurzel und alte_Wurzel mussen Verzeichnisse sein. o Die neue_Wurzel und die alte_Wurzel durfen sich nicht in der gleichen Einhangung wie die aktuelle Wurzel befinden. o Die alte_Wurzel muss sich unterhalb der neuen_Wurzel befinden, das heisst, Hinzufugen einer nicht-negativen Anzahl von /.. zum Pfadnamen, der auf die alte_Wurzel zeigt, muss das gleiche Verzeichnis wie die neue_Wurzel ergeben. o Neue_Wurzel muss ein Pfad zu einem Einhangepunkt sein, aber darf nicht "/" sein. Ein Pfad, der nicht bereits ein Einhangepunkt ist, kann umgewandelt werden, indem er auf sich selbst bind-eingehangt wird. o Der Ausbreitungstyp von neue_Wurzel und seiner Elterneinhangung durfen nicht MS_SHARED sein; entsprechend falls alte_Wurzel ein bestehender Einhangepunkt ist, darf sein Ausbreitungstyp nicht MS_SHARED sein. Diese Einschrankungen stellen sicher, dass pivot_root() niemals Anderungen in einen anderen Einhange-Namensraum ausbreitet. o Das aktuelle Wurzelverzeichnis muss ein Einhangepunkt sein. RUCKGABEWERT Bei Erfolg wird Null zuruckgegeben. Bei einem Fehler wird -1 zuruckgegeben und errno gesetzt, um den Fehler anzuzeigen. FEHLER pivot_root() kann jeden der von stat(2) zuruckgegebenen Fehler zuruckgeben. Zusatzlich kann Folgendes zuruckgegeben werden: EBUSY Die neue_Wurzel oder die alte_Wurzel sind in der aktuellen Wurzeleinhangung. (Dieser Fehler deckt den pathologischen Fall ab, wenn die neue_Wurzel "/" ist.) EINVAL neue_Wurzel ist kein Einhangepunkt. EINVAL Die alte_Wurzel ist nicht in oder unterhalb der neuen_Wurzel. EINVAL Das aktuelle Wurzelverzeichnis ist kein Einhangepunkt (wegen eines fruher ausgefuhrten chroot(2)). EINVAL Die aktuelle Wurzel ist auf dem Rootfs (anfanglichen Ramfs-)Dateisystem; siehe ANMERKUNGEN. EINVAL Entweder der Einhangepunkt unter neue_Wurzel oder die Elterneinhangung dieses Einhangepunktes hat den Ausbreitungstyp MS_SHARED. EINVAL alte_Wurzel ist ein Einhangepunkt und der Ausbreitungstyp ist MS_SHARED. ENOTDIR neue_Wurzel oder alte_Wurzel ist kein Verzeichnis. EPERM Der aufrufende Prozess verfugt nicht uber die CAP_SYS_ADMIN-Capability. STANDARDS Linux. GESCHICHTE Linux 2.3.41. ANMERKUNGEN Eine Befehlszeilenschnittstelle fur diesen Systemaufruf wird durch pivot_root(8) bereitgestellt. pivot_root() ermoglicht dem Aufrufenden, in eine neue Dateisystemwurzel zu wechseln, wahrend gleichzeitig die alte Einhangewurzel an einem Ort unterhalb der neuen_Wurzel platziert wird, wo sie anschliessend ausgehangt werden kann. (Die Tatsache, dass alle Prozesse, die ein Wurzelverzeichnis oder ein aktuelles Arbeitsverzeichnis unterhalb des alten Wurzelverzeichnisses haben, zu der neuen Wurzel verschoben werden, befreit das alte Wurzelverzeichnis von Benutzern, wodurch das alte Wurzelverzeichnis leichter ausgehangt werden kann.) Der typische Anwendungsfall von pivot_root() ist wahrend des Systemstarts, wenn das System ein temporares Wurzeldateisystem einhangt, zum Beispiel ein initrd(4). Danach wird das reale Wurzeldateisystem eingehangt und eventuell in die aktuelle Wurzel aller relevanten Prozesse und Threads verwandelt. Ein moderner Anwendungsfall ist die Einrichtung eines Wurzeldateisystems wahrend der Erzeugung eines Containers. pivot_root() verandert die Wurzel und das aktuelle Arbeitsverzeichnis in der im Abschnitt BESCHREIBUNG angegebenen Weise. Dies ist notig, um Kernel-Threads daran zu hindern, die alte Einhangewurzel mit ihren Wurzeln und aktuellen Arbeitsverzeichnissen belegt zu halten, selbst dann, wenn sie auf das Dateisystem niemals zugreifen. Das Rootfs (anfangliche Ramfs) kann nicht mittels pivot_root erreicht werden. Die in diesem Fall empfohlene Methode zur Anderung des Wurzeldateisystems ist das Loschen samtlicher Inhalte im Rootfs, das Rootfs mit der neuen Wurzel ubereinzuhangen, stdin/stdout/stderr an das neue /dev/console anzuhangen und das neue init(1) auszufuhren. Helferprogramme fur diesen Prozess existieren: siehe switch_root(8). pivot_root(".", ".") Neue_Wurzel und alte_Wurzel konnen das gleiche Verzeichnis sein. Die folgende Sequenz erlaubt eine Pivot-Root-Aktion, ohne dass ein temporares Verzeichnis angelegt und wieder entfernt werden muss: chdir(neue_Wurzel); pivot_root(".", "."); umount2(".", MNT_DETACH); Diese Sequenz ist erfolgreich, weil der Aufruf von pivot_root() den alten Wurzeleinhangepunkt uber den neuen Wurzeleinhangepunkt in / stapelt. An diesem Punkt beziehen sich das Wurzelverzeichnis und das aktuelle Arbeitsverzeichnis des aufrufenden Prozesses auf den neuen Wurzeleinhangepunkt (neue_Wurzel). Wahrend des darauf folgenden Aufrufs von umount() beginnt die Auflosung von "." mit der neue_Wurzel und wandert dann die Liste der in / gestapelten Einhangungen hinauf, mit dem Ergebnis, dass der alte Einhangepunkt ausgehangt wird. Geschichtliche Anmerkungen Viele Jahre lang enthielt diese Handbuchseite den folgenden Text: pivot_root() kann die aktuelle Wurzel und das aktuelle Arbeitsverzeichnis von Prozessen und Threads andern, 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 Anderung 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 uberhaupt abgeschlossen war, beabsichtigte seinerzeit moglicherweise, die Benutzer zu warnen, dass sich die Implementation bis zur finalen Veroffentlichung andern konnte. Jedoch ist das im Abschnitt BESCHREIBUNG angegebene Verhalten seit der Erstveroffentlichung dieses Systemaufrufs konsistent geblieben und wird sich nun nicht andern. BEISPIELE Das untenstehende Programm beschreibt die Verwendung von pivot_root() innerhalb eines Einhangenamensraums, der mit clone(2) erstellt wurde. Nach dem Umschwenken zu dem im ersten Befehlszeilenargument des Programms benannten Wurzelverzeichnis fuhrt der mit clone(2) erzeugte Kindprozess das in den ubrigen Befehlszeilenargumenten benannte Programm aus. Wir demonstrieren das Programm durch Anlegen eines Verzeichnisses, das als das neue Wurzeldateisystem dient, und Setzen einer (statisch gelinkten) Kopie der ausfuhrbaren Datei busybox(1) in dieses Verzeichnis. $ 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 #include #include #include #include #include #include #include #include #include #include #include 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 /* Startfunktion fur das geklonte Kind */ child(void *arg) { char path[PATH_MAX]; char **args = arg; char *new_root = args[0]; const char *put_old = "/oldrootfs"; /* Sicherstellen, dass >>neue_Wurzel<< und dessen Elterneinhangung keine gemeinsame Ausbreitung haben (was pivot_root() dazu bringen wurde, einen Fehler auszugeben) und die Ausbreitung von Einhangeereignissen in den anfanglichen Namensraum zu verhindern. */ if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL) == -1) err(EXIT_FAILURE, "mount-MS_PRIVATE"); /* Sicherstellen, dass >>neue_Wurzel<< ein Einhangepunkt ist. */ if (mount(new_root, new_root, NULL, MS_BIND, NULL) == -1) err(EXIT_FAILURE, "mount-MS_BIND"); /* Ein Verzeichnis anlegen, zu dem die alte Wurzel hin umgeschwenkt wird. */ snprintf(path, sizeof(path), "%s/%s", new_root, put_old); if (mkdir(path, 0777) == -1) err(EXIT_FAILURE, "mkdir"); /* Und das Wurzeldateisystem umschwenken. */ if (pivot_root(new_root, path) == -1) err(EXIT_FAILURE, "pivot_root"); /* Das aktuelle Arbeitsverzeichnis auf >>/<< andern. */ if (chdir("/") == -1) err(EXIT_FAILURE, "chdir"); /* Die alte Wurzel aushangen und den Einhangepunkt entfernen.*/ if (umount2(put_old, MNT_DETACH) == -1) perror("umount2"); if (rmdir(put_old) == -1) perror("rmdir"); /* Den in argv[1] angegebenen Befehl ausfuhren */ execv(args[1], &args[1]); err(EXIT_FAILURE, "execv"); } int main(int argc, char *argv[]) { char *stack; /* Einen Kindprozess in einem neuen Einhangenamensraum erzeugen. */ 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"); /* Elternprozess fallt bis hierher durch; wartet auf Kindprozess. */ if (wait(NULL) == -1) err(EXIT_FAILURE, "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) UBERSETZUNG Die deutsche Ubersetzung dieser Handbuchseite wurde von Mario Blattermann und Helge Kreutzmann erstellt. Diese Ubersetzung ist Freie Dokumentation; lesen Sie die GNU General Public License Version 3 oder neuer bezuglich der Copyright-Bedingungen. Es wird KEINE HAFTUNG ubernommen. Wenn Sie Fehler in der Ubersetzung dieser Handbuchseite finden, schicken Sie bitte eine E-Mail an die Mailingliste der Ubersetzer . Linux man-pages 6.06 31. Oktober 2023 pivot_root(2)