QSerialPort 无法在应用程序之前被 `root` 运行 后打开 tty

QSerialPort cannot open tty after application has previously been run by `root`

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

QIODevice::write (QSerialPort): device not open

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

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

最奇怪的是,当我只是使用 shell 以非根用户身份写入文件时,我 没有 收到错误消息:

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

我发现唯一可以解决问题的方法是重新启动机器。

这里可能发生了什么?

我正在使用 Debian 7。

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

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

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

如果打开串口的进程挂掉了,或者串口被其他任何方式不正确地关闭了,锁文件不会被删除。锁文件包含打开串口的进程的PID;如果进程不再是 运行ning,Qt 将尝试简单地占有锁,更改文件中的 PID。

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

这是fixed for version 5.6.2

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

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