0%

如何使用系统调用mount挂载NFS

前言

最近一直在使用NFS做一些开发和测试,功能开发完毕后,需要对NFS的可用性做一些监控,没有使用crontab+shell脚本的方式,总觉得这么做的都是临时方案,不成体系,所以就基于现有的框架写了一个轻量级的服务。具体的监控事项包括NFS的挂载和卸载、基本的读写、剩余空间等,发现异常后给出告警提示。基本的功能比较简单,但是在开发的时候却遇到一个问题:
在C++代码中,如何使用系统调用mount()来挂载NFS?

讨论

我们都知道,在Linux命令行下,使用系统工具mount可以很简单的完成这个事情:

1
mount -t nfs 10.10.123.101:/vbumjko7 -o "vers=3,nolock,proto=tcp"

但是在C++代码中怎么搞呢?方法大致如下:

  • 调用system执行mount命令
  • 调用popen执行mount命令
  • 调用系统API函数mount()

探索

system和popen的方式都是起子进程执行shell命令来完成挂载任务,这样本质上跟直接使用shell命令没有区别,且实现上比shell更复杂(你还要编译、调试),所以不会采用。
使用mount API怎么做呢?man了一下mount,原型如下:

1
2
3
int mount(const char *source, const char *target,
const char *filesystemtype, unsigned long mountflags,
const void *data);

说明:

  • source – 表示需要挂载的设备或者目录;
  • target – 表示目标挂载点(一个目录,比如/mnt/test_nfs);
  • filesystemtype – 表示需要挂载的文件系统类型,比如”ext2”, “ext3”, “jfs”, “xfs”, “nfs”等,我们这里是”nfs”;
  • mountflags – 表示用来控制mount行为的标识掩码;
  • data – 依据挂载的文件系统类型,指定相关的挂载选项;

看上去很简单就可以完成,比如我们这样:

1
2
3
4
if (mount("10.10.123.101:/vbumjko7", "/mnt/test_nfs", "nfs", 0, "vers=3,nolock,proto=tcp") == -1)
{
printf("ERROR: mount failed: %s \n", strerror(errno));
}

编译运行,意想不到的输出:

1
ERROR: mount failed: Invalid Argument

参数都是根据手册填的,哪里出错了呢?

解决

谷歌找一下,发现在stackoverflow上有一个一样的问题:NFS mount System Call in linux
答主的意思是:

首先,对于没有看到任何关于使用mount调用来挂载nfs的手册表示诧异。然后,深入到mount工具的源码实现,发现在挂载nfs时,解析对应的nfs挂载选项中有个Opt_addr,该字段对应挂载选项中的addr选项。为了使mount函数正常运行,应该在挂载选项中添加addr=x.x.x.x;

原因很明显了,我们缺少了must选项addr,修改代码,添加该选项后,代码为:

1
2
3
4
if (mount("10.10.123.101:/vbumjko7", "/mnt/test_nfs", "nfs", 0, "vers=3,nolock,proto=tcp,addr=10.10.123.101") == -1)
{
printf("ERROR: mount failed: %s \n", strerror(errno));
}

编译运行,啊哈,挂载成功!
至此问题解决。

附录

附上测试代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <sys/mount.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>

int main()
{
const char* src = "10.10.123.101:/vbumjko7";
const char* trgt = "/mnt/test_nfs";
const char* type = "nfs";
const unsigned long mntflags = 0;
const char* opts = "vers=3,nolock,proto=tcp,addr=10.10.123.101";

int result = mount(src, trgt, type, mntflags, opts);

if (result == 0)
{
printf("Mount created at %s...\n", trgt);
printf("Press <return> to unmount the volume: ");
getchar();
umount(trgt);
}
else
{
printf("Error : Failed to mount %s\n"
"Reason: %s [%d]\n",
src, strerror(errno), errno);
return -1;
}

return 0;
}

参考链接

如果对您有帮助