Linux下C语言判断samba服务器是否mount成功

最新的项目需要向网络共享服务器定时上传资料。但是客户的网络环境不知道咋配的,mount的执行总是有延时,并且还经常掉线。所以在上传文件之前我必须判断mount的目录是否是一个samba共享目录。
在我的环境下,这个共享文件夹是/mnt/smb/。这个文件夹有如下特性:
1:如果mount成功,它就是共享服务器的根文件夹,否则只是一个普通的Linux文件夹。
2:如果启动时网络有问题,那么fstab的自动mount(cifs方式)会执行失败。
3:fstab不归我管,也就是我没有改变mount时机的权力。
4:如果启动时网络没有问题,而后来断网,那么这个文件夹的仍旧处于挂载状态。所以使用mount命令是走不通的。
查找资料以后,我决定采用ping+判断文件夹文件系统的方法,来判断文件夹是否已经被mount。

用ping命令结合popen函数判断网络情况

断网是mount失败的充分非必要条件。之所以要先判断网络联通情况,是因为如果网络是中途切断的,cifs有一个180秒的漫长等待时间。此期间去调用(网络文件夹)的文件系统,也会等到cifs判断网络切断的时间点,才返回一个“网络临时切断”的errno(具体值忘了)。而这个cifs的等待时间以后,再去取网络文件夹的文件系统,就会立即返回Host挂了的errno(具体值也忘了)了。
为了节省这个最多达到180秒的时间,我ping一下不就行了。当然,如果服务器把ICMP给封了,当我没说。

static int ping_server(const char* ip_addr)
{
    int ret = 0;
    if (!ip_addr)
    {
        return ret;
    }
    char buffer[1024] = {0};
    char str_cmd[MAX_PATH] = {0};
    sprintf(str_cmd, "ping -c 1 -W 2 %s", ip_addr);
    FILE* pipe = popen(str_cmd, "r");
    if (!pipe)
    {
        printf("exec ping popen failed. ERROR:%d:%s", errno, strerror(errno));
        return ret;
    }
    sleep(1);
    int rd = fread(buffer, 1, 1024, pipe);
    if (rd <=0)
    {
        printf("exec ping timeout.");
    }
    else if( NULL != strstr( buffer, "ttl=" ) )
    {
        ret = 1;
    }
    pclose(pipe);
    return ret;
}

popen函数是个挺有趣的函数,它在stdio.h里就有。作用是起一个process来执行shell命令。跟system相比,它的等待过程更灵活,获取命令在屏幕上的输出内容也更方便。
这里的fread有点魔性。因为我写的ping命令配合参数,意思是ping一次,等待2秒。而我在fread之前只等了1秒。这样,如果断网,我在等待1秒后读取的屏幕内容为空,便可以立刻返回,而不必等待整个ping命令结束。判断接通就很简单了,看输出的内容里有没有“ttl=”的文字,常规操作。

用statfs函数判断文件夹文件系统属性

这个函数用起来就有点麻烦了。
首先要引一个系统头文件“sys/vfs.h”。然后里面那些相貌清奇的文件系统的宏定义被一层一层引用,很难找。于是我索性自己重新定义了一下,好孩子千万不要学。
文档在这里

#include <sys/vfs.h>
#ifndef SMB2_MAGIC_NUMBER
#define SMB2_MAGIC_NUMBER     0xfe534d42
#endif
static int is_smb_fs(void)
{
    struct statfs fs;
    int ret = statfs("/mnt/smb", &fs);

    if (0 == ret && (SMB2_MAGIC_NUMBER == fs.f_type))
    {
        printf(   "check smb dir [mnt/smb] ret = %d status = %llx", ret, fs.f_type);
        return 1;
    }
    return 0;
}

将上面两个函数封装成进一个函数

static int is_smb_folder_connected(const char* ip_addr)
{
    if (ping_server(ip_addr))
    {
        return is_smb_fs();
    }
    return 0;
}

main函数略。
收工。

已有6条评论

  1. 能提高效率减少等待时间都是极好的

  2. 会写点代码能省略掉很多无用工作。

    1. 写代码就是我的工作。

  3. 有过一模一样的需求,但是我的场景逗逼得多。

    启动时网络是崩的,因为我们定制的系统自己写ifcfg,启动时是空白的,所以不关心fstab,都是后天mount。
    写C的大神在被mount的目录下搞了个文件,每次调用文件夹的时候去试读这个文件,成功了那就是成功mount,失败了那就是没mount上。
    然后狠奇妙的这个文件被操作系统给缓存了,只要/mnt/smb/存在且被mount过,那即便断网了,也能读,于是每天上演奇幻情况。
    ping的办法也试过,问题是对面那个samba服务是我们自己魔改的,会崩会僵死会超时。

    然后我出了个极其弱智但能用的办法:每次要用对面这个samba服务之前,都umount再mount一遍……

  4. 离开技术行业很久了,今天在博客志上看到你的站,想起了上班的日子。

  5. 好多年不写c 代码了。

你好,新朋友。留言前请先填写昵称邮箱