Ths stty man-page describes the -f option to cause a non-blocking open of the passed file: -f Open and use the terminal named by file rather than using standard input. The file is opened using the O_NONBLOCK flag of open(), making it possible to set or display settings on a terminal that might otherwise block on the open. This does work when TTY options are fetched and displayed, but not when attempting to set some parameter. I'd expect the following command to not block, but instead to fail with a non-zero exit status: $ stty -f /dev/tty sane & But the command blocks, waiting for a "fg" command, and only then executes the requested operation on the TTY. The reason seems to be that the tcsetattr() function ignores the O_NONBLOCK flag of the passed file descriptor (or rather that the ioctl() it invokes ignores it). This appears to be a deviation from documented behavior (and breaks a script I'm working on which wants to reset the TTY on exit, but now blocks exiting from the script when it has been put into the background by the user).
What would you expect in this case to happen? TIOCSETA override the job control rules? I do not think this is wise. Or TIOCSETA returning EAGAIN for instance. The later may be reasonable, but I am not sure how much code would break. Anyway, the later option probably could be done by the attached change. Do you know what e.g. Linux does in this case?
Created attachment 236840 [details] (untested) tty: do not wait for job control when doing mod ioctl on non-blocking tty fd
Created attachment 236841 [details] (untested) tty: do not wait for job control when doing mod ioctl on non-blocking tty fd Some corrections to the patch
And error should be EWOULDBLOCK, I changed that locally.
(In reply to Konstantin Belousov from comment #3) Thank you for providing the patch. Sadly, it does only address part of the issue: $ stty -f /dev/tty sane & [1] 3355 $ fg stty -f /dev/tty sane stty: tcsetattr: Interrupted system call $ The error code is returned, but the system call is still blocking.
(In reply to Konstantin Belousov from comment #1) > What would you expect in this case to happen? TIOCSETA override the job > control rules? I do not think this is wise. Or TIOCSETA returning EAGAIN > for instance. The later may be reasonable, but I am not sure how much code > would break. Yes, I'm also afraid that making "stty sane &" return with an error code instead of waiting for the terminal to be controlled by the stty process might cause a violation of POLA. A program that runs in the background must not change the setting of a terminal in use by the foreground process. Both, blocking until the stty program has control of the terminal, or exiting with an error code seem to be possible approaches. But I can imagine that programs that want to set the terminal mode to "raw" may rather want to wait for access to the terminal when started in the background, but this would still work if the terminal is not opened with O_NONBLOCK. According to the documentation "stty sane" does not imply O_NONBLOCK, thus the blocking behavior would still be available. If there is a way that a shell script can determine whether "stty sane" would block, I could skip that call in the script running in the background. But I do not know of a reliable method to detect that case. > Anyway, the later option probably could be done by the attached change. Do you > know what e.g. Linux does in this case? Linux blocks the system call in the same way as FreeBSD: $ stty sane & [1] 8 $ fg stty sane $
(In reply to Stefan Eßer from comment #5) I found a Linux box to test, and so far the behavior seems to be identical to ours. As I said, the patch would break existing software most likely. [kostik@fc ~]$ stty -F /dev/tty sane& [1] 1309 [kostik@fc ~]$ [1]+ Stopped stty -F /dev/tty sane [kostik@fc ~]$ The hang you see is due to SIGTTOU sent before return from tty_wait_background(). This means that the patch is to make things work to your liking is even less likely to be reasonable. I attached the updated version that should work for you, but it is arguably not committable.
Created attachment 236843 [details] tty: do not wait for job control when doing mod ioctl on non-blocking tty fd
I think I have an idea that makes your case workable: root@:/ # stty -i -f /dev/tty sane & root@:/ # [1] Done stty -i -f /dev/tty sane root@:/ # Note the new '-i' option, which makes stty not block when in background, without kernel patch. In fact it would not block even if using blocking fd.
Created attachment 236847 [details] stty(1): add -i option
A similar effect could be obtained without patching any code using a command like (trap '' TTOU; stty -f /dev/tty sane) Note that with both this example and the proposed -i option, both the tcsetattr() call and any writes are affected (i.e. error messages or -a output will be written regardless of the TOSTOP setting). I agree that patching the kernel for this is a bad idea. The O_NONBLOCK flag is intended to allow non-blocking reads and writes such as for ssh(1), not to interfere with the normal functioning of job control.
A commit in branch main references this bug: URL: https://cgit.FreeBSD.org/src/commit/?id=a7eac018437e592a575f46a59151eedc7a742fa7 commit a7eac018437e592a575f46a59151eedc7a742fa7 Author: Konstantin Belousov <kib@FreeBSD.org> AuthorDate: 2022-09-26 21:34:22 +0000 Commit: Konstantin Belousov <kib@FreeBSD.org> CommitDate: 2022-10-02 17:29:53 +0000 stty(1): provide details about interaction with job control Describe a shell trick to do non-blocking modification of the terminal settings, by ignoring job control signals with trap built-in. PR: 266627 With input from: jilles Reviewed by: pauamma Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D36745 bin/stty/stty.1 | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-)
A commit in branch stable/13 references this bug: URL: https://cgit.FreeBSD.org/src/commit/?id=298d7504ae5b83cb61816b5ef7ae987a153f9f49 commit 298d7504ae5b83cb61816b5ef7ae987a153f9f49 Author: Konstantin Belousov <kib@FreeBSD.org> AuthorDate: 2022-09-26 21:34:22 +0000 Commit: Konstantin Belousov <kib@FreeBSD.org> CommitDate: 2022-10-09 02:23:04 +0000 stty(1): provide details about interaction with job control PR: 266627 (cherry picked from commit a7eac018437e592a575f46a59151eedc7a742fa7) bin/stty/stty.1 | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-)