2

I have an application (using QSerialPort) that reads and writes from a serial port. When I run this application as the root user, then run it again as a non-root user, I am no longer able to write to the serial port, receiving the following error:

QIODevice::write (QSerialPort): device not open

The non-root user is in the dialout group, and the permissions on the /dev/tty** file in question appear to be unchanged:

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

Weirdest of all, I do not get an error when I simply use my shell to write to the file as the non-root user:

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

The only thing I've found that appears to fix the problem is rebooting the machine.

What could possibly be going on here?

I'm on Debian 7.

Kyle Strand
  • 15,941
  • 8
  • 72
  • 167

2 Answers2

6

Update: this is a bug in Qt, and will be fixed in version 5.6.2, which is due for release later this month.

On Linux and Mac, QSerialPort creates a lock file in /var/lock/ when opening a serial port. The lockfile has permissions 0644, i.e. only the creator of the file can write to it.

If the process that opened the serial port dies or if the serial port is somehow improperly closed by any other means, the lock file will not be deleted. The lockfile contains the PID of the process that opened the serial port; if the process is no longer running, Qt will attempt to simply take possession of the lock, changing the PID in the file.

However, since the lockfile has 0644 permissions, if the improperly-closing process was run by root, the new process will be unable to delete or overwrite the lockfile, resulting in a permissions error.

This is fixed for version 5.6.2.

Note that QSerialPort does clean up after itself: when its destructor is called, the port is closed and the lockfile is deleted. However, by default, Qt does not call object destructors when SIGTERM or SIGINT causes the program to exit. (Personally, I think this is also a bug, but I recognize that this is more a matter of opinion.)

Also see the suggested dupe question. As can be seen from this question, the current behavior is actually an improvement--previously, the application would simply hang!

Community
  • 1
  • 1
Kyle Strand
  • 15,941
  • 8
  • 72
  • 167
  • This issue seems to be back... I am running a Mac M1... and I have two serial devices from the same manufacturer... one worked 100% correctly, the other failed totally. There was a lock file inside this directory on the Mac ... /var/spool/uucp The device was called /dev/cu.usbserial-A7004VW8 and the lock file named LCK..cu.usbserial-A7004VW8 sudo rm /var/spool/uucp/LCK..cu.usbserial-A7004VW8 But this has cost me 3 days of code/sole searching ... – Tim Seed May 12 '22 at 01:22
  • @TimSeed hm...I'm glad you found this issue and it helped, even though it doesn't sound like yours was necessarily a Qt issue. – Kyle Strand May 12 '22 at 16:36
3

Seems, you should remove the lock file from the /var/lock directory (please, search himself), before opening a device with non-root user.

Denis Shienkov
  • 517
  • 3
  • 12
  • Weird; you're right, there is a lock file there for my `tty`. Does this mean that my program isn't closing or cleaning up the serial-port properly? Also, why doesn't my `echo` command fail? – Kyle Strand May 20 '16 at 16:53
  • > Does this mean that my program isn't closing or cleaning up the serial-port properly? No, this mean that is is a feature/bug in QLockFile implementation (as QSerialPort uses QLockFile). When your app was launched with the root, it creates a lock file with the root permissions too.. So, when you try start your app with the non-root permissions, then there are no rights to modify a lock file (to write there the pid and other info), so, it is failed at opening. > Also, why doesn't my echo command fail? Echo dows not uses/checks a lock file. – Denis Shienkov May 21 '16 at 07:41
  • @KyleStrand did this not answer your question? - if it did please click the appropriate location : ) ... I was going to answer until I realised it seems to have a good answer already. +1 user3074135 – code_fodder May 21 '16 at 21:44
  • @code_fodder If you look at my account you'll see that I understand how the ask/accept system works, thanks. I haven't accepted yet because I don't yet feel that I understand why the lock file exists, why it's inconsistently cleaned up, etc. (Also, it *does* appear that my app wasn't cleaning up after itself properly; apparently Qt doesn't automatically call destructors when an app is closed with SIGTERM or SIGINT. I've now resolved that issue.) – Kyle Strand May 22 '16 at 05:22