前言
最近一直在使用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 | int mount(const char *source, const char *target, |
说明:
- source – 表示需要挂载的设备或者目录;
- target – 表示目标挂载点(一个目录,比如/mnt/test_nfs);
- filesystemtype – 表示需要挂载的文件系统类型,比如”ext2”, “ext3”, “jfs”, “xfs”, “nfs”等,我们这里是”nfs”;
- mountflags – 表示用来控制mount行为的标识掩码;
- data – 依据挂载的文件系统类型,指定相关的挂载选项;
看上去很简单就可以完成,比如我们这样:
1 | if (mount("10.10.123.101:/vbumjko7", "/mnt/test_nfs", "nfs", 0, "vers=3,nolock,proto=tcp") == -1) |
编译运行,意想不到的输出:
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 | if (mount("10.10.123.101:/vbumjko7", "/mnt/test_nfs", "nfs", 0, "vers=3,nolock,proto=tcp,addr=10.10.123.101") == -1) |
编译运行,啊哈,挂载成功!
至此问题解决。
附录
附上测试代码如下:
1 |
|