SBCL doesn't use O_NOCTTY

Bug #1909439 reported by Jeremy Phelps
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
SBCL
Won't Fix
Undecided
Unassigned

Bug Description

For whatever reason, probably having to do with the getty(8) and login(8) programs, the ancients decided that on Unix, if you open a serial device and you don't have a controlling terminal, this serial device becomes your controlling terminal.

SBCL inherits this behavior when it runs on Unix, because it implements CL:OPEN using the POSIX function open(2), and it doesn't pass the SB-UNIX:O_NOCTTY flag. Furthermore, there is no flag you can pass to CL:OPEN to get it to supply the flag, and it doesn't matter if you open a character or a binary stream.

I ran into the consequences of this recently when I wrote a daemon in Lisp that communicates with an Arduino board through a binary stream opened on the /dev/ttyACM0 device Linux registers for it when it is plugged in. Everything worked fine when I developed the app under SLIME. Then I bundled it up with SAVE-LISP-AND-DIE, and wrote a Systemd service file to launch it on boot.

When run from Systemd, the program didn't work, and for a long time I had no idea why.

The reason why was because the Arduino connection was being turned into a controlling terminal. Because the connection is now a terminal, Linux filters all the data through the line discipline. Certain bytes are interpreted as triggering actions, instead of being sent directly to the program on the other end. So when the Arduino sends #x8, that gets interpreted as a backspace. And #x13 pauses output. And so on.

I was forced to implement a Gray stream which behaves just like normal streams, except when I create an instance of it I open the file descriptor using the O_NOCTTY flag.

I encountered this problem using SBCL 1.4.16.debian, but the I can see that the bug is still there in GitHub. The sb-unix:o_noctty constant is nowhere to be found:

https://github.com/sbcl/sbcl/blob/master/src/code/fd-stream.lisp

Revision history for this message
Robert Brown (robert-brown) wrote :

I think you are using the wrong API to access the serial device. To communicate with a device on a serial port you may need to set the baud rate, turn off line buffering or character echoing, set parity, etc. You want a lower level API than Common Lisp streams, an API that supports ioctl operations on the file descriptor you have opened. Perhaps the file APIs in the SB-POSIX contrib package will work. The symbol SB-POSIX:O-NOCTTY is bound in my copy of SBCL.

A possible workaround that might allow you to use standard streams ... After opening the device, perhaps a TIOCNOTTY ioctl on the stream's file descriptor will cause your process to lose its controlling terminal.

Revision history for this message
Douglas Katzman (dougk) wrote :

I agree with Robert Brown. Lisp file streams are like libc's fopen(), not open(). Point being, if you write a C program that opens a terminal with fopen(), it will never pass O_NOCTTY. (The flags it passes to open are documented - https://man7.org/linux/man-pages/man3/fopen.3.html).
To operate at a lower layer, you have to do that yourself.
The right thing is (sb-posix:open "/dev/something" (logior sb-unix:o_rdwr sb-posix:o-noctty)).
If you want to live dangerously, you could call make-fd-stream on the result, but using a Gray stream is perfectly fine.

Changed in sbcl:
status: New → Won't Fix
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.