我曾尝试在我的系统上研究这些设备文件的差异,但谷歌的搜索结果对我来说不起作用。
答案1
/dev/ptmx
行为类似于 的符号链接(“打开时将在同一目录中查找 [...]“pts”。”)/dev/pts/ptmx
,但前者是所有人可读写的,而后者则无人可访问。与符号链接不同,目标权限无关紧要。可以使用 删除并重新创建它mknod
。您无法删除/dev/pts/ptmx
:
/dev# ll ptmx # Show original
crw-rw-rw- 1 root root 5, 2 Jan 31 03:50 ptmx
/dev# rm ptmx # Delete it
/dev# mknod ptmx c 5 2 # Recreate it
/dev# chmod 666 ptmx
/dev# ll ptmx
crw-rw-rw- 1 root root 5, 2 Jan 31 03:52 ptmx
/dev# ll pts/ptmx
c--------- 1 root root 5, 2 Jan 27 16:23 pts/ptmx
/dev# rm pts/ptmx # Can't delete that one
rm: cannot remove 'pts/ptmx': Operation not permitted
设备类型相同,因此应该具有相同的行为,但devpts
挂载的文件系统/dev/pts
很特殊,不允许删除其 ptmx。
$ stat /dev/ptmx
[...]
Device: 0,5 Inode: 90 Links: 1 Device type: 5,2
[...]
$ stat /dev/pts/ptmx
[...]
Device: 0,24 Inode: 2 Links: 1 Device type: 5,2
[...]
通常重要的部分是Device type: 5,2
意思是“PTY 主多路复用”。这标识了 IO 被发送到内核的哪个位置,但显然有特殊的代码可以使这两种情况有所不同。
记住坐骑本身。根据https://www.kernel.org/doc/Documentation/filesystems/devpts.txt,
现在,devpts 文件系统的每个挂载都是不同的,使得在一个挂载中分配的 ptys 及其索引与所有其他挂载中的 ptys 及其索引无关。
两者可用的原因在于向前和向后兼容。它们是两种不同类型的挂载点,分别/dev
是devtmpfs
,而/dev/pts
。devpts
其他发行版符号链接/dev/ptmx
到/dev/pts/ptmx
并使其/dev/pts/ptmx
可世界读写。为了向后兼容,/dev/ptmx
不能删除,因为今天的应用程序(您的终端等)使用它。为了向前兼容,我们希望/dev/pts/ptmx
允许命名空间和容器化。我可以将另一个devpts
文件系统挂载到其他地方,并且 ID 将与 中的 ID 分开/dev/pts
。命名空间和拥有单独 ID 的概念构成了 Docker 等容器化技术的基础。您可以启动 Docker 容器并查看mount
和ls -l /dev && ls -l /dev/pts
以了解其中的魔力。
以下是一些一般性的探索:
/tmp# mkdir test
/tmp# mount --make-private -t devtmpfs devtmpfs test # private to allow mount --move
/tmp# cd test
/tmp/test# ls ptmx
ptmx
/tmp/test# ls pts
/tmp/test# exec 3<>ptmx # ptmx acts like a broken symlink to pts/ptmx
-bash: ptmx: No such device
/tmp/test# mount -t devpts devpts pts # Now it works
/tmp/test# ls pts
ptmx
/tmp/test# exec 3<>ptmx # Open /dev/ptmx
/tmp/test# ls pts
0 ptmx
/tmp/test# exec 4<>pts/ptmx # Open /dev/pts/ptmx, same effect
/tmp/test# ls pts
0 1 ptmx
/tmp/test# exec 3>&- # Because they act on the same /dev/pts folder
/tmp/test# ls pts
1 ptmx
/tmp/test# exec 4>&-
/tmp/test# ls pts
ptmx
/tmp/test# exec 3<>ptmx # Set up a few examples
/tmp/test# exec 4<>ptmx
/tmp/test# exec 5<>ptmx
/tmp/test# ls pts
0 1 2 ptmx
/tmp/test# mkdir pts.old # If we move the mount, the /dev/ptmx will point to the new /dev/pts
/tmp/test# mount --move pts pts.old
/tmp/test# mount -t devpts devpts pts
/tmp/test# ls pts
ptmx
/tmp/test# ls pts.old
0 1 2 ptmx
/tmp/test# exec 6<>ptmx # Create in new mount
/tmp/test# ls pts/
0 ptmx
/tmp/test# ls pts.old
0 1 2 ptmx
/tmp/test# mount --move pts pts.new # Same thing if we swap the mounts
/tmp/test# mount --move pts.old pts
/tmp/test# mount --move pts.new pts.old
/tmp/test# ls pts
0 1 2 ptmx
/tmp/test# ls pts.old
0 ptmx
/tmp/test# exec 7<>ptmx
/tmp/test# ls pts
0 1 2 3 ptmx
/tmp/test# ls pts.old
0 ptmx
/tmp/test# exec 8<>pts/ptmx # If we access the pts/ptmx, it will use the corresponding namespace
/tmp/test# ls pts
0 1 2 3 4 ptmx
/tmp/test# ls pts.old
0 ptmx
/tmp/test# exec 9<>pts.old/ptmx
/tmp/test# ls pts
0 1 2 3 4 ptmx
/tmp/test# ls pts.old
0 1 ptmx
/tmp/test# cd ..
/tmp# umount -l test
/tmp# mount -t tmpfs tmpfs test
/tmp# cd test
/tmp/test# mknod ptmx c 5 2
/tmp/test# mkdir pts.new
/tmp/test# ln -s pts.new pts # It does not recursively follow symlinks
/tmp/test# mount -t devpts devpts pts.new
/tmp/test# exec 3<>ptmx
-bash: ptmx: No such device
home@daniel-tablet1:~$ unshare -mr # Create a unprivileged namespace where I am a "fake" root
root@daniel-tablet1:~# # Can't do this because every devtmpfs is the same. Docker uses a tmpfs for /dev.
root@daniel-tablet1:~# # If you create a file in /tmp/test, it will show up in /dev
root@daniel-tablet1:~# # But mounts under /tmp/test will NOT show up in /dev even if I didn't add --make-private
root@daniel-tablet1:~# mount -t devtmpfs devtmpfs Downloads # Can't do this because every devtmpfs is the same
mount: /home/home/Downloads: permission denied.
dmesg(1) may have more information after failed mount system call.
root@daniel-tablet1:~# mount -t devpts devpts Downloads # All users can create a new devpts namespace
root@daniel-tablet1:~# ls Downloads
ptmx
~# cd /dev
/dev# mount -t devpts devpts pts # I can overmount /dev/pts using an unprivileged mount namespace
/dev# ls pts
ptmx
/dev# exec 3<>ptmx
/dev# ls pts
0 ptmx