我有一个嵌入式环境,用户可以在其中插入或移除USB闪存驱动器。我想知道驱动器是否已被移除,或者当我尝试写入驱动器时是否存在其他问题。但是,Linux只是将信息保存在缓冲区中并返回,没有指示错误
我正在使用的计算机带有2.4.26内核和libc 2.3.2
我正以这种方式安装驱动器:
i = mount(MEMORY_DEV_PATH, MEMORY_MNT_PATH, "vfat", MS_SYNCHRONOUS, NULL);
这有效:
50:/root # mount
/dev/scsi/host0/bus0/target0/lun0/part1 on /mem type vfat (rw,sync)
50:/root #
稍后,我尝试将文件复制到它:
int ifile, ofile;
ifile = open("/tmp/tmpmidi.mid", O_RDONLY);
if (ifile < 0)
{
perror("open in");
break;
}
ofile = open(current_file_name.c_str(), O_WRONLY | O_SYNC);
if (ofile < 0)
{
perror("open out");
break;
}
#define BUFSZ 256
char buffer[BUFSZ];
while (1)
{
i = read(ifile, buffer, BUFSZ);
if (i < 0)
{
perror("read");
break;
}
j = write(ofile, buffer, i);
if (j < 0)
{
perror("write");
break;
}
if (i != j)
{
perror("Sizes wrong");
break;
}
if (i < BUFSZ)
{
printf("Copy is finished, I hope\n");
close(ifile);
close(ofile);
break;
}
}
如果使用写保护的USB存储器执行此代码片段,则结果为
Copy is finished, I hope
来自控制台内核的一连串错误消息
我相信如果我简单地移除USB驱动器(没有卸下它)就会发生同样的事情
我也摆脱了devfs。我想出了如何让它自动安装驱动器(使用REGISTER事件)但是当我拔出内存时它似乎永远不会触发UNREGISTER。
如何在我的程序中确定是否已成功创建文件?
7月4日更新:
对我来说,不检查close()的结果是一种愚蠢的疏忽。不幸的是,文件可以无误地关闭。所以这没有帮助。那fsync()怎么样?这听起来是个好主意,但也没有发现错误
如果我有这样的事情,/ sys中可能会有一些有趣的信息。我相信直到2.6才会增加。?。
关于我的闪存驱动器质量的评论可能是合理的。这是早先的一个。事实上,写保护开关现在似乎非常罕见
我想我必须使用overkill选项:创建一个文件,卸载&amp;重新安装驱动器,并检查文件是否存在。如果这不能解决我的问题,那么事情就搞砸了!自己注意:确保您尝试创建的文件不在那里!
顺便说一下,这恰好是一个C ++程序。您可以通过.c_str()告诉我,为了简单起见,我打算编辑它。
答案 0 :(得分:3)
如果您的应用程序想要将一个或多个文件保存到USB记忆棒中,并且让用户在小LED指示灯熄灭后立即拔出记忆棒,则需要
mount()
USB记忆棒
您不需要为此安装SYNC,这有助于使用劣质USB记忆棒
使用正确的代码保存文件
您对C低级I / O的尝试非常不正确。特别是,允许任何read()
或write()
返回短计数,1和所请求大小之间的任何正值,包括在内,而不指示任何类型的错误
fsync()
USB记忆棒上的文件
验证它是否返回成功。如果是,那么您就知道数据已经击中了USB记忆棒。
fsync()
包含USB记忆棒上文件的目录
验证它是否返回成功。如果确实如此,那么您就知道文件元数据已经点击了USB记忆棒,即使用户拉出USB记忆棒,该文件也应该可以访问。
umount()
USB记忆棒
这将阻止,直到USB记忆棒已准备好断开连接,因此在umount()
返回之前,您的应用程序看起来应保存到文件中。
如果您执行了上述fsync()
,则umount()
应该非常直接。根据文件系统的不同,内核可能需要进行一些簿记,但在任何情况下都不应该花费很长时间。
其他任何事情都不可靠。您可以通过安装具有同步访问权限的VFAT分区来做出某些假设,但这基本上只是手工操作。
如果您不想以root权限运行应用程序,则始终可以编写一个管理安装和卸载的简单特权服务。如果您怀疑在某些时候可能需要多个应用程序,我会非常热情地推荐,因为只有集中的安装程序/安装程序才能知道媒体何时准备就绪。 (如果另一个应用程序同时写入同一USB介质,它可以延迟返回“未安装”消息。顺便说一句,当你不需要同步安装USB介质时,这种方法很有效。)我个人会在/var/run/
中使用unix域数据报套接字,可能是/var/run/mounter.socket
,用于进程间通信。
最后,如果您的Linux内核已正确配置并且已安装/sys/
分区,则可以扫描所有/sys/block/sd?/
目录中的可移动媒体:
/sys/block/sd?/removable
将包含非零十进制数字符串/sys/block/sd?/size
包含以512字节为单位的设备大小,作为十进制数字字符串/sys/block/sd?/device/vendor
包含供应商名称字符串/sys/block/sd?/device/model
包含型号名称为字符串这些条目是硬件级别的,只要USB记忆棒连接并供电,就可以使用;无论是否安装都无关紧要。如果/当用户拿出USB记忆棒时,整个设备目录树将立即消失。
答案 1 :(得分:2)
如果要检测所有写入错误,则需要检查的不仅仅是write()
的返回代码 - 您还必须调用fsync()
(并检查返回值),并检查close()
报告的错误。
答案 2 :(得分:1)
简短回答:问题在于操作系统和/或USB驱动器。 Linux的 将(有时?)愉快地安装USB驱动器即使可写 写保护开关已设置。当它实际上试图写入它 然而,驱动器拒绝,这或多或少作为一个处理 驱动器故障。 (我不确定为什么会发生这种情况。我的猜测就是这样 闪存驱动器未向操作系统报告其只读权限。这个 可能取决于您正在使用的闪存驱动器的品牌和型号。)
我可以在3.2.0-26上使用(非常旧的)USB密钥获得相同的行为 内核(特别是Ubuntu 12)。我没有遇到麻烦 写保护的USB密钥读写和'cp'如果我复制一个就不会抱怨 提交给它。该文件甚至可能出现在目录中(因为 缓冲)但实际上没有任何东西写入它。我确实得到了 系统日志中有很多错误消息。
如果我是你,我会尝试实际写入闪存驱动器并确保 在假设驱动器实际可写之前它成功了。 具体来说,我:
将驱动器安装为可写。
使用唯一名称在驱动器上创建一个新文件。
卸载驱动器以清空缓冲区。
重新安装驱动器。
检查新文件是否仍在,并包含您写入的数据。
删除测试文件。
我没有充分了解硬件和驱动程序状态告诉你 如果有办法从API检测不可写的驱动器 - 可能会 是的,但我不知道。但即使有,这种情况也会发现 USB驱动器运行不正常。
<强>更新强>
我做了一些研究,结果发现如果设置了写保护开关,文件句柄上的fsync()将会失败。因此,我撤回了上述建议。相反,这是我的测试程序:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int
main(int argc, char *argv[]) {
char *path;
int f;
size_t stat;
const char *message = "Hello, world.\n";
if (argc != 2) {
printf("Need filename\n");
exit(1);
}
path = argv[1];
f = open(path, O_CREAT | O_WRONLY | O_SYNC, S_IRWXU);
if (f < 0) {
perror("open out");
exit(1);
}/* if */
stat = write(f, message, strlen(message));
if (stat < 0) {
perror("write");
exit(1);
}/* if */
stat = fsync(f);
if (stat) {
perror("fsync");
exit(1);
}
stat = close(f);
if (stat) {
perror("close");
exit(1);
}/* if */
printf("(Apparently) successfully wrote '%s'\n", path);
return 0;
}
如果设备不可写,则应该在fsync()调用时失败。
答案 3 :(得分:0)
这是POSIX的做事方式。如果write
的返回值为-1
,您肯定知道某些事情发生了可怕的错误。但是,如果write
返回0
,则某些内容也可能出错。检查errno
变量,看它是否与此处显示的预定义写入错误之一匹配:http://www.kernel.org/doc/man-pages/online/pages/man2/write.2.html
答案 4 :(得分:0)
如果找不到解决方案,可以试试这个丑陋的黑客攻击。在写入和关闭输出文件之后,您只需尝试在读取模式下打开它并检查它是否具有正确的大小。如果您确实希望确保它具有正确的内容,则可以验证它与您刚刚编写的文件具有相同的校验和。这假设操作系统将直接从USB驱动器读取文件,而不是某种缓存。