我想使用 C++ 挂载文件系统。我应该使用
mount()
系统调用,还是只执行 mount
二进制文件?
显然,系统调用会更快,而且我将浪费更少的时间来构建命令行参数和解析错误消息等。然而,读过
mount(2)
后,我不清楚这些论点有什么限制(如果有的话)。
我特别希望能够挂载磁盘映像文件以及实际的物理磁盘。我还希望能够通过指定距设备/映像开头的偏移量来挂载单个文件系统。我不知道您是否可以通过一次调用
mount()
来做到这一点,或者您是否需要先手动创建循环设备。 (我也不知道创建一个循环设备有多难 - 我假设这相当容易......)
如果正确设置这些东西相当复杂,那么调用
mount
二进制文件可能会更简单、更容易。但如果只是一个系统调用,直接调用 mount()
似乎更干净。那么哪一个可能给我带来的问题最少?
好吧,Nayden 建议跑步
strace mount
,这不是一个坏主意。
完成此操作后,看来
mount
正在做大量地狱的工作。看起来它确实创建了一个循环设备并安装了它。 (这意味着它需要找出下一个未使用的循环设备号是什么,等等)听起来您可能还需要手动找出文件系统类型。
简而言之,在我看来,对
mount
二进制文件的一次简单调用可能比尝试重新创建程序所做的一切要少得多。我原以为智能在内核中,但显然不是。
系统调用mount():
优点:
- 非阻塞(即您的进程仍然响应)。
- 更快,因为您不需要花时间创建新进程、线程。
缺点:
- 您需要指定文件系统类型、挂载标志、数据(某些文件系统使用的一些特殊内容,可能为 NULL)。
- 您可以挂载图像文件,但需要注意拥有空闲的循环设备并将其与您的图像相关联。
- 看看你的代码是否需要覆盖所有可能的用例,你可能会以自己编写的挂载工具结束:)
安装工具:
优点:
- 更易于使用,因为默认情况下需要指定的参数较少。
- 无需创建循环设备,将其与图像关联等(在安装图像的情况下)。
缺点:
- 当通过系统、fork-exec 等从 C++ 代码调用挂载工具时,如果使用 wait(),您的进程将被阻塞。某些应用程序对此类块很敏感(即有人可能依赖您的应用程序并等待答案,而安装正在进行中)
如果您对如何通过挂载系统调用挂载映像感兴趣,这里有一个简单的概念证明,基于:
http://man7.org/linux/man-pages/man4/loop.4.html
https://linux.die.net/man/2/mount
请注意不要在生产中使用此类代码,因为没有对返回值、异常等进行单一检查:)。无论如何,它可以编译并在我的机器上运行。应该用 root 运行。
#include <sys/mount.h> //mount
#include <sys/ioctl.h> //ioctl
#include <sys/stat.h> //open
#include <linux/loop.h> //LOOP_SET_FD
#include <fcntl.h> //open
#include <cstdio> // declaration of ::fileno
#include <cstdint> //int32_t
#include <sstream> //std::stringstream
#include <string>
constexpr char IMAGE_NAME[] = "image.img"; //of course we need this file to be present in same folder as built tool
constexpr char MOUNT_POINT[] = "/tmp/image_mnt"; //of course we need this folder already created
constexpr char FILESYSTEM_TYPE[] = "ext4";
constexpr char DEV_LOOP_CONTROL[] = "/dev/loop-control";
constexpr char DEV_LOOP_PREFIX[] = "/dev/loop";
constexpr int32_t MOUNT_FLAGS = MS_RDONLY;
int main()
{
const auto loop_control = std::fopen(DEV_LOOP_CONTROL, "r");
const auto loop_control_fd = fileno(loop_control);
const auto devnr = ioctl(loop_control_fd, LOOP_CTL_GET_FREE);
std::stringstream loopname;
loopname << DEV_LOOP_PREFIX << devnr;
const auto loop_device_name = loopname.str();
const auto loop_device = std::fopen(loop_device_name.c_str(), "r");
const auto loop_device_fd = fileno(loop_device);
const auto image = std::fopen(IMAGE_NAME, "r");
const auto image_fd = fileno(image);
//Associate the loop device with the open file whose file descriptor is passed as the (third) ioctl(2) argument.
ioctl(loop_device_fd, LOOP_SET_FD, image_fd);
const auto result = mount(loop_device_name.c_str(), MOUNT_POINT, FILESYSTEM_TYPE, MOUNT_FLAGS, NULL);
ioctl(loop_device_fd, LOOP_CLR_FD, 0);
return result;
}
我的建议是使用系统调用。 如果您想知道需要进行的确切调用,请通过 strace 或 gdb 下的 shell 运行 mount。