首页 > C/C++/Linux > 分区自动挂卸载2—-挂载和卸载模块的实现

分区自动挂卸载2—-挂载和卸载模块的实现

2009-06-04 17:51 星期四    浏览: 1,148    绿 发表评论 阅读评论
简述:根据”/proc/partitions”和”/proc/mounts”文件判断哪些分区还没挂载,然后创建挂载点,将其挂上;卸载时则检查是否在mounts文件中;若在,则umount, 并执行删除挂载点的操作。
主要用到的数据结构有Partion及其列表:
struct Partion{
char partionName[16];  //such as sdb, sdb1,sdb2, mmcblk0, mmcblk0p1,…
char partionNameAlias[6];//such as mmc, mmc1, …
char devNode[16];//such as /dev/sdb1, /dev/mmc1,…
char mntPoint[PATH_MAX];//such as /media/usb/sdb1, /media/sd/sd1,…
bool mounted;
};
vector<Partion*> partionList;
第一次遍历”/proc/partitions”文件,创建对象,初始化partionName 和 partionNameAlias 字段,检查哪些分区已经插上,并将其添加到list中去。第一次遍历的代码如下:
static bool firstParse()
{
FILE *fp = fopen(“/proc/partitions”, “r”);
if(fp == NULL)
{
fprintf(stderr, “firstParse: Read /proc/partitions failed!n”);
return false;
}
char tmp[256];
char buf[256];
 /* skip the first line */
fgets(tmp, sizeof(tmp), fp);
fgets(tmp, sizeof(tmp), fp);
char stream[300];
while (fgets(stream, sizeof(stream), fp))
{
sscanf(stream, “%s %s %s %s”, tmp, tmp, tmp, buf);
#ifdef MY_DEBUG
fprintf(stderr, “read /proc/partitions partion=%sn”, buf);
#endif
              if(strstr(buf, “sdb”)||strstr(buf, “sdc”)||strstr(buf, “mmcblk”))// construct sdb,sdc,mmcblk partions list
{
Partion* partion=new Partion();
//init partionName
                     strcpy(partion->partionName, buf);
//init partionNameAlias
if(strstr(buf, “mmcblk0″))
{
strcpy(partion->partionNameAlias, “mmc”);
if(strstr(buf, “mmcblk0p”))
{
char* tmp=buf;
strcat(partion->partionNameAlias, tmp+strlen(“mmcblk0p”));//such as mmc1, mmc2,…
}
}else
{
strcpy(partion->partionNameAlias, buf);
}
  partionList.push_back(partion);
}
}
fclose(fp);
return true;
}
第二次遍历”/proc/mounts”文件:检查哪些分区已经挂载上,初始化mounted, devNode, mntPoint三个字段:具体代码如下:
static bool secondParse()
{
FILE *fp = fopen(“/proc/mounts”, “r”);
if(fp == NULL)
{
fprintf(stderr, “secondParse: Read /proc/mounts failed!n”);
return false;
}
char buf[256];
char mnt[PATH_MAX];
char stream[300];
while (fgets(stream, sizeof(stream), fp))
{
sscanf(stream, “%s %s”, buf, mnt);
#ifdef MY_DEBUG
fprintf(stderr, “read /proc/muonts %s %sn”, buf, mnt);
#endif
unsigned int i=0;
for(i=0; i<partionList.size();i++)
{
 if(strstr(buf, partionList.at(i)->partionName)||strstr(buf, partionList.at(i)->partionNameAlias))//mounted
{
strcpy(partionList.at(i)->devNode, buf);
strcpy(partionList.at(i)->mntPoint, mnt);
partionList.at(i)->mounted=true;
}else
{
//init devNode
strcpy(partionList.at(i)->devNode, “/dev/”);
strcat(partionList.at(i)->devNode, partionList.at(i)->partionNameAlias);
//init mntPoint
if(strstr(partionList.at(i)->partionName, “mmcblk”))
{
strcpy(partionList.at(i)->mntPoint, “/c2-media/sd/”);
strcat(partionList.at(i)->mntPoint, partionList.at(i)->partionNameAlias);
}else
{
strcpy(partionList.at(i)->mntPoint, “/c2-media/usb/”);
strcat(partionList.at(i)->mntPoint, partionList.at(i)->partionNameAlias);
}
partionList.at(i)->mounted=false;
}
}//for
}
fclose(fp);
return true;
}
将二者和到一块就是一个完整的构建列表的操作:
static bool updatePartionListInfo()
{
resetPartionListInfo();
if(firstParse()&&secondParse())
{
#ifdef MY_DEBUG
printPartionListInfo();
#endif
return true;
}
return false;
}
于是挂载USB分区可以如下实现:
bool mountUSBPartions()
{
if(!updatePartionListInfo())
return false;
bool flag=true;
unsigned int i=0;
for(i=0; i<partionList.size();i++)
{
                if((!partionList.at(i)->mounted) && (strstr(partionList.at(i)->partionName, “sdb”)||strstr(partionList.at(i)->partionName, “sdc”)))
{
if(checkPartionNumbers(“sdb”)>0||checkPartionNumbers(“sdc”)>0)
{
if((checkPartionNumbers(“sdb”)>1 && !strcmp(partionList.at(i)->partionName, “sdb”))
||(checkPartionNumbers(“sdc”)>1 && !strcmp(partionList.at(i)->partionName, “sdc”)) )
continue;
if (createMntPoint(partionList.at(i)->mntPoint))
                                        flag &=mount(partionList.at(i)->devNode, partionList.at(i)->mntPoint);
else
flag= false;
}
}
}
resetPartionListInfo();
return flag;
}
挂载MMC设备的操作是:
bool MountUtil2::mountMMCPartions()
{
if(!updatePartionListInfo())
return false;
bool flag=true;
unsigned int i=0;
for(i=0; i<partionList.size();i++)
{
              if((!partionList.at(i)->mounted) && (strstr(partionList.at(i)->partionName, “mmcblk”)))
              {
if(checkPartionNumbers(“mmcblk”)>0)
{
if(checkPartionNumbers(“mmcblk”)>1 && !strcmp(partionList.at(i)->partionName, “mmcblk0″))
continue;
if (createMntPoint(partionList.at(i)->mntPoint))
flag &=mount(partionList.at(i)->devNode, partionList.at(i)->mntPoint);
else
flag=false;
}
}
}
resetPartionListInfo();
return flag;
}
其中static int checkPartionNumbers(const char* dev)是检查该盘有几个分区;若有多个分区时,第一个往往是磁盘设备,后面的才是分区,需要挂载。
createMntPoint是创建挂载点函数:
static bool createMntPoint(const char* mntPoint)
{
struct stat fileStat;
if(-1 == stat(mntPoint, &fileStat))
if(mkdir(mntPoint, S_IRWXU|S_IRWXG|S_IRWXO))
{
fprintf(stderr, “nCreate mount point %s failed! n”, mntPoint);
return false;
}else
DirCreatedOrRemoved(mntPoint, true);
return true;
}
真正具体的mount操作在函数mount中,它使用了一个非常愚笨的办法,一个个尝试使用了什么样的文件系统格式:
bool mount(const char*devNode, const char* mnt)
{
// rest = mount(c_devNode, c_dir, “vfat”, MS_SYNCHRONOUS|MS_DIRSYNC, 0);
char cmd[1024];
//sprintf(cmd,”mount -t vfat -o umask=000,noatime,async,codepage=936,iocharset=gb2312 %s  %s “, devNode, mnt);
sprintf(cmd,”mount -t vfat  %s  %s “, devNode, mnt);
#ifdef MY_DEBUG
fprintf(stderr,”n Try to use first mount cmd: %sn”, cmd);
#endif
int rest=system(cmd);
if(!rest)
return true;
else
{
sprintf(cmd,”mount -t  auto  %s  %s “,  devNode, mnt);//try to use other filesysem type
#ifdef MY_DEBUG
fprintf(stderr,”n Try to use second mount cmd: %sn”, cmd);
#endif
rest=system(cmd);
}
if(!rest)
return true;
else
{
//execl(“/home/work/ntfs-3g”, “ntfs-3g”, devNode, mnt,”-o”, “force,locale=zh_CN.UTF-8″,NULL);
//ntfs-3g /dev/sdd1 /mnt/usb
sprintf(cmd,”ntfs-3g   %s  %s “,  devNode, mnt);
#ifdef MY_DEBUG
fprintf(stderr,”n Try to use third mount cmd: %sn”, cmd);
#endif
rest=system(cmd);
}
if(!rest)
return true;
else{
#ifdef MY_DEBUG
fprintf(stderr,”n  Erro Code: %dn”, rest);
#endif
rmdir(mnt);
return false;
}
}
卸载分区则使用下面的函数,它使用特征字符去遍历检查文件/proc/mounts,在其里面则执行卸载操作:
bool MountUtil2::umountPartions(const char* devNode)
{
bool flag=false;
FILE *pfile = fopen(“/proc/mounts”, “r”);
if(!pfile)
{
fprintf(stderr, “unmount: Read /proc/mounts failed!n”);
return false;
}
char partitionDevPath[40];
char mountPoint[256];
char stream[300];
while (fgets(stream, sizeof(stream), pfile))
{
sscanf(stream, “%s  %s”, partitionDevPath, mountPoint);
if(strstr(partitionDevPath, devNode)==partitionDevPath)
{
char cmd[512];
sprintf(cmd,”umount %s “,  partitionDevPath );
if(system(cmd))
{
fprintf(stderr, “Umount %s Failed!n”,  partitionDevPath);
flag=false;
}
else
{
//remove the mnt point
if(rmdir(mountPoint))
fprintf(stderr, “rm %s mntpoint failed!n”, mountPoint);
//TODO: tell system refresh filesystem
else
DirCreatedOrRemoved(mountPoint, false);
flag=true;
}
}
}
fclose(pfile);
return flag;
}
每次挂载时还要清除原来遗留下来(因为某些原因未被清除)的挂载点目录:
void cleanObsoleteMntPoints(const char* parentDir)
{
DIR *dp = opendir(parentDir);
if (dp)
{
struct dirent *ep;
while( (ep =readdir(dp) ) != NULL )
{
if (0 != strcmp(ep->d_name, “.”) && 0 != strcmp(ep->d_name, “..”))
{
char mountPointPath[PATH_MAX];
strcpy(mountPointPath, parentDir);
strcat(mountPointPath, “/”);
strcat(mountPointPath, ep->d_name);
umount(mountPointPath);
if(!isMntPoint(mountPointPath))
if(rmdir(mountPointPath))
fprintf(stderr, “rm %s mntpoint failed!n”, mountPointPath);
}
}//while
closedir(dp);
}
}
其中isMntPoint用于检查该路径下是否还有挂载的分区,只有没有时才可以清除:
static bool isMntPoint(const char* dir)
{
FILE *pfile = fopen(“/proc/mounts”, “r”);
char partitionDevPath[40];
char mountPoint[256];
bool flag=false;
if(!pfile)
return true;//for safe, we cannot delete the unconfirmed dir
char stream[300];
while (fgets(stream, sizeof(stream), pfile))
{
sscanf(stream, “%s  %s”, partitionDevPath, mountPoint);
if(strstr(mountPoint, dir)==mountPoint)
flag=true;
}
fclose(pfile);
return flag;
}

本文链接地址: http://blog.redwolf-soft.com/?p=573

原创文章,版权©红狼博客所有, 转载随意,但请注明出处。

    分享到:

相关文章:

  • 无相关文章
分类: C/C++/Linux 标签:
  1. 本文目前尚无任何评论.
  1. 本文目前尚无任何 trackbacks 和 pingbacks.
订阅评论
  欢迎参与讨论,请在这里发表您的看法、交流您的观点。