到目前为止,我使用了四种方式卸载挂载点。第一种是使用system函数,但是没法获取umount失败时的字符串,比如说device is busy。第二种方式是使用系统函数umount,虽然可以得到设备忙的错误码,但是不能清楚系统文件/etc/mtab的记录。第三种方式是使用popen函数(参数1是“umount /mnt/wzhwho”,参数2是“r”),但是卸载挂载点失败时还是不能获取到字符串。第四种是使用pipe函数,fork函数和execlp函数,实现了我期望的效果。但是我不明白第三种方式为什么不行?
第三种和第四种的源程序如下:
#define BUFFER_LEN 1023
#define MOUNT_POINT "/mnt/wzhwho"
# ifndef errno
extern int errno;
# endif
int main(void)
{
int32_t ret = 0;
uint32_t retval = 0;
int32_t fd[2];// 创建管道返回的文件描述符
int32_t status_child = 0;
int32_t childpid = 0; // 子进程pid
int length = 1;
unsigned int chars_read = 0;
char *buf = NULL;
char *tmp = NULL;
char read_buf[BUFFER_LEN + 1] = {0};
// 调用pipe建立管道
ret = pipe(fd);
if (0 != ret)
{
// 打印创建管道失败
retval = errno;
printf("Failed to pipe: %s/n", strerrno(errno));
return retval;
}
// 调用vfork创建新进程,并获取pid
childpid = vfork();
if (0 == childpid)
{
/*========= 进入子进程处理流程 ========*/
// 关闭管道读取端
if ( 0> (ret = close(fd[0])))
{
printf("Failed to close file: %s/n",strerrno(errno));
}
// 将标准输出定向到管道写入端
if (0 > (ret = dup2(fd[1],STDOUT_FILENO)))
{
printf("Failed to dup2: %s/n",strerrno(errno));
}
// 将标准错误输出定向到管道写入端
if (0 > (ret = dup2(fd[1],STDERR_FILENO)))
{
printf("Failed to dup2: %s/n",strerrno(errno));
}
//执行命令
ret = execlp("umount","umount", MOUNT_POINT, (char *)0);
if (-1 == ret)
{
printf("Failed to execvp: %s/n",strerrno(errno));
}
// 退出子进程
exit(EXIT_FAILURE) ;
// 成功执行后不返回
}
else if(-1 == childpid)
{
retval = build_retval(errno);
/* 打印fork子进程出错 */
if ( 0> (ret = close(fd[1])))
{
printf("Failed to close file: %s/n",strerrno(errno));
}
if ( 0> (ret = close(fd[0])))
{
printf("Failed to close file: %s/n",strerrno(errno));
}
return retval;
}
// 关闭管道写入端
if ( 0> (ret = close(fd[1])))
{
printf("Failed to close file: %s/n",strerrno(errno));
}
/*==========父进程处理流程 ============*/
// 读取子进程信息
memset(read_buf,0, sizeof(read_buf));
chars_read = read(fd[0],read_buf, sizeof(read_buf) -1);
// 循环的读通道信息,直到读完
while(chars_read > 0)
{
tmp = realloc(buf,(unsigned int)(length + (int)chars_read));
// 分配空间失败
if(NULL == tmp)
{
printf("Fail to realloc: %s/n",strerrno(errno));
if(buf != NULL)
{
free(buf);
}
return -1;
}
buf = tmp;
strncpy(buf+length-1,read_buf,chars_read);
length = length+(int)chars_read;
buf[length-1] = 0;
chars_read = read(fd[0],read_buf, sizeof(read_buf) -1);
}
// 关闭管道读端
if ( 0> (ret = close(fd[0])))
{
printf("Failed to close file: %s/n",strerrno(errno));
}
// 调用waitpid等待子进程返回 */
waitpid(childpid,&status_child,0);
// 调用WIFEXITED判断子进程的返回状态字是可以访问的
if (!WIFEXITED(status_child))
{
// 状态字不可访问信息
if ( 0> (ret = close(fd[0])))
{
printf("Failed to close file: %s/n",strerrno(errno));
}
return -1;
}
// 取得进程结束返回值
if (WEXITSTATUS(status_child))
{
//判断管道中的数据是否带有busy
if(buf != NULL)
{
tmp = NULL;
printf("buf = %s/n", buf);
if((tmp = strstr(buf, "busy")) != NULL)
{
printf("Fail to umount %s : device is busy/n", MOUNT_POINT);
}
free(buf);
}
// 子进程退出异常
printf("Fail to umount %s/n", MOUNT_POINT);
return -1;
}
exit(EXIT_SUCCESS);
}
/*******************************************************************************
*
* 卸载挂载点失败时获取字符串(popen)
*
*******************************************************************************/
int main()
{
FILE *fp;
int length = 1;
unsigned int chars_read = 0;
char *buf = NULL;
char *tmp = NULL;
char read_buf[BUFFER_LEN + 1] = {0};
char cmd[BUFFER_LEN + 1] = {0};
uint32_t ret = 0;
snprintf(cmd,sizeof(cmd),"umount %s",MOUNT_POINT);
fp = popen(cmd, "r");
if(NULL == fp)
{
printf("Fail to popen: %s/n", strerrno(errno));
return -1;
}
else
{
memset(read_buf, 0, sizeof(read_buf));
chars_read = fread(read_buf, sizeof(char), BUFFER_LEN, fp);
// 读信息失败
if(chars_read == 0)
{
printf("Failed to read message./n");
pclose(fp);
return -1;
}
// 循环的读通道信息,直到读完 */
while(chars_read > 0)
{
tmp = realloc(buf,(unsigned int)(length + (int)chars_read));
// 分配空间失败
if(NULL == tmp)
{
printf("Fail to realloc./n");
if(buf != NULL)
{
free(buf);
}
return -1;
}
buf = tmp;
strncpy(buf+length-1,read_buf,chars_read);
length = length+(int)chars_read;
buf[length-1] = 0;
chars_read = fread(read_buf, sizeof(char), BUFFER_LEN, fp);
}
pclose(fp);
}
//判断管道中的数据是否带有busy
if(buf != NULL)
{
tmp = NULL;
printf("buf = %s/n", buf);
if((tmp = strstr(buf, "busy")) != NULL)
{
printf("Fail to umount %s : device is busy/n", MOUNT_POINT);
}
free(buf);
return -1;
}
exit(EXIT_SUCCESS);
}