在应用程序先前由“root”运行后,QSerialPort 无法打开 tty [重复]

Posted

技术标签:

【中文标题】在应用程序先前由“root”运行后,QSerialPort 无法打开 tty [重复]【英文标题】:QSerialPort cannot open tty after application has previously been run by `root` [duplicate] 【发布时间】:2016-05-20 00:06:32 【问题描述】:

我有一个从串行端口读取和写入的应用程序(使用QSerialPort)。当我以root 用户身份运行此应用程序,然后以非root 用户身份再次运行它时,我不再能够写入串行端口,收到以下错误:

QIODevice::write (QSerialPort): device not open

非root用户在dialout组中,而/dev/tty**相关文件的权限似乎没有改变:

crw-rw---T 1 root dialout ......

最奇怪的是,当我只是使用我的 shell 以非 root 用户身份写入文件时,我确实不会收到错误:

$> echo "foo bar baz" >> /dev/ttyS0
$> echo $?
0

我发现唯一能解决问题的方法是重启机器。

这里可能发生了什么?

我在 Debian 7 上。

【问题讨论】:

【参考方案1】:

更新:这是 Qt 中的一个错误,将在 5.6.2 版中修复,该版本将于本月晚些时候发布。

在 Linux 和 Mac 上,QSerialPort 在打开串行端口时会在/var/lock/ 中创建一个锁定文件。锁定文件的权限为0644,即只有文件的创建者可以写入。

如果打开串口的进程死掉了,或者串口被其他方式不当关闭,锁文件不会被删除。 lockfile包含打开串口的进程的PID;如果进程不再运行,Qt 将尝试简单地获取锁,更改文件中的 PID。

但是,由于锁文件有0644权限,如果root运行了不正确关闭的进程,新进程将无法删除或覆盖锁文件,导致权限错误。

这是fixed for version 5.6.2

请注意,QSerialPort 自行清理:当调用其析构函数时,端口会关闭并删除锁定文件。但是,默认情况下,当SIGTERMSIGINT 导致程序退出时,Qt 调用对象析构函数。 (我个人认为这也是一个错误,但我承认这更多的是见仁见智。)

另见suggested dupe question。从这个问题可以看出,当前的行为实际上是一种改进——以前,应用程序会简单地挂起

【讨论】:

【参考方案2】:

看来,您应该先从 /var/lock 目录中删除锁定文件(请自行搜索),然后再以非 root 用户打开设备。

【讨论】:

奇怪;没错,我的tty 有一个锁定文件。这是否意味着我的程序没有正确关闭或清理串行端口?另外,为什么我的echo 命令没有失败? > 这是否意味着我的程序没有正确关闭或清理串行端口?不,这意味着这是 QLockFile 实现中的一个功能/错误(因为 QSerialPort 使用 QLockFile)。当您的应用程序以 root 启动时,它也会创建一个具有 root 权限的锁定文件。所以,当您尝试使用非 root 权限启动您的应用程序时,没有权限修改锁定文件(写在那里pid和其他信息),因此打开失败。 > 另外,为什么我的 echo 命令没有失败? Echo dows 不使用/检查锁定文件。 @KyleStrand 这没有回答你的问题吗? - 如果确实如此,请单击适当的位置:) ...我要回答,直到我意识到它似乎已经有了一个很好的答案。 +1 用户3074135 @code_fodder 如果您查看我的帐户,您会发现我了解询问/接受系统的工作原理,谢谢。我还没有接受,因为我还不明白为什么存在锁定文件,为什么它被不一致地清理等等。(另外,它确实似乎我的应用程序没有清理正确地自行启动;显然,当使用 SIGTERM 或 SIGINT 关闭应用程序时,Qt 不会自动调用析构函数。我现在已经解决了这个问题。)

以上是关于在应用程序先前由“root”运行后,QSerialPort 无法打开 tty [重复]的主要内容,如果未能解决你的问题,请参考以下文章

[求助]请问虚拟机下的kali怎么安装vmware tools总提示权限不够

动态定义依赖于先前定义的属性的属性

批处理文件中的“EXIT”不能覆盖先前命令的返回码

无法使用 Travis-CI 运行可执行文件-不确定我做错了啥

先前的存储驱动程序“devicemapper”失败:docker 中的退出状态 1

linux课程总结