如何在 Linux 中跟踪块设备?

如何在 Linux 中跟踪块设备?

我试图获取 /dev/sda2 的最后 1024 个字节。当我这样做时sudo tail -c 1024 /dev/sda2 | hd,提示符会一直挂起,直到我按下 Ctrl-C。但是,当我tail -c 1024 ddfilecopyofsda2 | hd做时,我立即得到了文件最后 1024 个字节的良好输出。我在这里读到 (https://unix.stackexchange.com/questions/60034/what-are-character-special-and-block-special-files-in-a-unix-system)“块设备通常是可寻址的”,那么我遗漏了什么?

答案1

以下是获取块设备最后 1024 个字节的一种方法:

last_bytes() { sudo dd if=$2 iflag=skip_bytes skip=$(($(sudo blockdev --getsize64 $2) - $1)) bs=1M ; } ; last_bytes 1024 DEVICE

替换DEVICE为设备路径。对于您的情况,可以使用/dev/sda2


现在来回答一个更有趣的问题……

为什么要tail -c 1024 /dev/sda2搜索整个磁盘?

原因在于tail实现方式。当tail知道正在读取的文件的大小时,它就知道要查找多少。否则,它必须一直读取文件或流才能找出要回溯多远。

使用管道,这是有意义的,就像cat /dev/sda2 | tail -c 1024. tail以流的形式接收内容并且无法知道数据何时结束。

您可能希望tail -c 1024 /dev/sda2能够确定的大小/dev/sda2,但实际上,当tail查找时/dev/sda2,它会作为块设备而不是常规文件打开。

实现细节是tail调用fstat()获取有关该文件的信息。

tail在普通文件上

以下是打开文件strace示例的相关部分:tail

21:30:27 open("/var/log/syslog", O_RDONLY) = 3
21:30:27 fstat(3, {st_dev=makedev(0, 22), st_ino=4715, st_mode=S_IFREG|0640, st_nlink=1, st_uid=104, st_gid=4, st_blksize=131072, st_blocks=54, st_size=175500, st_atime=2017/11/10-21:28:39.243133398, st_mtime=2017/11/10-21:30:20.438031639, st_ctime=2017/11/10-21:30:20.438031639}) = 0
21:30:27 lseek(3, 0, SEEK_CUR)          = 0
21:30:27 lseek(3, 174476, SEEK_SET)     = 174476

fstat()提供st_size=175500。现在tail只需要往回数1024个字节:

175500-1024=174476

…这正是tail

lseek(3, 174476, SEEK_SET)     = 174476

tail在块设备上

fstat()这次不返回尺寸!:

21:29:43 open("/dev/sda", O_RDONLY)     = 3
21:29:43 fstat(3, {st_dev=makedev(0, 6), st_ino=17488, st_mode=S_IFBLK|0660, st_nlink=1, st_uid=0, st_gid=6, st_blksize=4096, st_blocks=0, st_rdev=makedev(8, 0), st_atime=2017/11/10-09:21:15.643998960, st_mtime=2017/11/10-09:21:15.555998962, st_ctime=2017/11/10-09:21:15.555998962}) = 0

如果没有st_sizetail就无法知道要寻找多远,因此它默认读取整个块设备直到最后。

这就是为什么您通常应该使用诸如的块设备工具dd来操作块设备而不是诸如的用于常规文件的工具tail


你可能会问“如何blockdev --getsize64快速获取块设备的大小?”

这里是sudo strace -vvvfts1000 blockdev --getsize64 /dev/sda

21:53:15 open("/dev/sda", O_RDONLY)     = 3
21:53:15 ioctl(3, BLKGETSIZE64, [512110190592]) = 0

blockdev用于获取块设备ioctl,并BLKGETSIZE64获取块设备的大小。


至于为什么 tail不行BLKGETSIZE64,我不知道。源代码显示:

#define IS_TAILABLE_FILE_TYPE(Mode) \
  (S_ISREG (Mode) || S_ISFIFO (Mode) || S_ISSOCK (Mode) || S_ISCHR (Mode))

我只从那句话中知道,没有S_ISBLK(),作者并不打算tail支持块设备。

相关内容