linux 移动存储设备弹出操作详解
本文开发环境搭建:
库名 | deb系 | rpm系 |
---|---|---|
glib2/gio | apt install libglib2.0-dev | yum install glib2-devel |
1、基础信息简述:
1、常见的移动存储设备有:udisk(U盘)、DVD(光盘)、Mobile Hard disk(移动硬盘)
2、选择udisk为例,一个udisk实物在操作系统层面可以抽象出三个对象:Drive(驱动)、Mount(挂载点)、Volume(卷设备)
3、使用lsblk
命令可以看到系统的磁盘信息,如果某个设备已经弹出,那么它的/dev
设备是存在的,但是lsblk不会显示。
简单一句:linux内核肯定有处理udisk的驱动,驱动再可以检测是否存在卷设备,再者就是卷设备是否已经挂载、以及挂载点信息。
2、Mobile Hard disk的特殊之处
假设某个移动硬盘的设备是/dev/sdb1,它的挂载点是/media/user/aaa
1、如果是udisk设备,我们用以下2个命令均可以弹出udisk,但是运行命令后移动硬盘只会卸载,不会弹出
sudo eject /dev/sdb1
sudo eject /media/user/aaa
2、但是如果使用linux的文件管理器 右键菜单中的弹出按钮,发现移动硬盘可以弹出成功
3、原因(移动硬盘弹出原理):文件管理器内部处理移动设备的弹出操作时,udisk与DVD均是操作的Volume
,但是移动硬盘操作的是Drive
,移动硬盘需要关闭它的驱动连接
才能真正的弹出它。
3、代码理论铺垫
1、在上述论据的基础上,我们将udisk与DVD分为一类,将移动硬盘单独分为一类
,读者会问:代码中怎么区分这2类设备?
2、针对移动硬盘的特殊性质,我们可以使用如下函数进行区分
gboolean g_drive_can_eject(GDrive* drive) //udisk与DVD使用该函数即可判断是否可弹出
gboolean g_drive_can_stop(GDrive* drive) //移动硬盘使用该函数即可判断其Drive是否可停止
3、系统每插入一个移动设备,均会存在一个对应的computer:///xxx.drive
的文件,我们使用该文件比较udisk与移动硬盘的不同点(以开机后再插入设备为例)
4、Mobile Hard disk的特殊之处2
事实证明,存在2种情况:
- 开机后插入移动硬盘,针对移动硬盘使用g_drive_can_stop()返回TRUE。
- 开机前插入移动硬盘,针对移动硬盘使用g_drive_can_stop()返回FALSE
大胆猜测与分析:
1、移动硬盘的驱动确实与其他移动存储设备的驱动有所不同,导致开机前插入的话会被默认当作系统硬盘而不是移动盘
2、该特殊问题如何解决?我猜测该问题目前应该无解或者触及了知识盲区。
5、C代码实例
1、代码逻辑讲解:
- 代码内的 xxx.drive 是
gvfs-ls computer:///
命令的结果,这个文件是插入的udisk与移动硬盘在内存中的一种表示方式(linux一切皆文件的道理?) - GMainLoop g_main_loop_new(GMainContext,gboolean) 和 void g_main_loop_run(GMainLoop*) 分表表示创建和运行一个主循环,类似于守护进程的概念。
- 增加主循环主要是为了保证glib2/gio API能够成功执行完成,保证用户能看到期待的结果,因为
我们的程序是单线程的,而glib2库全部的回调函数均是通过信号触发的
- func() 内部对udisk与移动硬盘的弹出均做了处理,读者只需要插入移动存储设备后将代码内的xxx.drive替换为gvfs-ls computer:///命令的某个结果,重新编译运行即可。
2、代码分块
1)功能代码 (if 和else if两个不同的分支分别处理udisk与移动硬盘设备)
void func(){gboolean canEject,canStop;//布尔变量,取值TRUE或FALSEchar *devFile;//GFile *file = g_file_new_for_uri("computer:///Kingston DataTraveler 3.0.drive");//创建金士顿设备文件对象GFile *file = g_file_new_for_uri("computer:///S5170-25 6.drive");//创建移动硬盘设备文件对象GFileInfo *fileInfo = g_file_query_info(file,"mountable::*", /*查询挂载相关的所有信息*/G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,//不允许符号链接NULL,NULL);//查询具体属性值canEject = g_file_info_get_attribute_boolean(fileInfo, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_EJECT);//可弹出属性canStop = g_file_info_get_attribute_boolean(fileInfo, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_STOP); //可停止属性if(canEject) //如果可以弹出则正常弹出设备,udisk一般走这个分支g_file_eject_mountable_with_operation(file,G_MOUNT_UNMOUNT_NONE,NULL,NULL,NULL,NULL);else if(canStop){ //如果不可以正常弹出则尝试通过停止驱动的方式来弹出设备,移动硬盘一般走这个分支devFile = g_file_info_get_attribute_as_string(fileInfo, G_FILE_ATTRIBUTE_MOUNTABLE_UNIX_DEVICE_FILE);//查询驱动设备对应的dev设备文
件if(devFile){ejectDeviceByStopDrive(devFile);//停止驱动以达到弹出的效果g_free(devFile);}}g_object_unref(file); //释放节点内存g_object_unref(fileInfo);
}
2)弹出指定/dev设备(这个代码主要是供移动硬盘使用的)
/* 通过停止驱动来弹出设备* @devFile 需要弹出的设备,如/dev/sdb1*/
void ejectDeviceByStopDrive(const char* devFile){GDrive* drive = getDriveFromSystem(devFile);//获取驱动if(!drive)return;if(g_drive_can_stop(drive)) //驱动是否可以停止g_drive_stop(drive,G_MOUNT_UNMOUNT_NONE,NULL,NULL,NULL,NULL);//停止驱动g_object_unref(drive); //释放节点内存
}
3) 从系统磁盘监视器获取指定/dev设备的驱动
/* 从系统中获取指定设备的驱动* @devFile 如/dev/sdb1* @return @devFile在内存中对应的驱动对象*/
GDrive* getDriveFromSystem(const char* devFile){GVolumeMonitor *monitor = g_volume_monitor_get(); //系统磁盘监控器if(!monitor)return NULL;GList *allVolumes = g_volume_monitor_get_volumes(monitor); //获取所有已连接的卷设备if(!allVolumes)return NULL;GList *l; //glib2库的链表结构体GVolume *volume;//glib2库的卷设备结构体GDrive *drive; //glib2库的驱动结构体const char *devPath;for(l = allVolumes; l != NULL; l = l->next){volume = l->data;//链表节点的数据域存放的是GVolume*对象devPath = g_volume_get_identifier(volume,"unix-device");//获取卷设备对象的dev设备标识符if(devPath && !strcmp(devFile,devPath)){drive = g_volume_get_drive(volume); //获取卷设备对象的驱动g_free(devPath);break;}g_free(devPath);}g_list_foreach(allVolumes,(GFunc)g_object_unref,NULL); //遍历链表,使用g_object_unref()释放每个链表节点g_list_free(allVolumes); //释放掉链表的内存g_object_unref(monitor);return drive;
}
4)main函数(负责创建守护进程,保证API成功执行完成)
#include <stdio.h>
#include <glib.h>
#include <gio/gio.h>//函数原型声明
void func();
GDrive* getDriveFromSystem(const char* devFile);
void ejectDeviceByStopDrive(const char* devFile);int main(){GMainLoop *loop;func();loop = g_main_loop_new(NULL,FALSE);//创建主循环,NULL不需要传递进程上下文,FALSE现在不运行主循环g_main_loop_run(loop); //运行主循环return 0;
}
6、编译运行
1)由于设备的驱动名可能不同,读者可能需要修改代码内的xxx.drive字符串
2)编译命令:gcc main.c -o main `pkg-config --cflags --libs glib-2.0 gio-2.0 `
3)运行:./main
linux 移动存储设备弹出操作详解相关推荐
- linux脚本日期时间,Linux 日期和时间操作详解
Linux 日期和时间操作详解 发布时间:2012-11-27 15:10:07 作者:佚名 我要评论 Linux将时钟分为系统时钟(System Clock)和硬件(Real Time Cl ...
- 玩转Linux之dd命令操作详解
一.dd命令介绍 dd 是 Linux/UNIX 下的一个非常有用的命令,作用是用指定大小的块拷贝一个文件,并在拷贝的同时进行指定的转换. 使用权限: 所有使用者dd 这个指令在 manual ...
- Linux中的vi操作详解【转】
vi编辑器是所有Unix及Linux系统下标准的编辑器,它的强大不逊色于任何最新的文本编辑器,这里只是简单地介绍一下它的用法和一小部分指令.由于对Unix及Linux系统的任何版本,vi编辑器是完全相 ...
- linux拉取指定时间内,Linux 日期和时间操作详解
Linux将时钟分为系统时钟(System Clock)和硬件(Real Time Clock,简称RTC)时钟两种.系统时间是指当前Linux Kernel中的时钟,而硬件时钟则是主板上由电池供电的 ...
- Linux 下 SVN 命令操作详解 将文件checkout到本地目录
1.将文件checkout到本地目录 svn checkout path(path是服务器上的目录) 例如:svn checkout svn://192.168.1.1/pro/domain ...
- SVN的Windows和Linux客户端操作详解
SVN的Windows和Linux客户端操作详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Windows客户端操作 1.安装SVN客户端 a>.去官网下载svn软件 ...
- linux系统下grub.cfg详解和实例操作
linux系统下grub.cfg详解和实例操作 简介 grub是引导操作系统的程序,它会根据自己的配置文件,去引导内核,当内核被加载到内存以后,内核会根据grub配置文件中的配置,找到根分区所使用的文 ...
- 尼尔机器人技能快捷键_尼尔机械纪元武器配置及全出招操作详解-游侠网
看着游戏女主华丽的招式是不是很羡慕呢,其实只要掌握了一些出招操作,你也可以做到,那么怎么操作呢?小编这就给大家分享下尼尔机械纪元武器配置及全出招操作详解,一起看下吧. 武器配置1: 轻型刀装备于轻栏位 ...
- Linux账号和权限管理详解(超详细示例操作)!
Linux账号和权限管理详解 一.用户账号和组账号概述 1.1 Linux基于用户身份对资源访问进行控制 1.2 用户账号 1.3 组账号 二.用户账号文件 2.1 用户账号文件 /etc/passw ...
最新文章
- Squid access.log 转发到其他syslog服务器(OSSIM)
- JQuery方式执行ajax请求
- python替换所有标点符号 正则_python 把标点符号替换为空
- Labyrinth(HDU-4826)
- Web应用——焦点图自动浏览
- 程序员未来前景如何?大龄程序员出路在哪里?
- 前端实现红包雨功能_微信隐藏的7个实用功能,你都知道吗?真的白玩这么久微信...
- paip.路由器拨号上网密码找回.txt
- xp系统qq安装不上网络连接服务器,xp系统安装QQ提示“安装文件失败”如何解决...
- Java线程执行native方法时程序计数器为空,如何确保native执行完后的程序执行的位置
- AD16创建元器件库步骤
- 台式计算机常用的网卡类型,有几种常见的网卡接口类型
- BGP带宽是什么意思
- 再见postman,被这个一站式接口管理工具折服了
- 《为你打开一扇门》| 赵丽宏
- javaSE探赜索隐六(常用类API)
- ICLR2021 - Federated Learning Paper
- 初级测试小宝典 测试流程,不能复现bug,开发不认为是bug级2020测试点的热点提问的回答
- android_button onclick点击事件的5种写法
- 金山软件CEO张宏江:技术与经营,优化不同的参数而已
热门文章
- SQLMAP插件tamper编写与使用
- 谷歌pay 手续费_您可以使用Google Pay进行的所有操作
- 【KCP】UDP可靠性传输
- 解决viewpager setCurrentItem 白屏问题
- mac 下Protege中使用OWL Viz插件
- 关于c中的%x及其它格式化符
- goim 架构与定制
- 知云文献翻译打不开_学用系列|自带翻译功能的PDF文献阅读器——知云文献翻译3.0...
- When you want to give up, remember why you started.
- C 语言究竟能干什么