MathematicalOrchid
MathematicalOrchid

Reputation: 62818

Should I use mount() or /usr/bin/mount

I want to mount a filesystem using C++. Should I use the mount() system call, or just execute the mount binary?

Obviously a system call is going to be faster, and I'm going to waste less time building command-line arguments and parsing error messages and stuff. However, having read mount(2), it is unclear to me what restrictions (if any) there are on the arguments.

I particularly want to be able to mount disk image files as well as actual physical disks. And I also want to be able to mount individual filesystems by specifying an offset from the start of the device / image. I don't know whether you can do that with a single call to mount(), or whether you would need to manually create loop devices first. (I also don't know how hard it is to create a loop device — I presume it's fairly easy...)

If setting this stuff up right is fairly complicated, then it's probably simpler and easier to call the mount binary. But if it's just one system call, calling mount() directly seems cleaner. So which one is likely to give me the fewest problems?

Upvotes: 1

Views: 1455

Answers (3)

Serhii Karasov
Serhii Karasov

Reputation: 41

System call mount():
pros:
- non blocking(i.e. your process is still responsive).
- kind of faster, as you don't spend time on creation of new process, thread.
cons:
- you need to specify the filesystem type, mount flags, data(some special stuff used by some filesystems, maybe NULL).
- you can mount image file, but there is a necessity to take care about having free loop device and associating it with your image.
- looks if your code need to cover all possible use cases, you may end with self-written mount tool :)

Mount tool:
pros:
- easier to use, as less arguments need to specify by default.
- no need to create loop device, associate it with image, etc(in case of image mount).
cons:
- when it goes about calling mount tool from c++ code via system, fork-exec etc, your process will be blocked, if wait() would be used. Some applications are sensible to such block(i.e. somebody may depend on your application and wait for answer, while mount would be in progress)

If you are interested in how to mount image via mount system call, here is a simple proof of concept, based on:
http://man7.org/linux/man-pages/man4/loop.4.html
https://linux.die.net/man/2/mount
Be aware not to use such code in production, as there is no single check on return values, exceptions etc :). Anyway it compiles, and works on my machine. Should be ran with 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;
}

Upvotes: 1

MathematicalOrchid
MathematicalOrchid

Reputation: 62818

Well, Nayden suggested running strace mount, which isn't a bad idea.

Having done this, it appears that mount is doing a hell of a lot of work. It looks like it does create a loop device and mount that. (Which means it needs to figure out what the next unused loop device number is, etc.) It sounds like you may also need to manually figure out the filesystem type.

In short, it looks to me like one simple call to the mount binary is probably going to be far less work than trying to recreate everything that program does. I had thought the intelligence is in the kernel, but apparently not.

Upvotes: 1

Nayden Dochev
Nayden Dochev

Reputation: 58

My advice is use the system call. If you want to know the exact call you need to make, run mount via the shell under strace or gdb.

Upvotes: 0

Related Questions