Não. OMI isto não é muito claro, mas há uma leitura muito mais consistente e correta.
A parte essencial de pivot_root (), que deve ser a mesma em qualquer implementação, é:
pivot_root() moves the root filesystem
of the calling processto the directory put_old and makes new_root the new root filesystemof the calling process.
A parte essencial de pivot_root () não está limitada apenas ao processo de chamada. A operação descrita nesta citação funciona no namespace de montagem do processo de chamada. Isso afetará a exibição de todos os processos no mesmo namespace de montagem.
Suponho que a página do manual tente definir isso falando sobre o "sistema de arquivos raiz" aqui, ao passo que quando ele quiser se referir ao chroot atual, ele diz "raiz" por conta própria. Eu acho que usa esses termos de forma consistente, mas até que eu entendi os detalhes do pivot_root (), isso não era nada claro para mim.
Considere o efeito que a mudança essencial tem em um segundo processo - ou thread de kernel - cujo diretório de trabalho era o antigo sistema de arquivos raiz. Seu diretório atual ainda será o antigo sistema de arquivos raiz. Isso manterá o ponto de montagem /put_old
ocupado e, portanto, não será possível desmontar o sistema de arquivos raiz antigo.
Se você controlar esse segundo processo, resolva isso, conforme a página do manual, configurando seu diretório de trabalho como new_root antes de pivot_root () ser chamado. Depois que pivot_root () é chamado, seu diretório atual ainda será o novo sistema de arquivos raiz.
Portanto, o processo S (ystemd) foi configurado para sinalizar o processo P (lymouth), para alterar o diretório de trabalho antes que o S chame pivot_root (). Sem problemas. Mas também temos threads do kernel, que começam em /
. A implementação atual do pivot_root () cuida dos threads do kernel para nós; é equivalente a configurar os diretórios de trabalho dos encadeamentos do kernel e qualquer outro processo para new_root
antes da parte essencial de pivot_root ().
Exceto, a implementação atual do pivot_root () somente altera o diretório de trabalho de um processo se o diretório de trabalho antigo for /
. Então é bem fácil ver a diferença que isso faz:
$ unshare -rm
# cd /tmp # work in a subdir instead of '/', and pivot_root() will not change it
# /bin/pwd
/tmp
# mount --bind /new-root /new-root
# pivot_root /new-root /new-root/mnt
# /bin/pwd
/mnt/tmp # see below: if pivot_root had not updated our current chroot, this would show /tmp
v.s.
$ unshare -rm
# cd /
# /bin/pwd
/
# ls -lid .
2 dr-xr-xr-x. 19 nfsnobody nfsnobody 4096 Jun 13 01:17 .
# ls -lid /newroot
6424395 dr-xr-xr-x. 20 nfsnobody nfsnobody 4096 May 10 12:53 /new-root
# mount --bind /new-root /new-root
# pivot_root /new-root /new-root/mnt
# /bin/pwd
/
# ls -lid .
6424395 dr-xr-xr-x. 20 nobody nobody 4096 May 10 12:53 .
# ls -lid /
6424395 dr-xr-xr-x. 20 nobody nobody 4096 May 10 12:53 /
# ls -lid /mnt
2 dr-xr-xr-x. 19 nobody nobody 4096 Jun 13 01:17 /mnt
Agora eu entendo o que está acontecendo com o diretório de trabalho, acho mais fácil entender o que está acontecendo com o chroot (). O chroot atual do processo que chama pivot_root () pode ser uma referência ao sistema de arquivos raiz original, assim como seu diretório de trabalho atual pode ser.
Note, se você fizer chdir () + pivot_root () mas esqueceu de chroot (), seu diretório atual estará fora do seu chroot atual. Quando seu diretório atual está fora de seu chroot atual, as coisas ficam bastante confusas. Você provavelmente não deseja executar seu programa nesse estado.
# cd /
# python
>>> import os
>>> os.chroot("/newroot")
>>> os.system("/bin/pwd")
(unreachable)/
0
>>> os.getcwd()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OSError: [Errno 2] No such file or directory
>>> os.system("ls -l ./proc/self/cwd")
lrwxrwxrwx. 1 root root 0 Jun 17 13:46 ./proc/self/cwd -> /
0
>>> os.system("ls -lid ./proc/self/cwd/")
2 dr-xr-xr-x. 19 root root 4096 Jun 13 01:17 ./proc/self/cwd/
0
>>> os.system("ls -lid /")
6424395 dr-xr-xr-x. 20 root root 4096 May 10 12:53 /
0
POSIX não especifica o resultado de pwd
ou getcwd () nesta situação :). POSIX não dá nenhum aviso de que você pode obter um erro "Nenhum arquivo ou diretório" (ENOENT) de getcwd (). Manpages do Linux apontam esse erro como possível, se o diretório de trabalho foi desvinculado (por exemplo, com rm
). Eu acho que esse é um bom paralelo.