首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何获取文件的块设备名称?

如何获取文件的块设备名称?
EN

Stack Overflow用户
提问于 2022-05-12 16:49:58
回答 1查看 601关注 0票数 0

这是牦牛须一个X问题,所以我从一开始就开始。

我希望测试一个程序的行为,该程序将文件从源驱动器复制到目标驱动器,而目标驱动器试图聪明地判断源目录是远程的还是本地的。

另见以编程方式复制许多文件的最有效方法是什么?

我只是在测试正确性。测试平台不需要可靠地测量性能(尽管这样做很好)。重点是测试程序要处理的场景,比如使用XFS将源或目标标识为本地驱动器,或者使用sshfs或nfs将远程驱动器标识为本地驱动器。

为此,我想设置一些测试文件系统,并在它们之间复制数据。这类似于这个问题- 作为集成测试的一部分,我可以在Docker容器中创建一个文件系统(例如xfs )吗?

我打算将这些测试包括在自动化测试套件中,它必须在本地和Azure下运行。

对于本地文件系统,我的计划是这样的策略:

代码语言:javascript
运行
复制
dd if=/dev/zero of=xfs.img bs=1M count=250
/usr/sbin/mkfs.xfs xfs.img
mkdir -p mnt/xfs1
guestmount -a xfs.img -m /dev/sda mntxfs

对于在用户空间中挂载图像,我已经决定/发现客座是最好的选择。模糊安装和udiskctl仍然需要超级用户特权。同样,我也不想和-在码头集装箱上享有特权搏斗。

流浪汉肯定能解决这个问题,但如果我能在脚本或坞中这样做的话,它会造成太大的损失。(在Azure上,流浪者无论如何都会跑进码头)。

如果我使用guestmount -i,我得到:

代码语言:javascript
运行
复制
guestmount: no operating system was found on this disk

因此,我必须使用-m,它需要知道正确的块设备,例如:

代码语言:javascript
运行
复制
guestmount -a xfs.img -m /dev/sda mntxfs

这里的问题是识别包含xfs.img的块设备。

我可以使用df或fndmnt查找文件系统/分区

代码语言:javascript
运行
复制
>findmnt -no source -T xfs.img
/dev/mapper/rhel-home

但是来宾不喜欢逻辑卷:

代码语言:javascript
运行
复制
>guestmount -a xfs.img -m /dev/mapper/rhel-home mntxfs
libguestfs: error: vfs_type: vfs_type_stub: /dev/mapper/rhel-home: No such file or directory
libguestfs: error: mount_options: mount_options_stub: /dev/mapper/rhel-home: No such file or directory
guestmount: /dev/mapper/rhel-home could not be mounted.
guestmount: Did you mean to mount one of these filesystems?
guestmount:     /dev/sda (xfs)

所以问题是如何查找文件的块设备名称 (或分区)

你可以获取分区的设备名称。

代码语言:javascript
运行
复制
ls -l /sys/class/block/sda1
lrwxrwxrwx. 1 root root 0 May 12 10:08 /sys/class/block/sda1 -> ../../devices/pci0000:ae/0000:ae:00.0/0000:af:00.0/host0/target0:2:0/0:2:0:0/block/sda/sda1
>lsblk -ndo pkname /dev/sda1
sda

但是,对于逻辑卷来说,这是失败的:

代码语言:javascript
运行
复制
>lsblk /dev/mapper/rhel-home 
NAME      MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
rhel-home 253:2    0  1.8T  0 lvm  /home

这些信息在lsblk中,但是很难解析:

代码语言:javascript
运行
复制
>lsblk -a
NAME          MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
loop0           7:0    0  250M  0 loop /run/media/root/075889d6-43c8-45da-a1fb-d9b99d98716a
sda             8:0    0  931G  0 disk 
sda1          8:1    0    1G  0 part /boot
sda2          8:2    0  930G  0 part 
 rhel-root 253:0    0   70G  0 lvm  /
 rhel-swap 253:1    0    4G  0 lvm  [SWAP]
 rhel-home 253:2    0  1.8T  0 lvm  /home
sdb             8:16   0  931G  0 disk 
sdb1          8:17   0  931G  0 part 
 rhel-home 253:2    0  1.8T  0 lvm  /home

如果您有一种安全可靠的方法从这里得到sdb或sda,请告诉我。(我不知道为什么/home在sda和sdb都在这里-如果你这么做了,请解释)

使用-fs选项可能更容易:

代码语言:javascript
运行
复制
>lsblk -fs
NAME      FSTYPE      LABEL UUID                                   MOUNTPOINT
rhel-root xfs               eced9cd8-d1ac-4541-b596-09839ad91afb   /
sda2    LVM2_member       rqDCVg-8XR9-Gu0K-eNL1-vZt4-2wgr-yyRL4a 
  sda                                                            
rhel-home xfs               6be4c859-ff15-4242-aace-05f6afac9d93   /home
sda2    LVM2_member       rqDCVg-8XR9-Gu0K-eNL1-vZt4-2wgr-yyRL4a 
 sda                                                            
sdb1    LVM2_member       y772ZY-jJsE-AoOy-pVqf-71vC-aU79-pXxq6z 
 sdb                                   

信息在/sys中的某个地方,但我不知道如何提取它。

代码语言:javascript
运行
复制
>grep -r rhel-home /sys 2>/dev/null
/sys/devices/virtual/block/dm-2/dm/name:rhel-home

我试着查看lsblk来源,但到目前为止还没有确定它是如何生成树的。

通过对lvm的欢迎,我可以从lsblk中识别出这是一个合乎逻辑的变体。

代码语言:javascript
运行
复制
>lsblk | grep rhel-home 
rhel-home 253:2    0  1.8T  0 lvm  /home
rhel-home 253:2    0  1.8T  0 lvm  /home

如果我们知道这是一个逻辑卷,那么问题就变成了https://serverfault.com/questions/461385/how-to-find-the-physical-volumes-that-hold-a-logical-volume-in-lvm,lvs需要根:

代码语言:javascript
运行
复制
>lvs -o +devices
 WARNING: Running as a non-root user. Functionality may be unavailable.
 /run/lock/lvm/P_global:aux: open failed: Permission denied

我可以通过以下方式使用设备号来定位分区:

代码语言:javascript
运行
复制
>grep -r 253:2 /sys/devices/ 2>/dev/null
/sys/devices/virtual/block/dm-2/dev:253:2
>ls /sys/devices/virtual/block/dm-2/slaves/
sda2  sdb1

这样我就能做到了。只是极度的痛苦。如果我想把它写进脚本中,那么就有太多的错误发生了。

肯定有更好的办法吗?

guestmount已经知道块设备,正如它所暗示的那样。解析其错误消息将是对上述恶作剧的改进。

我还想了解/sys相关部分的布局,这样我就可以编写一个更好的脚本,或者一个编译好的程序或库例程来完成这个任务。

另见在Linux中模拟硬盘驱动器

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-05-12 16:49:58

下面是我为此创建的可怕的脚本。请让我们有更好的方法!

代码语言:javascript
运行
复制
#!/bin/bash
#
# Given a file identify the block device on which it resides
#

PROGNAME=`basename $0`
STATUS=0
VERBOSE=0

showUsage() {
    echo "usage:"
    echo "  $PROGNAME <filename>"
}

showHelp() {
    showUsage
    echo
    echo "$PROGNAME is a simple utility to identify the block device on which a file resides"
}

usageError() {
    if [ -z "$1" ]; then
    echo "$PROGNAME: error: incorrect usage" >&2
    else
    echo "$PROGNAME: error: incorrect usage: $1" >&2
    fi
    showUsage >&2
    exit 1
}

reportError() {
    echo "$PROGNAME: error: $1" >&2
    STATUS=1
}

reportFileError() {    
    echo "$1: error: $2" >&2
    STATUS=1
}

checkStatus() {
    RET=$?
    if [ $RET -ne 0 ]; then
    STATUS=$RET
    reportError "$1"
    exit $RET
    fi
}

while [ $# -gt 0 ]; do
   case "$1" in
   --)
      shift
      break;;
   --help)
      showHelp
      exit 0
      break;;
   --verbose)
      VERBOSE=1
      shift;;
   --*)
      usageError "unknown option \"$1\""
      shift;;
   *)
      break;;
   esac
done

FILE="$1"
if [ $VERBOSE -eq 1 ]; then
    echo FILE=$FILE
fi
FILE=`readlink -f $FILE`

if [ -z "$1" ]; then
    usageError "expected a filename"
    exit 1
elif [ ! -e $FILE ]; then
    reportFileError "$FILE" "file does not exist"
    exit 1
fi

FILESYSTEM=`findmnt -no source -T $FILE`
checkStatus "could not identify mount point"


if [ $VERBOSE -eq 1 ]; then
    echo FILESYSTEM=$FILESYSTEM
fi

FS=`basename $FILESYSTEM`
SYSLINE=`grep -rs $FS /sys/devices 2>/dev/null`
test ! -z "$SYSLINE" 
checkStatus "could not find device in /sys/devices"

if [ $FS == "fuse" ]; then
    reportFileError "$FILE" "is on a fuse filesystem"
    exit 1
fi

echo $SYSLINE | grep -q virtual
if [ $? -eq 0 ]; then
    LOGICALVOLUME=1
    if [ $VERBOSE -eq 1 ]; then
    echo "file is on a logical volume"
    fi
else
    LOGICALVOLUME=0

fi

DEVICENO=`lsblk | grep $FS | awk '{ print $2; }' | head -n 1`
checkStatus "could identify device number"
test ! -z $DEVICENO
checkStatus "could identify device number"

if [ $VERBOSE -eq 1 ]; then
    echo "Device number $DEVICENO"
fi

if [ $LOGICALVOLUME -eq 1 ]; then
    DEVDIR=`grep -rs ${DEVICENO}$ /sys/devices/ 2>&1`
    DEVDIR=`dirname $DEVDIR`    
    DEVICE=`ls $DEVDIR/slaves | head -n 1`
    if [ $VERBOSE -eq 1 ]; then
    echo DEVICE=/dev/$DEVICE
    fi
    DEVICENO=`lsblk | grep $DEVICE | awk '{ print $2; }' | head -n 1`
    checkStatus "could identify parent device number"
    if [ $VERBOSE -eq 1 ]; then
    echo "Parent Device number $DEVICENO"
    fi
fi
    
# The first grep does not like the first colon so we double grep
# Maybe a /sys pecularity?
DEVLINE=`grep -rs ${DEVICENO}$ /sys/devices/ 2>&1 | grep :${DEVICENO}`
checkStatus "could identify device from number in sys"

DEVICE=`echo $DEVLINE | sed -e s_.*/block/__ | cut -f 1 -d/`
if [ $VERBOSE -eq 1 ]; then
    echo -n "block device: "
fi
echo "/dev/$DEVICE"

exit $STATUS

这似乎适用于任何普通文件或目录,这里是一些示例输出。

其中/home是一个逻辑卷。

代码语言:javascript
运行
复制
>./getblkdev.sh --verbose /home
FILE=/home
FILESYSTEM=/dev/mapper/rhel-home
file is on a logical volume
Device number 253:2
DEVICE=/dev/sda2
Parent Device number 8:2
block device: /dev/sda

其中/boot是一个常规分区:

代码语言:javascript
运行
复制
>./getblkdev.sh --verbose /boot
FILE=/boot
FILESYSTEM=/dev/sda1
Device number 8:1
block device: /dev/sda

请建议改进意见或你自己的替代答案,无论是脚本,其他语言的程序,甚至伪代码与一个更好的计划。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72219414

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档